1 /*
2 * *****************************************************************************
3 *
4 * Copyright (c) 2018-2019 Gavin D. Howard and contributors.
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 *
30 * *****************************************************************************
31 *
32 * The lexer for dc.
33 *
34 */
35
36 #if DC_ENABLED
37
38 #include <ctype.h>
39
40 #include <status.h>
41 #include <lex.h>
42 #include <dc.h>
43 #include <vm.h>
44
dc_lex_negCommand(BcLex * l)45 bool dc_lex_negCommand(BcLex *l) {
46 char c = l->buf[l->i];
47 return !BC_LEX_NUM_CHAR(c, false, false);
48 }
49
dc_lex_register(BcLex * l)50 static BcStatus dc_lex_register(BcLex *l) {
51
52 if (DC_X && isspace(l->buf[l->i - 1])) {
53
54 char c;
55
56 bc_lex_whitespace(l);
57 c = l->buf[l->i];
58
59 if (!isalnum(c) && c != '_')
60 return bc_lex_verr(l, BC_ERROR_PARSE_CHAR, c);
61
62 l->i += 1;
63 bc_lex_name(l);
64 }
65 else {
66 bc_vec_npop(&l->str, l->str.len);
67 bc_vec_pushByte(&l->str, (uchar) l->buf[l->i - 1]);
68 bc_vec_pushByte(&l->str, '\0');
69 l->t = BC_LEX_NAME;
70 }
71
72 return BC_STATUS_SUCCESS;
73 }
74
dc_lex_string(BcLex * l)75 static BcStatus dc_lex_string(BcLex *l) {
76
77 size_t depth = 1, nls = 0, i = l->i;
78 char c;
79
80 l->t = BC_LEX_STR;
81 bc_vec_npop(&l->str, l->str.len);
82
83 for (; (c = l->buf[i]) && depth; ++i) {
84
85 if (c == '\\') {
86 c = l->buf[++i];
87 if (!c) break;
88 }
89 else {
90 depth += (c == '[');
91 depth -= (c == ']');
92 }
93
94 nls += (c == '\n');
95
96 if (depth) bc_vec_push(&l->str, &c);
97 }
98
99 if (BC_ERR(c == '\0' && depth)) {
100 l->i = i;
101 return bc_lex_err(l, BC_ERROR_PARSE_STRING);
102 }
103
104 bc_vec_pushByte(&l->str, '\0');
105
106 l->i = i;
107 l->line += nls;
108
109 return BC_STATUS_SUCCESS;
110 }
111
dc_lex_token(BcLex * l)112 BcStatus dc_lex_token(BcLex *l) {
113
114 BcStatus s = BC_STATUS_SUCCESS;
115 char c = l->buf[l->i++], c2;
116 size_t i;
117
118 for (i = 0; i < dc_lex_regs_len; ++i) {
119 if (l->last == dc_lex_regs[i]) return dc_lex_register(l);
120 }
121
122 if (c >= '$' && c <= '~' &&
123 (l->t = dc_lex_tokens[(c - '$')]) != BC_LEX_INVALID)
124 {
125 return s;
126 }
127
128 // This is the workhorse of the lexer.
129 switch (c) {
130
131 case '\0':
132 case '\n':
133 case '\t':
134 case '\v':
135 case '\f':
136 case '\r':
137 case ' ':
138 {
139 bc_lex_commonTokens(l, c);
140 break;
141 }
142
143 case '!':
144 {
145 c2 = l->buf[l->i];
146
147 if (c2 == '=') l->t = BC_LEX_OP_REL_NE;
148 else if (c2 == '<') l->t = BC_LEX_OP_REL_LE;
149 else if (c2 == '>') l->t = BC_LEX_OP_REL_GE;
150 else return bc_lex_invalidChar(l, c);
151
152 l->i += 1;
153 break;
154 }
155
156 case '#':
157 {
158 bc_lex_lineComment(l);
159 break;
160 }
161
162 case '.':
163 {
164 c2 = l->buf[l->i];
165 if (BC_NO_ERR(BC_LEX_NUM_CHAR(c2, true, false)))
166 s = bc_lex_number(l, c);
167 else s = bc_lex_invalidChar(l, c);
168 break;
169 }
170
171 case '0':
172 case '1':
173 case '2':
174 case '3':
175 case '4':
176 case '5':
177 case '6':
178 case '7':
179 case '8':
180 case '9':
181 case 'A':
182 case 'B':
183 case 'C':
184 case 'D':
185 case 'E':
186 case 'F':
187 {
188 s = bc_lex_number(l, c);
189 break;
190 }
191
192 case '[':
193 {
194 s = dc_lex_string(l);
195 break;
196 }
197
198 default:
199 {
200 s = bc_lex_invalidChar(l, c);
201 break;
202 }
203 }
204
205 return s;
206 }
207 #endif // DC_ENABLED
208