/*1* *****************************************************************************2*3* SPDX-License-Identifier: BSD-2-Clause4*5* Copyright (c) 2018-2025 Gavin D. Howard and contributors.6*7* Redistribution and use in source and binary forms, with or without8* modification, are permitted provided that the following conditions are met:9*10* * Redistributions of source code must retain the above copyright notice, this11* list of conditions and the following disclaimer.12*13* * Redistributions in binary form must reproduce the above copyright notice,14* this list of conditions and the following disclaimer in the documentation15* and/or other materials provided with the distribution.16*17* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"18* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE19* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE20* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE21* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR22* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF23* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS24* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN25* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)26* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE27* POSSIBILITY OF SUCH DAMAGE.28*29* *****************************************************************************30*31* Definitions for bc's parser.32*33*/3435#ifndef BC_PARSE_H36#define BC_PARSE_H3738#include <limits.h>39#include <stdbool.h>40#include <stdint.h>4142#include <status.h>43#include <vector.h>44#include <lex.h>45#include <lang.h>4647// The following are flags that can be passed to @a BcParseExpr functions. They48// define the requirements that the parsed expression must meet to not have an49// error thrown.5051/// A flag that requires that the expression is valid for conditionals in for52/// loops, while loops, and if statements. This is because POSIX requires that53/// certain operators are *only* used in those cases. It's whacked, but that's54/// how it is.55#define BC_PARSE_REL (UINTMAX_C(1) << 0)5657/// A flag that requires that the expression is valid for a print statement.58#define BC_PARSE_PRINT (UINTMAX_C(1) << 1)5960/// A flag that requires that the expression does *not* have any function call.61#define BC_PARSE_NOCALL (UINTMAX_C(1) << 2)6263/// A flag that requires that the expression does *not* have a read()64/// expression.65#define BC_PARSE_NOREAD (UINTMAX_C(1) << 3)6667/// A flag that *allows* (rather than requires) that an array appear in the68/// expression. This is mostly used as parameters in bc.69#define BC_PARSE_ARRAY (UINTMAX_C(1) << 4)7071/// A flag that requires that the expression is not empty and returns a value.72#define BC_PARSE_NEEDVAL (UINTMAX_C(1) << 5)7374/**75* Returns true if the parser has been initialized.76* @param p The parser.77* @param prg The program.78* @return True if @a p has been initialized, false otherwise.79*/80#define BC_PARSE_IS_INITED(p, prg) ((p)->prog == (prg))8182/**83* Returns true if the current parser state allows parsing, false otherwise.84* @param p The parser.85* @return True if parsing can proceed, false otherwise.86*/87#define BC_PARSE_CAN_PARSE(p) ((p).l.t != BC_LEX_EOF)8889/**90* Pushes the instruction @a i onto the bytecode vector for the current91* function.92* @param p The parser.93* @param i The instruction to push onto the bytecode vector.94*/95#define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (uchar) (i)))9697/**98* Pushes an index onto the bytecode vector. For more information, see99* @a bc_vec_pushIndex() in src/vector.c and @a bc_program_index() in100* src/program.c.101* @param p The parser.102* @param idx The index to push onto the bytecode vector.103*/104#define bc_parse_pushIndex(p, idx) (bc_vec_pushIndex(&(p)->func->code, (idx)))105106/**107* A convenience macro for throwing errors in parse code. This takes care of108* plumbing like passing in the current line the lexer is on.109* @param p The parser.110* @param e The error.111*/112#if BC_DEBUG113#define bc_parse_err(p, e) \114(bc_vm_handleError((e), __FILE__, __LINE__, (p)->l.line))115#else // BC_DEBUG116#define bc_parse_err(p, e) (bc_vm_handleError((e), (p)->l.line))117#endif // BC_DEBUG118119/**120* A convenience macro for throwing errors in parse code. This takes care of121* plumbing like passing in the current line the lexer is on.122* @param p The parser.123* @param e The error.124* @param ... The varags that are needed.125*/126#if BC_DEBUG127#define bc_parse_verr(p, e, ...) \128(bc_vm_handleError((e), __FILE__, __LINE__, (p)->l.line, __VA_ARGS__))129#else // BC_DEBUG130#define bc_parse_verr(p, e, ...) \131(bc_vm_handleError((e), (p)->l.line, __VA_ARGS__))132#endif // BC_DEBUG133134// Forward declarations.135struct BcParse;136struct BcProgram;137138/**139* A function pointer to call when more parsing is needed.140* @param p The parser.141*/142typedef void (*BcParseParse)(struct BcParse* p);143144/**145* A function pointer to call when an expression needs to be parsed. This can146* happen for read() expressions or dc strings.147* @param p The parser.148* @param flags The flags for what is allowed or required. (See flags above.)149*/150typedef void (*BcParseExpr)(struct BcParse* p, uint8_t flags);151152/// The parser struct.153typedef struct BcParse154{155/// The lexer.156BcLex l;157158#if BC_ENABLED159/// The stack of flags for bc. (See comments in include/bc.h.) This stack is160/// *required* to have one item at all times. Not maintaining that invariant161/// will cause problems.162BcVec flags;163164/// The stack of exits. These are indices into the bytecode vector where165/// blocks for loops and if statements end. Basically, these are the places166/// to jump to when skipping code.167BcVec exits;168169/// The stack of conditionals. Unlike exits, which are indices to jump170/// *forward* to, this is a vector of indices to jump *backward* to, usually171/// to the conditional of a loop, hence the name.172BcVec conds;173174/// A stack of operators. When parsing expressions, the bc parser uses the175/// Shunting-Yard algorithm, which requires a stack of operators. This can176/// hold the stack for multiple expressions at once because the expressions177/// stack as well. For more information, see the Expression Parsing section178/// of the Development manual (manuals/development.md).179BcVec ops;180181/// A buffer to temporarily store a string in. This is because the lexer182/// might generate a string as part of its work, and the parser needs that183/// string, but it also needs the lexer to continue lexing, which might184/// overwrite the string stored in the lexer. This buffer is for copying185/// that string from the lexer to keep it safe.186BcVec buf;187#endif // BC_ENABLED188189/// A reference to the program to grab the current function when necessary.190struct BcProgram* prog;191192/// A reference to the current function. The function is what holds the193/// bytecode vector that the parser is filling.194BcFunc* func;195196/// The index of the function.197size_t fidx;198199#if BC_ENABLED200/// True if the bc parser just entered a function and an auto statement201/// would be valid.202bool auto_part;203#endif // BC_ENABLED204205} BcParse;206207/**208* Initializes a parser.209* @param p The parser to initialize.210* @param prog A referenc to the program.211* @param func The index of the current function.212*/213void214bc_parse_init(BcParse* p, struct BcProgram* prog, size_t func);215216/**217* Frees a parser. This is not guarded by #if BC_DEBUG because a separate218* parser is created at runtime to parse read() expressions and dc strings.219* @param p The parser to free.220*/221void222bc_parse_free(BcParse* p);223224/**225* Resets the parser. Resetting means erasing all state to the point that the226* parser would think it was just initialized.227* @param p The parser to reset.228*/229void230bc_parse_reset(BcParse* p);231232/**233* Adds a string. See @a BcProgram in include/program.h for more details.234* @param p The parser that parsed the string.235*/236void237bc_parse_addString(BcParse* p);238239/**240* Adds a number. See @a BcProgram in include/program.h for more details.241* @param p The parser that parsed the number.242*/243void244bc_parse_number(BcParse* p);245246/**247* Update the current function in the parser.248* @param p The parser.249* @param fidx The index of the new function.250*/251void252bc_parse_updateFunc(BcParse* p, size_t fidx);253254/**255* Adds a new variable or array. See @a BcProgram in include/program.h for more256* details.257* @param p The parser that parsed the variable or array name.258* @param name The name of the variable or array to add.259* @param var True if the name is for a variable, false if it's for an array.260*/261void262bc_parse_pushName(const BcParse* p, char* name, bool var);263264/**265* Sets the text that the parser will parse.266* @param p The parser.267* @param text The text to lex.268* @param mode The mode to parse in.269*/270void271bc_parse_text(BcParse* p, const char* text, BcMode mode);272273// References to const 0 and 1 strings for special cases. bc and dc have274// specific instructions for 0 and 1 because they pop up so often and (in the275// case of 1), increment/decrement operators.276extern const char bc_parse_zero[2];277extern const char bc_parse_one[2];278279#endif // BC_PARSE_H280281282