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 parser for dc.
33 *
34 */
35
36 #if DC_ENABLED
37
38 #include <assert.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 #include <status.h>
43 #include <parse.h>
44 #include <dc.h>
45 #include <program.h>
46 #include <vm.h>
47
dc_parse_register(BcParse * p,bool var)48 static BcStatus dc_parse_register(BcParse *p, bool var) {
49
50 BcStatus s;
51
52 s = bc_lex_next(&p->l);
53 if (BC_ERR(s)) return s;
54 if (p->l.t != BC_LEX_NAME) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
55
56 bc_parse_pushName(p, p->l.str.v, var);
57
58 return s;
59 }
60
dc_parse_string(BcParse * p)61 static BcStatus dc_parse_string(BcParse *p) {
62
63 BcFunc f;
64
65 bc_program_addFunc(p->prog, &f, bc_func_main);
66 bc_parse_string(p);
67
68 return bc_lex_next(&p->l);
69 }
70
dc_parse_mem(BcParse * p,uchar inst,bool name,bool store)71 static BcStatus dc_parse_mem(BcParse *p, uchar inst, bool name, bool store) {
72
73 BcStatus s;
74
75 bc_parse_push(p, inst);
76
77 if (name) {
78 s = dc_parse_register(p, inst != BC_INST_ARRAY_ELEM);
79 if (BC_ERR(s)) return s;
80 }
81
82 if (store) {
83 bc_parse_push(p, BC_INST_SWAP);
84 bc_parse_push(p, BC_INST_ASSIGN_NO_VAL);
85 }
86
87 return bc_lex_next(&p->l);
88 }
89
dc_parse_cond(BcParse * p,uchar inst)90 static BcStatus dc_parse_cond(BcParse *p, uchar inst) {
91
92 BcStatus s;
93
94 bc_parse_push(p, inst);
95 bc_parse_push(p, BC_INST_EXEC_COND);
96
97 s = dc_parse_register(p, true);
98 if (BC_ERR(s)) return s;
99
100 s = bc_lex_next(&p->l);
101 if (BC_ERR(s)) return s;
102
103 if (p->l.t == BC_LEX_KW_ELSE) {
104 s = dc_parse_register(p, true);
105 if (BC_ERR(s)) return s;
106 s = bc_lex_next(&p->l);
107 }
108 else bc_parse_pushIndex(p, SIZE_MAX);
109
110 return s;
111 }
112
dc_parse_token(BcParse * p,BcLexType t,uint8_t flags)113 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags) {
114
115 BcStatus s = BC_STATUS_SUCCESS;
116 uchar inst;
117 bool assign, get_token = false;
118
119 switch (t) {
120
121 case BC_LEX_OP_REL_EQ:
122 case BC_LEX_OP_REL_LE:
123 case BC_LEX_OP_REL_GE:
124 case BC_LEX_OP_REL_NE:
125 case BC_LEX_OP_REL_LT:
126 case BC_LEX_OP_REL_GT:
127 {
128 inst = (uchar) (t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
129 s = dc_parse_cond(p, inst);
130 break;
131 }
132
133 case BC_LEX_SCOLON:
134 case BC_LEX_COLON:
135 {
136 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
137 break;
138 }
139
140 case BC_LEX_STR:
141 {
142 s = dc_parse_string(p);
143 break;
144 }
145
146 case BC_LEX_NEG:
147 {
148 if (dc_lex_negCommand(&p->l)) {
149 bc_parse_push(p, BC_INST_NEG);
150 get_token = true;
151 break;
152 }
153
154 s = bc_lex_next(&p->l);
155 if (BC_ERR(s)) return s;
156 }
157 // Fallthrough.
158 case BC_LEX_NUMBER:
159 {
160 bc_parse_number(p);
161
162 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
163 get_token = true;
164
165 break;
166 }
167
168 case BC_LEX_KW_READ:
169 {
170 if (BC_ERR(flags & BC_PARSE_NOREAD))
171 s = bc_parse_err(p, BC_ERROR_EXEC_REC_READ);
172 else bc_parse_push(p, BC_INST_READ);
173 get_token = true;
174 break;
175 }
176
177 case BC_LEX_OP_ASSIGN:
178 case BC_LEX_STORE_PUSH:
179 {
180 assign = t == BC_LEX_OP_ASSIGN;
181 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
182 s = dc_parse_mem(p, inst, true, assign);
183 break;
184 }
185
186 case BC_LEX_LOAD:
187 case BC_LEX_LOAD_POP:
188 {
189 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
190 s = dc_parse_mem(p, inst, true, false);
191 break;
192 }
193
194 case BC_LEX_STORE_IBASE:
195 case BC_LEX_STORE_OBASE:
196 case BC_LEX_STORE_SCALE:
197 {
198 inst = (uchar) (t - BC_LEX_STORE_IBASE + BC_INST_IBASE);
199 s = dc_parse_mem(p, inst, false, true);
200 break;
201 }
202
203 default:
204 {
205 s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
206 get_token = true;
207 break;
208 }
209 }
210
211 if (BC_NO_ERR(!s) && get_token) s = bc_lex_next(&p->l);
212
213 return s;
214 }
215
dc_parse_expr(BcParse * p,uint8_t flags)216 BcStatus dc_parse_expr(BcParse *p, uint8_t flags) {
217
218 BcStatus s = BC_STATUS_SUCCESS;
219 BcInst inst;
220 BcLexType t;
221 bool have_expr = false, need_expr = (flags & BC_PARSE_NOREAD) != 0;
222
223 while (BC_NO_SIG && BC_NO_ERR(!s) && (t = p->l.t) != BC_LEX_EOF) {
224
225 if (t == BC_LEX_NLINE) {
226 s = bc_lex_next(&p->l);
227 continue;
228 }
229
230 inst = dc_parse_insts[t];
231
232 if (inst != BC_INST_INVALID) {
233 bc_parse_push(p, inst);
234 s = bc_lex_next(&p->l);
235 }
236 else s = dc_parse_token(p, t, flags);
237
238 have_expr = true;
239 }
240
241 if (BC_NO_ERR(!s)) {
242 if (BC_SIG) s = BC_STATUS_SIGNAL;
243 else if (BC_ERR(need_expr && !have_expr))
244 s = bc_vm_err(BC_ERROR_EXEC_READ_EXPR);
245 else if (p->l.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
246 bc_parse_push(p, BC_INST_POP_EXEC);
247 }
248
249 return s;
250 }
251
dc_parse_parse(BcParse * p)252 BcStatus dc_parse_parse(BcParse *p) {
253
254 BcStatus s;
255
256 assert(p != NULL);
257
258 if (BC_ERR(p->l.t == BC_LEX_EOF)) s = bc_parse_err(p, BC_ERROR_PARSE_EOF);
259 else s = dc_parse_expr(p, 0);
260
261 if (BC_ERR(s) || BC_SIG) s = bc_parse_reset(p, s);
262
263 return s;
264 }
265 #endif // DC_ENABLED
266