2 * *****************************************************************************
4 * SPDX-License-Identifier: BSD-2-Clause
6 * Copyright (c) 2018-2020 Gavin D. Howard and contributors.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
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.
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.
30 * *****************************************************************************
47 static void dc_parse_register(BcParse *p, bool var) {
50 if (p->l.t != BC_LEX_NAME) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
52 bc_parse_pushName(p, p->l.str.v, var);
55 static inline void dc_parse_string(BcParse *p) {
56 bc_parse_addString(p);
60 static void dc_parse_mem(BcParse *p, uchar inst, bool name, bool store) {
62 bc_parse_push(p, inst);
64 if (name) dc_parse_register(p, inst != BC_INST_ARRAY_ELEM);
67 bc_parse_push(p, BC_INST_SWAP);
68 bc_parse_push(p, BC_INST_ASSIGN_NO_VAL);
74 static void dc_parse_cond(BcParse *p, uchar inst) {
76 bc_parse_push(p, inst);
77 bc_parse_push(p, BC_INST_EXEC_COND);
79 dc_parse_register(p, true);
83 if (p->l.t == BC_LEX_KW_ELSE) {
84 dc_parse_register(p, true);
87 else bc_parse_pushIndex(p, SIZE_MAX);
90 static void dc_parse_token(BcParse *p, BcLexType t, uint8_t flags) {
93 bool assign, get_token = false;
97 case BC_LEX_OP_REL_EQ:
98 case BC_LEX_OP_REL_LE:
99 case BC_LEX_OP_REL_GE:
100 case BC_LEX_OP_REL_NE:
101 case BC_LEX_OP_REL_LT:
102 case BC_LEX_OP_REL_GT:
104 inst = (uchar) (t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
105 dc_parse_cond(p, inst);
112 dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
124 if (dc_lex_negCommand(&p->l)) {
125 bc_parse_push(p, BC_INST_NEG);
139 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
147 if (BC_ERR(flags & BC_PARSE_NOREAD))
148 bc_parse_err(p, BC_ERR_EXEC_REC_READ);
149 else bc_parse_push(p, BC_INST_READ);
154 case BC_LEX_OP_ASSIGN:
155 case BC_LEX_STORE_PUSH:
157 assign = t == BC_LEX_OP_ASSIGN;
158 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
159 dc_parse_mem(p, inst, true, assign);
164 case BC_LEX_LOAD_POP:
166 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
167 dc_parse_mem(p, inst, true, false);
171 case BC_LEX_STORE_IBASE:
172 case BC_LEX_STORE_OBASE:
173 case BC_LEX_STORE_SCALE:
174 #if BC_ENABLE_EXTRA_MATH
175 case BC_LEX_STORE_SEED:
176 #endif // BC_ENABLE_EXTRA_MATH
178 inst = (uchar) (t - BC_LEX_STORE_IBASE + BC_INST_IBASE);
179 dc_parse_mem(p, inst, false, true);
185 bc_parse_err(p, BC_ERR_PARSE_TOKEN);
189 if (get_token) bc_lex_next(&p->l);
192 void dc_parse_expr(BcParse *p, uint8_t flags) {
196 bool have_expr = false, need_expr = (flags & BC_PARSE_NOREAD) != 0;
198 while ((t = p->l.t) != BC_LEX_EOF) {
200 if (t == BC_LEX_NLINE) {
205 inst = dc_parse_insts[t];
207 if (inst != BC_INST_INVALID) {
208 bc_parse_push(p, inst);
211 else dc_parse_token(p, t, flags);
216 if (BC_ERR(need_expr && !have_expr))
217 bc_vm_err(BC_ERR_EXEC_READ_EXPR);
218 else if (p->l.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
219 bc_parse_push(p, BC_INST_POP_EXEC);
222 void dc_parse_parse(BcParse *p) {
228 if (BC_ERR(p->l.t == BC_LEX_EOF)) bc_parse_err(p, BC_ERR_PARSE_EOF);
229 else dc_parse_expr(p, 0);
233 if (BC_ERR(vm.status || vm.sig)) bc_parse_reset(p);