1252884aeSStefan Eßer /* 2252884aeSStefan Eßer * ***************************************************************************** 3252884aeSStefan Eßer * 43aa99676SStefan Eßer * SPDX-License-Identifier: BSD-2-Clause 5252884aeSStefan Eßer * 6*a970610aSStefan Eßer * Copyright (c) 2018-2024 Gavin D. Howard and contributors. 7252884aeSStefan Eßer * 8252884aeSStefan Eßer * Redistribution and use in source and binary forms, with or without 9252884aeSStefan Eßer * modification, are permitted provided that the following conditions are met: 10252884aeSStefan Eßer * 11252884aeSStefan Eßer * * Redistributions of source code must retain the above copyright notice, this 12252884aeSStefan Eßer * list of conditions and the following disclaimer. 13252884aeSStefan Eßer * 14252884aeSStefan Eßer * * Redistributions in binary form must reproduce the above copyright notice, 15252884aeSStefan Eßer * this list of conditions and the following disclaimer in the documentation 16252884aeSStefan Eßer * and/or other materials provided with the distribution. 17252884aeSStefan Eßer * 18252884aeSStefan Eßer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19252884aeSStefan Eßer * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20252884aeSStefan Eßer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21252884aeSStefan Eßer * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22252884aeSStefan Eßer * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23252884aeSStefan Eßer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24252884aeSStefan Eßer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25252884aeSStefan Eßer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26252884aeSStefan Eßer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27252884aeSStefan Eßer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28252884aeSStefan Eßer * POSSIBILITY OF SUCH DAMAGE. 29252884aeSStefan Eßer * 30252884aeSStefan Eßer * ***************************************************************************** 31252884aeSStefan Eßer * 32252884aeSStefan Eßer * Code common to the parsers. 33252884aeSStefan Eßer * 34252884aeSStefan Eßer */ 35252884aeSStefan Eßer 36252884aeSStefan Eßer #include <assert.h> 37252884aeSStefan Eßer #include <stddef.h> 38252884aeSStefan Eßer #include <stdlib.h> 39252884aeSStefan Eßer #include <string.h> 40252884aeSStefan Eßer 41252884aeSStefan Eßer #include <limits.h> 42252884aeSStefan Eßer 43252884aeSStefan Eßer #include <parse.h> 44252884aeSStefan Eßer #include <program.h> 45252884aeSStefan Eßer #include <vm.h> 46252884aeSStefan Eßer 4778bc019dSStefan Eßer void 4878bc019dSStefan Eßer bc_parse_updateFunc(BcParse* p, size_t fidx) 4978bc019dSStefan Eßer { 50252884aeSStefan Eßer p->fidx = fidx; 51252884aeSStefan Eßer p->func = bc_vec_item(&p->prog->fns, fidx); 52252884aeSStefan Eßer } 53252884aeSStefan Eßer 5478bc019dSStefan Eßer inline void 5578bc019dSStefan Eßer bc_parse_pushName(const BcParse* p, char* name, bool var) 5678bc019dSStefan Eßer { 57252884aeSStefan Eßer bc_parse_pushIndex(p, bc_program_search(p->prog, name, var)); 58252884aeSStefan Eßer } 59252884aeSStefan Eßer 6044d4804dSStefan Eßer /** 6144d4804dSStefan Eßer * Updates the function, then pushes the instruction and the index. This is a 6244d4804dSStefan Eßer * convenience function. 6344d4804dSStefan Eßer * @param p The parser. 6444d4804dSStefan Eßer * @param inst The instruction to push. 6544d4804dSStefan Eßer * @param idx The index to push. 6644d4804dSStefan Eßer */ 67d101cdd6SStefan Eßer static inline void 68d101cdd6SStefan Eßer bc_parse_pushInstIdx(BcParse* p, uchar inst, size_t idx) 6978bc019dSStefan Eßer { 70252884aeSStefan Eßer bc_parse_push(p, inst); 71252884aeSStefan Eßer bc_parse_pushIndex(p, idx); 72252884aeSStefan Eßer } 73252884aeSStefan Eßer 7478bc019dSStefan Eßer void 7578bc019dSStefan Eßer bc_parse_addString(BcParse* p) 7678bc019dSStefan Eßer { 77252884aeSStefan Eßer size_t idx; 78252884aeSStefan Eßer 79d101cdd6SStefan Eßer idx = bc_program_addString(p->prog, p->l.str.v); 80252884aeSStefan Eßer 8144d4804dSStefan Eßer // Push the string info. 82d101cdd6SStefan Eßer bc_parse_pushInstIdx(p, BC_INST_STR, idx); 83252884aeSStefan Eßer } 84252884aeSStefan Eßer 8578bc019dSStefan Eßer static void 8678bc019dSStefan Eßer bc_parse_addNum(BcParse* p, const char* string) 8778bc019dSStefan Eßer { 88d101cdd6SStefan Eßer BcProgram* prog = p->prog; 89252884aeSStefan Eßer size_t idx; 90d101cdd6SStefan Eßer 91d101cdd6SStefan Eßer // XXX: This function has an implicit assumption: that string is a valid C 92d101cdd6SStefan Eßer // string with a nul terminator. This is because of the unchecked array 93d101cdd6SStefan Eßer // accesses below. I can't check this with an assert() because that could 94d101cdd6SStefan Eßer // lead to out-of-bounds access. 95d101cdd6SStefan Eßer // 96d101cdd6SStefan Eßer // XXX: In fact, just for safety's sake, assume that this function needs a 97d101cdd6SStefan Eßer // non-empty string with a nul terminator, just in case bc_parse_zero or 98d101cdd6SStefan Eßer // bc_parse_one change in the future, which I doubt. 99252884aeSStefan Eßer 10010041e99SStefan Eßer BC_SIG_ASSERT_LOCKED; 10110041e99SStefan Eßer 10244d4804dSStefan Eßer // Special case 0. 10378bc019dSStefan Eßer if (bc_parse_zero[0] == string[0] && bc_parse_zero[1] == string[1]) 10478bc019dSStefan Eßer { 1053aa99676SStefan Eßer bc_parse_push(p, BC_INST_ZERO); 1063aa99676SStefan Eßer return; 1073aa99676SStefan Eßer } 10844d4804dSStefan Eßer 10944d4804dSStefan Eßer // Special case 1. 11078bc019dSStefan Eßer if (bc_parse_one[0] == string[0] && bc_parse_one[1] == string[1]) 11178bc019dSStefan Eßer { 112252884aeSStefan Eßer bc_parse_push(p, BC_INST_ONE); 113252884aeSStefan Eßer return; 114252884aeSStefan Eßer } 115252884aeSStefan Eßer 116d101cdd6SStefan Eßer if (bc_map_insert(&prog->const_map, string, prog->consts.len, &idx)) 117d101cdd6SStefan Eßer { 118d101cdd6SStefan Eßer BcConst* c; 119d101cdd6SStefan Eßer BcId* id = bc_vec_item(&prog->const_map, idx); 120252884aeSStefan Eßer 121d101cdd6SStefan Eßer // Get the index. 122d101cdd6SStefan Eßer idx = id->idx; 123252884aeSStefan Eßer 12444d4804dSStefan Eßer // Push an empty constant. 125d101cdd6SStefan Eßer c = bc_vec_pushEmpty(&prog->consts); 12644d4804dSStefan Eßer 127d101cdd6SStefan Eßer // Set the fields. We reuse the string in the ID (allocated by 128d101cdd6SStefan Eßer // bc_map_insert()), because why not? 129d101cdd6SStefan Eßer c->val = id->name; 13044d4804dSStefan Eßer c->base = BC_NUM_BIGDIG_MAX; 13144d4804dSStefan Eßer 132d101cdd6SStefan Eßer // We need this to be able to tell that the number has not been 133d101cdd6SStefan Eßer // allocated. 13444d4804dSStefan Eßer bc_num_clear(&c->num); 135d101cdd6SStefan Eßer } 136d101cdd6SStefan Eßer else 137d101cdd6SStefan Eßer { 138d101cdd6SStefan Eßer BcId* id = bc_vec_item(&prog->const_map, idx); 139d101cdd6SStefan Eßer idx = id->idx; 140d101cdd6SStefan Eßer } 141252884aeSStefan Eßer 142d101cdd6SStefan Eßer bc_parse_pushInstIdx(p, BC_INST_NUM, idx); 143252884aeSStefan Eßer } 144252884aeSStefan Eßer 14578bc019dSStefan Eßer void 14678bc019dSStefan Eßer bc_parse_number(BcParse* p) 14778bc019dSStefan Eßer { 148252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 149252884aeSStefan Eßer char* exp = strchr(p->l.str.v, 'e'); 150252884aeSStefan Eßer size_t idx = SIZE_MAX; 151252884aeSStefan Eßer 15244d4804dSStefan Eßer // Do we have a number in scientific notation? If so, add a nul byte where 15344d4804dSStefan Eßer // the e is. 15478bc019dSStefan Eßer if (exp != NULL) 15578bc019dSStefan Eßer { 156252884aeSStefan Eßer idx = ((size_t) (exp - p->l.str.v)); 157252884aeSStefan Eßer *exp = 0; 158252884aeSStefan Eßer } 159252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 160252884aeSStefan Eßer 161252884aeSStefan Eßer bc_parse_addNum(p, p->l.str.v); 162252884aeSStefan Eßer 163252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 16444d4804dSStefan Eßer // If we have a number in scientific notation... 16578bc019dSStefan Eßer if (exp != NULL) 16678bc019dSStefan Eßer { 167252884aeSStefan Eßer bool neg; 168252884aeSStefan Eßer 16944d4804dSStefan Eßer // Figure out if the exponent is negative. 170252884aeSStefan Eßer neg = (*((char*) bc_vec_item(&p->l.str, idx + 1)) == BC_LEX_NEG_CHAR); 171252884aeSStefan Eßer 17244d4804dSStefan Eßer // Add the number and instruction. 173252884aeSStefan Eßer bc_parse_addNum(p, bc_vec_item(&p->l.str, idx + 1 + neg)); 174252884aeSStefan Eßer bc_parse_push(p, BC_INST_LSHIFT + neg); 175252884aeSStefan Eßer } 176252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 177252884aeSStefan Eßer } 178252884aeSStefan Eßer 17978bc019dSStefan Eßer void 180d101cdd6SStefan Eßer bc_parse_text(BcParse* p, const char* text, BcMode mode) 18178bc019dSStefan Eßer { 18210041e99SStefan Eßer BC_SIG_LOCK; 18310041e99SStefan Eßer 184252884aeSStefan Eßer // Make sure the pointer isn't invalidated. 185252884aeSStefan Eßer p->func = bc_vec_item(&p->prog->fns, p->fidx); 186d101cdd6SStefan Eßer bc_lex_text(&p->l, text, mode); 18710041e99SStefan Eßer 18810041e99SStefan Eßer BC_SIG_UNLOCK; 189252884aeSStefan Eßer } 190252884aeSStefan Eßer 19178bc019dSStefan Eßer void 19278bc019dSStefan Eßer bc_parse_reset(BcParse* p) 19378bc019dSStefan Eßer { 194252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 195252884aeSStefan Eßer 19644d4804dSStefan Eßer // Reset the function if it isn't main and switch to main. 19778bc019dSStefan Eßer if (p->fidx != BC_PROG_MAIN) 19878bc019dSStefan Eßer { 199252884aeSStefan Eßer bc_func_reset(p->func); 200252884aeSStefan Eßer bc_parse_updateFunc(p, BC_PROG_MAIN); 201252884aeSStefan Eßer } 202252884aeSStefan Eßer 20344d4804dSStefan Eßer // Reset the lexer. 204252884aeSStefan Eßer p->l.i = p->l.len; 205252884aeSStefan Eßer p->l.t = BC_LEX_EOF; 206252884aeSStefan Eßer 207252884aeSStefan Eßer #if BC_ENABLED 20878bc019dSStefan Eßer if (BC_IS_BC) 20978bc019dSStefan Eßer { 21044d4804dSStefan Eßer // Get rid of the bc parser state. 21144d4804dSStefan Eßer p->auto_part = false; 212252884aeSStefan Eßer bc_vec_npop(&p->flags, p->flags.len - 1); 21310328f8bSStefan Eßer bc_vec_popAll(&p->exits); 21410328f8bSStefan Eßer bc_vec_popAll(&p->conds); 21510328f8bSStefan Eßer bc_vec_popAll(&p->ops); 216252884aeSStefan Eßer } 217252884aeSStefan Eßer #endif // BC_ENABLED 218252884aeSStefan Eßer 21944d4804dSStefan Eßer // Reset the program. This might clear the error. 220252884aeSStefan Eßer bc_program_reset(p->prog); 221252884aeSStefan Eßer 22244d4804dSStefan Eßer // Jump if there is an error. 223d101cdd6SStefan Eßer if (BC_ERR(vm->status)) BC_JMP; 224252884aeSStefan Eßer } 225252884aeSStefan Eßer 226103d7cdfSStefan Eßer #if BC_DEBUG 22778bc019dSStefan Eßer void 22878bc019dSStefan Eßer bc_parse_free(BcParse* p) 22978bc019dSStefan Eßer { 230252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 231252884aeSStefan Eßer 232252884aeSStefan Eßer assert(p != NULL); 233252884aeSStefan Eßer 234252884aeSStefan Eßer #if BC_ENABLED 23578bc019dSStefan Eßer if (BC_IS_BC) 23678bc019dSStefan Eßer { 237252884aeSStefan Eßer bc_vec_free(&p->flags); 238252884aeSStefan Eßer bc_vec_free(&p->exits); 239252884aeSStefan Eßer bc_vec_free(&p->conds); 240252884aeSStefan Eßer bc_vec_free(&p->ops); 241252884aeSStefan Eßer bc_vec_free(&p->buf); 242252884aeSStefan Eßer } 243252884aeSStefan Eßer #endif // BC_ENABLED 244252884aeSStefan Eßer 245252884aeSStefan Eßer bc_lex_free(&p->l); 246252884aeSStefan Eßer } 247103d7cdfSStefan Eßer #endif // BC_DEBUG 248252884aeSStefan Eßer 24978bc019dSStefan Eßer void 25078bc019dSStefan Eßer bc_parse_init(BcParse* p, BcProgram* prog, size_t func) 25178bc019dSStefan Eßer { 252252884aeSStefan Eßer #if BC_ENABLED 253252884aeSStefan Eßer uint16_t flag = 0; 254252884aeSStefan Eßer #endif // BC_ENABLED 255252884aeSStefan Eßer 256252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 257252884aeSStefan Eßer 258252884aeSStefan Eßer assert(p != NULL && prog != NULL); 259252884aeSStefan Eßer 260252884aeSStefan Eßer #if BC_ENABLED 26178bc019dSStefan Eßer if (BC_IS_BC) 26278bc019dSStefan Eßer { 26344d4804dSStefan Eßer // We always want at least one flag set on the flags stack. 26444d4804dSStefan Eßer bc_vec_init(&p->flags, sizeof(uint16_t), BC_DTOR_NONE); 265252884aeSStefan Eßer bc_vec_push(&p->flags, &flag); 26644d4804dSStefan Eßer 26744d4804dSStefan Eßer bc_vec_init(&p->exits, sizeof(BcInstPtr), BC_DTOR_NONE); 26844d4804dSStefan Eßer bc_vec_init(&p->conds, sizeof(size_t), BC_DTOR_NONE); 26944d4804dSStefan Eßer bc_vec_init(&p->ops, sizeof(BcLexType), BC_DTOR_NONE); 27044d4804dSStefan Eßer bc_vec_init(&p->buf, sizeof(char), BC_DTOR_NONE); 27144d4804dSStefan Eßer 27244d4804dSStefan Eßer p->auto_part = false; 273252884aeSStefan Eßer } 274252884aeSStefan Eßer #endif // BC_ENABLED 275252884aeSStefan Eßer 276252884aeSStefan Eßer bc_lex_init(&p->l); 277252884aeSStefan Eßer 27844d4804dSStefan Eßer // Set up the function. 279252884aeSStefan Eßer p->prog = prog; 280252884aeSStefan Eßer bc_parse_updateFunc(p, func); 281252884aeSStefan Eßer } 282