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 * Definitions for bc's parser. 33252884aeSStefan Eßer * 34252884aeSStefan Eßer */ 35252884aeSStefan Eßer 36252884aeSStefan Eßer #ifndef BC_PARSE_H 37252884aeSStefan Eßer #define BC_PARSE_H 38252884aeSStefan Eßer 39252884aeSStefan Eßer #include <limits.h> 40252884aeSStefan Eßer #include <stdbool.h> 41252884aeSStefan Eßer #include <stdint.h> 42252884aeSStefan Eßer 43252884aeSStefan Eßer #include <status.h> 44252884aeSStefan Eßer #include <vector.h> 45252884aeSStefan Eßer #include <lex.h> 46252884aeSStefan Eßer #include <lang.h> 47252884aeSStefan Eßer 4844d4804dSStefan Eßer // The following are flags that can be passed to @a BcParseExpr functions. They 4944d4804dSStefan Eßer // define the requirements that the parsed expression must meet to not have an 5044d4804dSStefan Eßer // error thrown. 5144d4804dSStefan Eßer 5244d4804dSStefan Eßer /// A flag that requires that the expression is valid for conditionals in for 5344d4804dSStefan Eßer /// loops, while loops, and if statements. This is because POSIX requires that 5444d4804dSStefan Eßer /// certain operators are *only* used in those cases. It's whacked, but that's 5544d4804dSStefan Eßer /// how it is. 56252884aeSStefan Eßer #define BC_PARSE_REL (UINTMAX_C(1) << 0) 5744d4804dSStefan Eßer 5844d4804dSStefan Eßer /// A flag that requires that the expression is valid for a print statement. 59252884aeSStefan Eßer #define BC_PARSE_PRINT (UINTMAX_C(1) << 1) 6044d4804dSStefan Eßer 6144d4804dSStefan Eßer /// A flag that requires that the expression does *not* have any function call. 62252884aeSStefan Eßer #define BC_PARSE_NOCALL (UINTMAX_C(1) << 2) 6344d4804dSStefan Eßer 6478bc019dSStefan Eßer /// A flag that requires that the expression does *not* have a read() 6578bc019dSStefan Eßer /// expression. 66252884aeSStefan Eßer #define BC_PARSE_NOREAD (UINTMAX_C(1) << 3) 6744d4804dSStefan Eßer 6844d4804dSStefan Eßer /// A flag that *allows* (rather than requires) that an array appear in the 6944d4804dSStefan Eßer /// expression. This is mostly used as parameters in bc. 70252884aeSStefan Eßer #define BC_PARSE_ARRAY (UINTMAX_C(1) << 4) 7144d4804dSStefan Eßer 7244d4804dSStefan Eßer /// A flag that requires that the expression is not empty and returns a value. 73252884aeSStefan Eßer #define BC_PARSE_NEEDVAL (UINTMAX_C(1) << 5) 74252884aeSStefan Eßer 7544d4804dSStefan Eßer /** 7644d4804dSStefan Eßer * Returns true if the parser has been initialized. 7744d4804dSStefan Eßer * @param p The parser. 7844d4804dSStefan Eßer * @param prg The program. 7944d4804dSStefan Eßer * @return True if @a p has been initialized, false otherwise. 8044d4804dSStefan Eßer */ 8144d4804dSStefan Eßer #define BC_PARSE_IS_INITED(p, prg) ((p)->prog == (prg)) 8244d4804dSStefan Eßer 8344d4804dSStefan Eßer /** 8444d4804dSStefan Eßer * Returns true if the current parser state allows parsing, false otherwise. 8544d4804dSStefan Eßer * @param p The parser. 8644d4804dSStefan Eßer * @return True if parsing can proceed, false otherwise. 8744d4804dSStefan Eßer */ 88252884aeSStefan Eßer #define BC_PARSE_CAN_PARSE(p) ((p).l.t != BC_LEX_EOF) 8944d4804dSStefan Eßer 9044d4804dSStefan Eßer /** 9144d4804dSStefan Eßer * Pushes the instruction @a i onto the bytecode vector for the current 9244d4804dSStefan Eßer * function. 9344d4804dSStefan Eßer * @param p The parser. 9444d4804dSStefan Eßer * @param i The instruction to push onto the bytecode vector. 9544d4804dSStefan Eßer */ 96252884aeSStefan Eßer #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (uchar) (i))) 9744d4804dSStefan Eßer 9844d4804dSStefan Eßer /** 9944d4804dSStefan Eßer * Pushes an index onto the bytecode vector. For more information, see 10044d4804dSStefan Eßer * @a bc_vec_pushIndex() in src/vector.c and @a bc_program_index() in 10144d4804dSStefan Eßer * src/program.c. 10244d4804dSStefan Eßer * @param p The parser. 10344d4804dSStefan Eßer * @param idx The index to push onto the bytecode vector. 10444d4804dSStefan Eßer */ 105252884aeSStefan Eßer #define bc_parse_pushIndex(p, idx) (bc_vec_pushIndex(&(p)->func->code, (idx))) 106252884aeSStefan Eßer 10744d4804dSStefan Eßer /** 108d101cdd6SStefan Eßer * A convenience macro for throwing errors in parse code. This takes care of 10944d4804dSStefan Eßer * plumbing like passing in the current line the lexer is on. 11044d4804dSStefan Eßer * @param p The parser. 11144d4804dSStefan Eßer * @param e The error. 11244d4804dSStefan Eßer */ 113103d7cdfSStefan Eßer #if BC_DEBUG 114d101cdd6SStefan Eßer #define bc_parse_err(p, e) \ 115d101cdd6SStefan Eßer (bc_vm_handleError((e), __FILE__, __LINE__, (p)->l.line)) 116103d7cdfSStefan Eßer #else // BC_DEBUG 11750696a6eSStefan Eßer #define bc_parse_err(p, e) (bc_vm_handleError((e), (p)->l.line)) 118103d7cdfSStefan Eßer #endif // BC_DEBUG 11944d4804dSStefan Eßer 12044d4804dSStefan Eßer /** 121d101cdd6SStefan Eßer * A convenience macro for throwing errors in parse code. This takes care of 12244d4804dSStefan Eßer * plumbing like passing in the current line the lexer is on. 12344d4804dSStefan Eßer * @param p The parser. 12444d4804dSStefan Eßer * @param e The error. 12544d4804dSStefan Eßer * @param ... The varags that are needed. 12644d4804dSStefan Eßer */ 127103d7cdfSStefan Eßer #if BC_DEBUG 128d101cdd6SStefan Eßer #define bc_parse_verr(p, e, ...) \ 129d101cdd6SStefan Eßer (bc_vm_handleError((e), __FILE__, __LINE__, (p)->l.line, __VA_ARGS__)) 130103d7cdfSStefan Eßer #else // BC_DEBUG 13150696a6eSStefan Eßer #define bc_parse_verr(p, e, ...) \ 13250696a6eSStefan Eßer (bc_vm_handleError((e), (p)->l.line, __VA_ARGS__)) 133103d7cdfSStefan Eßer #endif // BC_DEBUG 134252884aeSStefan Eßer 13544d4804dSStefan Eßer // Forward declarations. 136252884aeSStefan Eßer struct BcParse; 137252884aeSStefan Eßer struct BcProgram; 138252884aeSStefan Eßer 13944d4804dSStefan Eßer /** 14044d4804dSStefan Eßer * A function pointer to call when more parsing is needed. 14144d4804dSStefan Eßer * @param p The parser. 14244d4804dSStefan Eßer */ 14344d4804dSStefan Eßer typedef void (*BcParseParse)(struct BcParse* p); 144252884aeSStefan Eßer 14544d4804dSStefan Eßer /** 14644d4804dSStefan Eßer * A function pointer to call when an expression needs to be parsed. This can 14744d4804dSStefan Eßer * happen for read() expressions or dc strings. 14844d4804dSStefan Eßer * @param p The parser. 14944d4804dSStefan Eßer * @param flags The flags for what is allowed or required. (See flags above.) 15044d4804dSStefan Eßer */ 15144d4804dSStefan Eßer typedef void (*BcParseExpr)(struct BcParse* p, uint8_t flags); 15244d4804dSStefan Eßer 15344d4804dSStefan Eßer /// The parser struct. 15478bc019dSStefan Eßer typedef struct BcParse 15578bc019dSStefan Eßer { 15644d4804dSStefan Eßer /// The lexer. 157252884aeSStefan Eßer BcLex l; 158252884aeSStefan Eßer 159252884aeSStefan Eßer #if BC_ENABLED 16044d4804dSStefan Eßer /// The stack of flags for bc. (See comments in include/bc.h.) This stack is 16144d4804dSStefan Eßer /// *required* to have one item at all times. Not maintaining that invariant 16244d4804dSStefan Eßer /// will cause problems. 163252884aeSStefan Eßer BcVec flags; 16444d4804dSStefan Eßer 16544d4804dSStefan Eßer /// The stack of exits. These are indices into the bytecode vector where 16644d4804dSStefan Eßer /// blocks for loops and if statements end. Basically, these are the places 16744d4804dSStefan Eßer /// to jump to when skipping code. 168252884aeSStefan Eßer BcVec exits; 16944d4804dSStefan Eßer 17044d4804dSStefan Eßer /// The stack of conditionals. Unlike exits, which are indices to jump 17144d4804dSStefan Eßer /// *forward* to, this is a vector of indices to jump *backward* to, usually 17244d4804dSStefan Eßer /// to the conditional of a loop, hence the name. 173252884aeSStefan Eßer BcVec conds; 17444d4804dSStefan Eßer 17544d4804dSStefan Eßer /// A stack of operators. When parsing expressions, the bc parser uses the 17644d4804dSStefan Eßer /// Shunting-Yard algorithm, which requires a stack of operators. This can 17744d4804dSStefan Eßer /// hold the stack for multiple expressions at once because the expressions 17844d4804dSStefan Eßer /// stack as well. For more information, see the Expression Parsing section 17944d4804dSStefan Eßer /// of the Development manual (manuals/development.md). 180252884aeSStefan Eßer BcVec ops; 18144d4804dSStefan Eßer 18244d4804dSStefan Eßer /// A buffer to temporarily store a string in. This is because the lexer 18344d4804dSStefan Eßer /// might generate a string as part of its work, and the parser needs that 18444d4804dSStefan Eßer /// string, but it also needs the lexer to continue lexing, which might 18544d4804dSStefan Eßer /// overwrite the string stored in the lexer. This buffer is for copying 18644d4804dSStefan Eßer /// that string from the lexer to keep it safe. 187252884aeSStefan Eßer BcVec buf; 188252884aeSStefan Eßer #endif // BC_ENABLED 189252884aeSStefan Eßer 19044d4804dSStefan Eßer /// A reference to the program to grab the current function when necessary. 191252884aeSStefan Eßer struct BcProgram* prog; 19244d4804dSStefan Eßer 19344d4804dSStefan Eßer /// A reference to the current function. The function is what holds the 19444d4804dSStefan Eßer /// bytecode vector that the parser is filling. 195252884aeSStefan Eßer BcFunc* func; 19644d4804dSStefan Eßer 19744d4804dSStefan Eßer /// The index of the function. 198252884aeSStefan Eßer size_t fidx; 199252884aeSStefan Eßer 20044d4804dSStefan Eßer #if BC_ENABLED 20144d4804dSStefan Eßer /// True if the bc parser just entered a function and an auto statement 20244d4804dSStefan Eßer /// would be valid. 203252884aeSStefan Eßer bool auto_part; 20444d4804dSStefan Eßer #endif // BC_ENABLED 205252884aeSStefan Eßer 206252884aeSStefan Eßer } BcParse; 207252884aeSStefan Eßer 20844d4804dSStefan Eßer /** 20944d4804dSStefan Eßer * Initializes a parser. 21044d4804dSStefan Eßer * @param p The parser to initialize. 21144d4804dSStefan Eßer * @param prog A referenc to the program. 21244d4804dSStefan Eßer * @param func The index of the current function. 21344d4804dSStefan Eßer */ 21478bc019dSStefan Eßer void 21578bc019dSStefan Eßer bc_parse_init(BcParse* p, struct BcProgram* prog, size_t func); 21644d4804dSStefan Eßer 21744d4804dSStefan Eßer /** 218103d7cdfSStefan Eßer * Frees a parser. This is not guarded by #if BC_DEBUG because a separate 21944d4804dSStefan Eßer * parser is created at runtime to parse read() expressions and dc strings. 22044d4804dSStefan Eßer * @param p The parser to free. 22144d4804dSStefan Eßer */ 22278bc019dSStefan Eßer void 22378bc019dSStefan Eßer bc_parse_free(BcParse* p); 22444d4804dSStefan Eßer 22544d4804dSStefan Eßer /** 22644d4804dSStefan Eßer * Resets the parser. Resetting means erasing all state to the point that the 22744d4804dSStefan Eßer * parser would think it was just initialized. 22844d4804dSStefan Eßer * @param p The parser to reset. 22944d4804dSStefan Eßer */ 23078bc019dSStefan Eßer void 23178bc019dSStefan Eßer bc_parse_reset(BcParse* p); 232252884aeSStefan Eßer 23344d4804dSStefan Eßer /** 23444d4804dSStefan Eßer * Adds a string. See @a BcProgram in include/program.h for more details. 23544d4804dSStefan Eßer * @param p The parser that parsed the string. 23644d4804dSStefan Eßer */ 23778bc019dSStefan Eßer void 23878bc019dSStefan Eßer bc_parse_addString(BcParse* p); 239252884aeSStefan Eßer 24044d4804dSStefan Eßer /** 24144d4804dSStefan Eßer * Adds a number. See @a BcProgram in include/program.h for more details. 24244d4804dSStefan Eßer * @param p The parser that parsed the number. 24344d4804dSStefan Eßer */ 24478bc019dSStefan Eßer void 24578bc019dSStefan Eßer bc_parse_number(BcParse* p); 24644d4804dSStefan Eßer 24744d4804dSStefan Eßer /** 24844d4804dSStefan Eßer * Update the current function in the parser. 24944d4804dSStefan Eßer * @param p The parser. 25044d4804dSStefan Eßer * @param fidx The index of the new function. 25144d4804dSStefan Eßer */ 25278bc019dSStefan Eßer void 25378bc019dSStefan Eßer bc_parse_updateFunc(BcParse* p, size_t fidx); 25444d4804dSStefan Eßer 25544d4804dSStefan Eßer /** 25644d4804dSStefan Eßer * Adds a new variable or array. See @a BcProgram in include/program.h for more 25744d4804dSStefan Eßer * details. 25844d4804dSStefan Eßer * @param p The parser that parsed the variable or array name. 25944d4804dSStefan Eßer * @param name The name of the variable or array to add. 26044d4804dSStefan Eßer * @param var True if the name is for a variable, false if it's for an array. 26144d4804dSStefan Eßer */ 26278bc019dSStefan Eßer void 26378bc019dSStefan Eßer bc_parse_pushName(const BcParse* p, char* name, bool var); 26444d4804dSStefan Eßer 26544d4804dSStefan Eßer /** 26644d4804dSStefan Eßer * Sets the text that the parser will parse. 26744d4804dSStefan Eßer * @param p The parser. 26844d4804dSStefan Eßer * @param text The text to lex. 269d101cdd6SStefan Eßer * @param mode The mode to parse in. 27044d4804dSStefan Eßer */ 27178bc019dSStefan Eßer void 272d101cdd6SStefan Eßer bc_parse_text(BcParse* p, const char* text, BcMode mode); 27344d4804dSStefan Eßer 27444d4804dSStefan Eßer // References to const 0 and 1 strings for special cases. bc and dc have 27544d4804dSStefan Eßer // specific instructions for 0 and 1 because they pop up so often and (in the 27644d4804dSStefan Eßer // case of 1), increment/decrement operators. 27750696a6eSStefan Eßer extern const char bc_parse_zero[2]; 27850696a6eSStefan Eßer extern const char bc_parse_one[2]; 279252884aeSStefan Eßer 280252884aeSStefan Eßer #endif // BC_PARSE_H 281