bc: fix handling of 'return' not in functions, and 'define f()<newline>{...}'
function old new delta zbc_vm_process 561 597 +36 zbc_parse_stmt_possibly_auto 2232 2253 +21 zbc_lex_number 192 200 +8 zbc_num_divmod 150 156 +6 bc_vm_run 134 139 +5 bc_vm_init 757 760 +3 bc_num_printNewline 51 54 +3 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 7/0 up/down: 82/0) Total: 82 bytes text data bss dec hex filename 982138 485 7296 989919 f1adf busybox_old 982247 485 7296 990028 f1b4c busybox_unstripped Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
d1d29b4245
commit
e9519e44a6
@ -591,6 +591,8 @@ typedef struct BcParse {
|
||||
|
||||
//TODO: needed? Example?
|
||||
size_t nbraces;
|
||||
|
||||
size_t in_funcdef;
|
||||
} BcParse;
|
||||
|
||||
typedef struct BcProgram {
|
||||
@ -4057,19 +4059,16 @@ static BC_STATUS zbc_parse_return(BcParse *p)
|
||||
{
|
||||
BcStatus s;
|
||||
BcLexType t;
|
||||
bool paren;
|
||||
|
||||
dbg_lex_enter("%s:%d entered", __func__, __LINE__);
|
||||
|
||||
s = zbc_lex_next(&p->l);
|
||||
if (s) RETURN_STATUS(s);
|
||||
|
||||
t = p->l.t.t;
|
||||
paren = t == BC_LEX_LPAREN;
|
||||
|
||||
if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
|
||||
bc_parse_push(p, BC_INST_RET0);
|
||||
else {
|
||||
bool paren = (t == BC_LEX_LPAREN);
|
||||
s = bc_parse_expr_empty_ok(p, 0, bc_parse_next_expr);
|
||||
if (s == BC_STATUS_PARSE_EMPTY_EXP) {
|
||||
bc_parse_push(p, BC_INST_RET0);
|
||||
@ -4390,7 +4389,7 @@ static BC_STATUS zbc_parse_break_or_continue(BcParse *p, BcLexType type)
|
||||
# define zbc_parse_break_or_continue(...) (zbc_parse_break_or_continue(__VA_ARGS__), BC_STATUS_SUCCESS)
|
||||
#endif
|
||||
|
||||
static BC_STATUS zbc_parse_func(BcParse *p)
|
||||
static BC_STATUS zbc_parse_funcdef(BcParse *p)
|
||||
{
|
||||
BcStatus s;
|
||||
bool var, comma = false;
|
||||
@ -4454,7 +4453,16 @@ static BC_STATUS zbc_parse_func(BcParse *p)
|
||||
if (p->l.t.t != BC_LEX_LBRACE)
|
||||
s = bc_POSIX_requires("the left brace be on the same line as the function header");
|
||||
|
||||
// Prevent "define z()<newline>" to be interpreted as function with empty stmt as body
|
||||
while (p->l.t.t == BC_LEX_NLINE) {
|
||||
s = zbc_lex_next(&p->l);
|
||||
if (s) RETURN_STATUS(s);
|
||||
}
|
||||
//TODO: GNU bc requires a {} block even if function body has single stmt, enforce this?
|
||||
|
||||
p->in_funcdef++; // to determine whether "return" stmt is allowed, and such
|
||||
s = zbc_parse_stmt_possibly_auto(p, true);
|
||||
p->in_funcdef--;
|
||||
if (s) RETURN_STATUS(s);
|
||||
|
||||
bc_parse_push(p, BC_INST_RET0);
|
||||
@ -4467,7 +4475,7 @@ err:
|
||||
RETURN_STATUS(s);
|
||||
}
|
||||
#if ERRORS_ARE_FATAL
|
||||
# define zbc_parse_func(...) (zbc_parse_func(__VA_ARGS__), BC_STATUS_SUCCESS)
|
||||
# define zbc_parse_funcdef(...) (zbc_parse_funcdef(__VA_ARGS__), BC_STATUS_SUCCESS)
|
||||
#endif
|
||||
|
||||
static BC_STATUS zbc_parse_auto(BcParse *p)
|
||||
@ -4626,6 +4634,8 @@ static BC_STATUS zbc_parse_stmt_possibly_auto(BcParse *p, bool auto_allowed)
|
||||
// not when it is executed
|
||||
QUIT_OR_RETURN_TO_MAIN;
|
||||
case BC_LEX_KEY_RETURN:
|
||||
if (!p->in_funcdef)
|
||||
RETURN_STATUS(bc_error("'return' not in a function"));
|
||||
s = zbc_parse_return(p);
|
||||
break;
|
||||
case BC_LEX_KEY_WHILE:
|
||||
@ -4657,7 +4667,7 @@ static BC_STATUS zbc_parse_stmt_or_funcdef(BcParse *p)
|
||||
s = bc_error("end of file");
|
||||
else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
|
||||
dbg_lex("%s:%d p->l.t.t:BC_LEX_KEY_DEFINE", __func__, __LINE__);
|
||||
s = zbc_parse_func(p);
|
||||
s = zbc_parse_funcdef(p);
|
||||
} else {
|
||||
dbg_lex("%s:%d p->l.t.t:%d (not BC_LEX_KEY_DEFINE)", __func__, __LINE__, p->l.t.t);
|
||||
s = zbc_parse_stmt(p);
|
||||
@ -7021,7 +7031,13 @@ static BC_STATUS zbc_vm_stdin(void)
|
||||
bc_lex_file(&G.prs.l);
|
||||
|
||||
G.use_stdin = 1;
|
||||
s = zbc_vm_process("");
|
||||
do {
|
||||
s = zbc_vm_process("");
|
||||
// We do not stop looping on errors here.
|
||||
// Example: start interactive bc and enter "return".
|
||||
// It should say "'return' not in a function"
|
||||
// but should not exit.
|
||||
} while (G.use_stdin);
|
||||
RETURN_STATUS(s);
|
||||
}
|
||||
#if ERRORS_ARE_FATAL
|
||||
|
@ -51,6 +51,11 @@ testing "bc define auto" \
|
||||
"8\n9\n" \
|
||||
"" "define w() { auto z; return 8; }; w(); 9"
|
||||
|
||||
testing "bc define with body on next line" \
|
||||
"bc" \
|
||||
"8\n9\n" \
|
||||
"" "define w()\n{ auto z; return 8; }\nw()\n9"
|
||||
|
||||
tar xJf bc_large.tar.xz
|
||||
|
||||
for f in bc*.bc; do
|
||||
|
Loading…
Reference in New Issue
Block a user