Fix a bug I partially fixed in 5.1.0
The bug was the improper ending of if statements in files and before function definitions. In 5.1.0, I fixed it such that an if statement right before a function definition works, but not a series of if statements or if statements inbetween loops. This does the full fix. Signed-off-by: Gavin Howard <[email protected]>
This commit is contained in:
parent
16cd0feb66
commit
f60ce30fd5
|
@ -396,6 +396,15 @@ void bc_parse_expr(BcParse *p, uint8_t flags);
|
|||
*/
|
||||
void bc_parse_parse(BcParse *p);
|
||||
|
||||
/**
|
||||
* Ends a series of if statements. This is to ensure that full parses happen
|
||||
* when a file finishes or before defining a function. Without this, bc thinks
|
||||
* that it cannot parse any further. But if we reach the end of a file or a
|
||||
* function definition, we know we can add an empty else clause.
|
||||
* @param p The parser.
|
||||
*/
|
||||
void bc_parse_endif(BcParse *p);
|
||||
|
||||
/// References to the signal message and its length.
|
||||
extern const char bc_sig_msg[];
|
||||
extern const uchar bc_sig_msg_len;
|
||||
|
|
|
@ -999,6 +999,44 @@ static void bc_parse_startBody(BcParse *p, uint16_t flags) {
|
|||
bc_vec_push(&p->flags, &flags);
|
||||
}
|
||||
|
||||
void bc_parse_endif(BcParse *p) {
|
||||
|
||||
size_t i;
|
||||
bool good;
|
||||
|
||||
// Not a problem if this is true.
|
||||
if (BC_NO_ERR(!BC_PARSE_NO_EXEC(p))) return;
|
||||
|
||||
good = true;
|
||||
|
||||
// Find an instance of a body that needs closing, i.e., a statement that did
|
||||
// not have a right brace when it should have.
|
||||
for (i = 0; good && i < p->flags.len; ++i) {
|
||||
uint16_t flag = *((uint16_t*) bc_vec_item(&p->flags, i));
|
||||
good = ((flag & BC_PARSE_FLAG_BRACE) != BC_PARSE_FLAG_BRACE);
|
||||
}
|
||||
|
||||
// If we did not find such an instance...
|
||||
if (good) {
|
||||
|
||||
// We set this to restore it later. We don't want the parser thinking
|
||||
// that we are on stdin for this one because it will want more.
|
||||
bool is_stdin = vm.is_stdin;
|
||||
|
||||
vm.is_stdin = false;
|
||||
|
||||
// End all of the if statements and loops.
|
||||
while (p->flags.len > 1 || BC_PARSE_IF_END(p)) {
|
||||
if (BC_PARSE_IF_END(p)) bc_parse_noElse(p);
|
||||
if (p->flags.len > 1) bc_parse_endBody(p, false);
|
||||
}
|
||||
|
||||
vm.is_stdin = is_stdin;
|
||||
}
|
||||
// If we reach here, a block was not properly closed, and we should error.
|
||||
else bc_parse_err(&vm.prs, BC_ERR_PARSE_BLOCK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an if statement.
|
||||
* @param p The parser.
|
||||
|
@ -1730,12 +1768,9 @@ void bc_parse_parse(BcParse *p) {
|
|||
// Functions need special parsing.
|
||||
else if (p->l.t == BC_LEX_KW_DEFINE) {
|
||||
if (BC_ERR(BC_PARSE_NO_EXEC(p))) {
|
||||
if (p->flags.len == 1 &&
|
||||
BC_PARSE_TOP_FLAG(p) == BC_PARSE_FLAG_IF_END)
|
||||
{
|
||||
bc_parse_noElse(p);
|
||||
}
|
||||
else bc_parse_err(p, BC_ERR_PARSE_TOKEN);
|
||||
bc_parse_endif(p);
|
||||
if (BC_ERR(BC_PARSE_NO_EXEC(p)))
|
||||
bc_parse_err(p, BC_ERR_PARSE_TOKEN);
|
||||
}
|
||||
bc_parse_func(p);
|
||||
}
|
||||
|
|
43
src/vm.c
43
src/vm.c
|
@ -839,45 +839,14 @@ static void bc_vm_process(const char *text, bool is_stdin) {
|
|||
#if BC_ENABLED
|
||||
|
||||
/**
|
||||
* Ends an if statement that ends a file. This is to ensure that full parses
|
||||
* happen when a file finishes. Without this, bc thinks that it cannot parse
|
||||
* any further. But if we reach the end of a file, we know we can add an empty
|
||||
* else clause.
|
||||
* Ends a series of if statements. This is to ensure that full parses happen
|
||||
* when a file finishes or stdin has no more data. Without this, bc thinks that
|
||||
* it cannot parse any further. But if we reach the end of a file or stdin has
|
||||
* no more data, we know we can add an empty else clause.
|
||||
*/
|
||||
static void bc_vm_endif(void) {
|
||||
|
||||
size_t i;
|
||||
bool good;
|
||||
|
||||
// Not a problem if this is true.
|
||||
if (BC_NO_ERR(!BC_PARSE_NO_EXEC(&vm.prs))) return;
|
||||
|
||||
good = true;
|
||||
|
||||
// Find an instance of a body that needs closing, i.e., a statement that did
|
||||
// not have a right brace when it should have.
|
||||
for (i = 0; good && i < vm.prs.flags.len; ++i) {
|
||||
uint16_t flag = *((uint16_t*) bc_vec_item(&vm.prs.flags, i));
|
||||
good = ((flag & BC_PARSE_FLAG_BRACE) != BC_PARSE_FLAG_BRACE);
|
||||
}
|
||||
|
||||
// If we did not find such an instance...
|
||||
if (good) {
|
||||
|
||||
// We set this to restore it later. We don't want the parser thinking
|
||||
// that we are on stdin for this one because it will want more.
|
||||
bool is_stdin = vm.is_stdin;
|
||||
|
||||
vm.is_stdin = false;
|
||||
|
||||
// Cheat and keep parsing empty else clauses until all of them are
|
||||
// satisfied.
|
||||
while (BC_PARSE_IF_END(&vm.prs)) bc_vm_process("else {}", false);
|
||||
|
||||
vm.is_stdin = is_stdin;
|
||||
}
|
||||
// If we reach here, a block was not properly closed, and we should error.
|
||||
else bc_parse_err(&vm.prs, BC_ERR_PARSE_BLOCK);
|
||||
bc_parse_endif(&vm.prs);
|
||||
bc_program_exec(&vm.prog);
|
||||
}
|
||||
#endif // BC_ENABLED
|
||||
|
||||
|
|
Loadingâ¦
Reference in New Issue