diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-25 18:37:52 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-25 18:37:52 +0100 |
commit | 2638454464b944f9c407326257851bab13c045ec (patch) | |
tree | 6afd3f8d336f4f22cc7bf87b40d896fadeff8879 | |
parent | 5fa74b9efc538b55ec164ce3886eeea782016487 (diff) | |
download | busybox-w32-2638454464b944f9c407326257851bab13c045ec.tar.gz busybox-w32-2638454464b944f9c407326257851bab13c045ec.tar.bz2 busybox-w32-2638454464b944f9c407326257851bab13c045ec.zip |
bc: add code to detect errors like "print 1 print 2"
function old new delta
zbc_vm_process 831 925 +94
zbc_program_exec 3964 3976 +12
zdc_program_execStr 506 512 +6
zbc_lex_next 2161 2167 +6
zbc_program_assign 419 424 +5
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 5/0 up/down: 123/0) Total: 123 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | miscutils/bc.c | 49 |
1 files changed, 39 insertions, 10 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c index 7c8edcf33..8b44d4425 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c | |||
@@ -711,6 +711,7 @@ dc_LEX_to_INST[] = { // starts at XC_LEX_OP_POWER // corresponding XC/DC_L | |||
711 | 711 | ||
712 | typedef struct BcLex { | 712 | typedef struct BcLex { |
713 | const char *buf; | 713 | const char *buf; |
714 | const char *lex_next_at; // last lex_next() was called at this string | ||
714 | size_t i; | 715 | size_t i; |
715 | size_t line; | 716 | size_t line; |
716 | size_t len; | 717 | size_t len; |
@@ -2990,9 +2991,11 @@ static BC_STATUS zbc_lex_next(BcLex *l) | |||
2990 | } | 2991 | } |
2991 | // here it's guaranteed that l->i is below l->len | 2992 | // here it's guaranteed that l->i is below l->len |
2992 | } | 2993 | } |
2994 | l->lex_next_at = l->buf + l->i; | ||
2993 | dbg_lex("next string to parse:'%.*s'", | 2995 | dbg_lex("next string to parse:'%.*s'", |
2994 | (int)(strchrnul(l->buf + l->i, '\n') - (l->buf + l->i)), | 2996 | (int)(strchrnul(l->lex_next_at, '\n') - l->lex_next_at), |
2995 | l->buf + l->i); | 2997 | l->lex_next_at |
2998 | ); | ||
2996 | if (IS_BC) { | 2999 | if (IS_BC) { |
2997 | IF_BC(s = zbc_lex_token(l)); | 3000 | IF_BC(s = zbc_lex_token(l)); |
2998 | } else { | 3001 | } else { |
@@ -6756,13 +6759,38 @@ static BC_STATUS zbc_vm_process(const char *text) | |||
6756 | 6759 | ||
6757 | dbg_lex("%s:%d G.prs.l.lex:%d, parsing...", __func__, __LINE__, G.prs.l.lex); | 6760 | dbg_lex("%s:%d G.prs.l.lex:%d, parsing...", __func__, __LINE__, G.prs.l.lex); |
6758 | if (IS_BC) { | 6761 | if (IS_BC) { |
6759 | // FIXME: "eating" of stmt delimiters is coded inconsistently | 6762 | #if ENABLE_BC |
6760 | // (sometimes zbc_parse_stmt() eats the delimiter, sometimes don't), | 6763 | s = zbc_parse_stmt_or_funcdef(&G.prs); |
6761 | // which causes bugs such as "print 1 print 2" erroneously accepted, | 6764 | if (s) goto err; |
6762 | // or "print 1 else 2" detecting parse error only after executing | 6765 | |
6763 | // "print 1" part. | 6766 | // Check that next token is not bogus, and skip over |
6764 | IF_BC(s = zbc_parse_stmt_or_funcdef(&G.prs)); | 6767 | // stmt delimiter(s) - newlines and semicolons |
6768 | s = 1; // s == 1 on first iteration only | ||
6769 | for (;;) { | ||
6770 | if (G.prs.l.lex == XC_LEX_EOF) | ||
6771 | goto execute; // this goto avoids resetting 's' to zero | ||
6772 | if (G.prs.l.lex != BC_LEX_SCOLON | ||
6773 | && G.prs.l.lex != XC_LEX_NLINE | ||
6774 | ) { | ||
6775 | const char *err_at; | ||
6776 | // Not newline and not semicolon | ||
6777 | if (s == 0) // saw at least one NL/semicolon before it? | ||
6778 | break; // yes, good | ||
6779 | //TODO: commolalize for other parse errors: | ||
6780 | err_at = G.prs.l.lex_next_at ? G.prs.l.lex_next_at : "UNKNOWN"; | ||
6781 | bc_error_fmt("bad statement terminator at '%.*s'", | ||
6782 | (int)(strchrnul(err_at, '\n') - err_at), | ||
6783 | err_at | ||
6784 | ); | ||
6785 | goto err; | ||
6786 | } | ||
6787 | // NL or semicolon: skip it, set s = 0, repeat | ||
6788 | s = zbc_lex_next(&G.prs.l); | ||
6789 | if (s) goto err; | ||
6790 | } | ||
6791 | #endif | ||
6765 | } else { | 6792 | } else { |
6793 | #if ENABLE_DC | ||
6766 | // Most of dc parsing assumes all whitespace, | 6794 | // Most of dc parsing assumes all whitespace, |
6767 | // including '\n', is eaten. | 6795 | // including '\n', is eaten. |
6768 | while (G.prs.l.lex == XC_LEX_NLINE) { | 6796 | while (G.prs.l.lex == XC_LEX_NLINE) { |
@@ -6771,14 +6799,15 @@ static BC_STATUS zbc_vm_process(const char *text) | |||
6771 | if (G.prs.l.lex == XC_LEX_EOF) | 6799 | if (G.prs.l.lex == XC_LEX_EOF) |
6772 | goto done; | 6800 | goto done; |
6773 | } | 6801 | } |
6774 | IF_DC(s = zdc_parse_expr(&G.prs)); | 6802 | s = zdc_parse_expr(&G.prs); |
6803 | #endif | ||
6775 | } | 6804 | } |
6776 | if (s || G_interrupt) { | 6805 | if (s || G_interrupt) { |
6777 | err: | 6806 | err: |
6778 | bc_parse_reset(&G.prs); // includes bc_program_reset() | 6807 | bc_parse_reset(&G.prs); // includes bc_program_reset() |
6779 | RETURN_STATUS(BC_STATUS_FAILURE); | 6808 | RETURN_STATUS(BC_STATUS_FAILURE); |
6780 | } | 6809 | } |
6781 | 6810 | IF_BC(execute:) | |
6782 | dbg_lex("%s:%d executing...", __func__, __LINE__); | 6811 | dbg_lex("%s:%d executing...", __func__, __LINE__); |
6783 | s = zbc_program_exec(); | 6812 | s = zbc_program_exec(); |
6784 | if (s) { | 6813 | if (s) { |