1 /* 2 * ***************************************************************************** 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2018-2021 Gavin D. Howard and contributors. 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 #include <setjmp.h> 42 43 #include <dc.h> 44 #include <program.h> 45 #include <vm.h> 46 47 static void dc_parse_register(BcParse *p, bool var) { 48 49 bc_lex_next(&p->l); 50 if (p->l.t != BC_LEX_NAME) bc_parse_err(p, BC_ERR_PARSE_TOKEN); 51 52 bc_parse_pushName(p, p->l.str.v, var); 53 } 54 55 static inline void dc_parse_string(BcParse *p) { 56 bc_parse_addString(p); 57 bc_lex_next(&p->l); 58 } 59 60 static void dc_parse_mem(BcParse *p, uchar inst, bool name, bool store) { 61 62 bc_parse_push(p, inst); 63 64 if (name) dc_parse_register(p, inst != BC_INST_ARRAY_ELEM); 65 66 if (store) { 67 bc_parse_push(p, BC_INST_SWAP); 68 bc_parse_push(p, BC_INST_ASSIGN_NO_VAL); 69 } 70 71 bc_lex_next(&p->l); 72 } 73 74 static void dc_parse_cond(BcParse *p, uchar inst) { 75 76 bc_parse_push(p, inst); 77 bc_parse_push(p, BC_INST_EXEC_COND); 78 79 dc_parse_register(p, true); 80 81 bc_lex_next(&p->l); 82 83 if (p->l.t == BC_LEX_KW_ELSE) { 84 dc_parse_register(p, true); 85 bc_lex_next(&p->l); 86 } 87 else bc_parse_pushIndex(p, SIZE_MAX); 88 } 89 90 static void dc_parse_token(BcParse *p, BcLexType t, uint8_t flags) { 91 92 uchar inst; 93 bool assign, get_token = false; 94 95 switch (t) { 96 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: 103 { 104 inst = (uchar) (t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ); 105 dc_parse_cond(p, inst); 106 break; 107 } 108 109 case BC_LEX_SCOLON: 110 case BC_LEX_COLON: 111 { 112 dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON); 113 break; 114 } 115 116 case BC_LEX_STR: 117 { 118 dc_parse_string(p); 119 break; 120 } 121 122 case BC_LEX_NEG: 123 { 124 if (dc_lex_negCommand(&p->l)) { 125 bc_parse_push(p, BC_INST_NEG); 126 get_token = true; 127 break; 128 } 129 130 bc_lex_next(&p->l); 131 } 132 // Fallthrough. 133 BC_FALLTHROUGH 134 135 case BC_LEX_NUMBER: 136 { 137 bc_parse_number(p); 138 139 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG); 140 get_token = true; 141 142 break; 143 } 144 145 case BC_LEX_KW_READ: 146 { 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); 150 get_token = true; 151 break; 152 } 153 154 case BC_LEX_OP_ASSIGN: 155 case BC_LEX_STORE_PUSH: 156 { 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); 160 break; 161 } 162 163 case BC_LEX_LOAD: 164 case BC_LEX_LOAD_POP: 165 { 166 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD; 167 dc_parse_mem(p, inst, true, false); 168 break; 169 } 170 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 177 { 178 inst = (uchar) (t - BC_LEX_STORE_IBASE + BC_INST_IBASE); 179 dc_parse_mem(p, inst, false, true); 180 break; 181 } 182 183 default: 184 { 185 bc_parse_err(p, BC_ERR_PARSE_TOKEN); 186 } 187 } 188 189 if (get_token) bc_lex_next(&p->l); 190 } 191 192 void dc_parse_expr(BcParse *p, uint8_t flags) { 193 194 BcInst inst; 195 BcLexType t; 196 bool have_expr = false, need_expr = (flags & BC_PARSE_NOREAD) != 0; 197 198 while ((t = p->l.t) != BC_LEX_EOF) { 199 200 if (t == BC_LEX_NLINE) { 201 bc_lex_next(&p->l); 202 continue; 203 } 204 205 inst = dc_parse_insts[t]; 206 207 if (inst != BC_INST_INVALID) { 208 bc_parse_push(p, inst); 209 bc_lex_next(&p->l); 210 } 211 else dc_parse_token(p, t, flags); 212 213 have_expr = true; 214 } 215 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); 220 } 221 222 void dc_parse_parse(BcParse *p) { 223 224 assert(p != NULL); 225 226 BC_SETJMP(exit); 227 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); 230 231 exit: 232 BC_SIG_MAYLOCK; 233 if (BC_ERR(vm.status || vm.sig)) bc_parse_reset(p); 234 BC_LONGJMP_CONT; 235 } 236 #endif // DC_ENABLED 237