bc: handle "limits" and "quit" immediately at parse time

No need to propagate a special exit code.

function                                             old     new   delta
bc_parse_stmt                                       2197    2301    +104
quit                                                   -      38     +38
bc_read_line                                         344     349      +5
bc_program_reset                                     174     172      -2
bc_num_s                                             252     246      -6
bc_num_a                                             454     445      -9
bc_parse_parse                                       471     461     -10
bc_num_ulong                                          95      85     -10
bc_program_exec                                     4500    4478     -22
bc_vm_run                                           2006    1978     -28
bc_vm_process                                        291     139    -152
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 2/8 up/down: 147/-239)          Total: -92 bytes
   text	   data	    bss	    dec	    hex	filename
 987936	    485	   7296	 995717	  f3185	busybox_old
 987844	    485	   7296	 995625	  f3129	busybox_unstripped

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2018-12-03 14:02:35 +01:00
parent 01cabafd05
commit cfdc1334c3

View File

@ -231,8 +231,8 @@ typedef enum BcStatus {
BC_STATUS_POSIX_FOR3, BC_STATUS_POSIX_FOR3,
BC_STATUS_POSIX_BRACE, BC_STATUS_POSIX_BRACE,
#endif #endif
BC_STATUS_QUIT, // BC_STATUS_QUIT,
BC_STATUS_LIMITS, // BC_STATUS_LIMITS,
// BC_STATUS_INVALID_OPTION, // BC_STATUS_INVALID_OPTION,
} BcStatus; } BcStatus;
@ -1121,6 +1121,13 @@ static const char bc_lib[] = {
}; };
#endif // ENABLE_BC #endif // ENABLE_BC
static void quit(void) NORETURN;
static void quit(void)
{
fflush_all();
exit(ferror(stdout) || ferror(stderr));
}
static void bc_vec_grow(BcVec *v, size_t n) static void bc_vec_grow(BcVec *v, size_t n)
{ {
size_t cap = v->cap * 2; size_t cap = v->cap * 2;
@ -1279,9 +1286,9 @@ static BcStatus bc_read_line(BcVec *vec, const char *prompt)
fflush(stdout); fflush(stdout);
#if ENABLE_FEATURE_BC_SIGNALS #if ENABLE_FEATURE_BC_SIGNALS
if (bb_got_signal) { /* ^C was pressed */ if (bb_got_signal) { // ^C was pressed
intr: intr:
bb_got_signal = 0; /* resets G_interrupt to zero */ bb_got_signal = 0; // resets G_interrupt to zero
fputs(IS_BC fputs(IS_BC
? "\ninterrupt (type \"quit\" to exit)\n" ? "\ninterrupt (type \"quit\" to exit)\n"
: "\ninterrupt (type \"q\" to exit)\n" : "\ninterrupt (type \"q\" to exit)\n"
@ -1293,7 +1300,6 @@ static BcStatus bc_read_line(BcVec *vec, const char *prompt)
fflush(stderr); fflush(stderr);
#if ENABLE_FEATURE_BC_SIGNALS #if ENABLE_FEATURE_BC_SIGNALS
again:
errno = 0; errno = 0;
#endif #endif
do { do {
@ -1302,16 +1308,13 @@ static BcStatus bc_read_line(BcVec *vec, const char *prompt)
i = fgetc(stdin); i = fgetc(stdin);
#if ENABLE_FEATURE_BC_SIGNALS
if (bb_got_signal) /* ^C was pressed */
goto intr;
#endif
if (i == EOF) { if (i == EOF) {
#if ENABLE_FEATURE_BC_SIGNALS #if ENABLE_FEATURE_BC_SIGNALS
if (errno == EINTR) { // Both conditions appear simultaneously, check both just in case
if (errno == EINTR || bb_got_signal) {
// ^C was pressed
clearerr(stdin); clearerr(stdin);
goto again; goto intr;
} }
#endif #endif
if (ferror(stdin)) if (ferror(stdin))
@ -4630,9 +4633,18 @@ static BcStatus bc_parse_stmt(BcParse *p)
case BC_LEX_KEY_LIMITS: case BC_LEX_KEY_LIMITS:
{ {
// "limits" is a compile-time command,
// the output is produced at _parse time_.
s = bc_lex_next(&p->l); s = bc_lex_next(&p->l);
if (s) return s; if (s) return s;
s = BC_STATUS_LIMITS; printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
printf("MAX Exponent = %lu\n", BC_MAX_EXP);
printf("Number of vars = %lu\n", BC_MAX_VARS);
break; break;
} }
@ -4644,10 +4656,10 @@ static BcStatus bc_parse_stmt(BcParse *p)
case BC_LEX_KEY_QUIT: case BC_LEX_KEY_QUIT:
{ {
// Quit is a compile-time command. We don't exit directly, // "quit" is a compile-time command. For example,
// so the vm can clean up. Limits do the same thing. // "if (0 == 1) quit" terminates when parsing the statement,
s = BC_STATUS_QUIT; // not when it is executed
break; quit();
} }
case BC_LEX_KEY_RETURN: case BC_LEX_KEY_RETURN:
@ -4685,7 +4697,7 @@ static BcStatus bc_parse_parse(BcParse *p)
else else
s = bc_parse_stmt(p); s = bc_parse_stmt(p);
if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || G_interrupt) if (s || G_interrupt)
s = bc_parse_reset(p, s); s = bc_parse_reset(p, s);
return s; return s;
@ -6283,8 +6295,8 @@ static BcStatus bc_program_nquit(void)
if (G.prog.stack.len < val) if (G.prog.stack.len < val)
return BC_STATUS_EXEC_STACK; return BC_STATUS_EXEC_STACK;
else if (G.prog.stack.len == val) if (G.prog.stack.len == val)
return BC_STATUS_QUIT; quit();
bc_vec_npop(&G.prog.stack, val); bc_vec_npop(&G.prog.stack, val);
@ -6456,17 +6468,15 @@ static BcStatus bc_program_reset(BcStatus s)
ip = bc_vec_top(&G.prog.stack); ip = bc_vec_top(&G.prog.stack);
ip->idx = f->code.len; ip->idx = f->code.len;
if (!s && G_interrupt && !G.tty) return BC_STATUS_QUIT; if (!s && G_interrupt && !G.tty) quit();
if (!s || s == BC_STATUS_EXEC_SIGNAL) { if (!s || s == BC_STATUS_EXEC_SIGNAL) {
if (G.ttyin) { if (!G.ttyin)
fflush(stdout); quit();
fputs(bc_program_ready_msg, stderr); fflush(stdout);
fflush(stderr); fputs(bc_program_ready_msg, stderr);
s = BC_STATUS_SUCCESS; fflush(stderr);
} s = BC_STATUS_SUCCESS;
else
s = BC_STATUS_QUIT;
} }
return s; return s;
@ -6524,7 +6534,7 @@ static BcStatus bc_program_exec(void)
case BC_INST_HALT: case BC_INST_HALT:
{ {
s = BC_STATUS_QUIT; quit();
break; break;
} }
@ -6767,9 +6777,8 @@ static BcStatus bc_program_exec(void)
case BC_INST_QUIT: case BC_INST_QUIT:
{ {
if (G.prog.stack.len <= 2) if (G.prog.stack.len <= 2)
s = BC_STATUS_QUIT; quit();
else bc_vec_npop(&G.prog.stack, 2);
bc_vec_npop(&G.prog.stack, 2);
break; break;
} }
@ -6781,7 +6790,7 @@ static BcStatus bc_program_exec(void)
#endif // ENABLE_DC #endif // ENABLE_DC
} }
if ((s && s != BC_STATUS_QUIT) || G_interrupt) s = bc_program_reset(s); if (s || G_interrupt) s = bc_program_reset(s);
// If the stack has changed, pointers may be invalid. // If the stack has changed, pointers may be invalid.
ip = bc_vec_top(&G.prog.stack); ip = bc_vec_top(&G.prog.stack);
@ -6895,30 +6904,14 @@ static BcStatus bc_vm_process(const char *text)
s = G.prs.parse(&G.prs); s = G.prs.parse(&G.prs);
if (s == BC_STATUS_LIMITS) { s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
if (s) return s;
printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
printf("MAX Exponent = %lu\n", BC_MAX_EXP);
printf("Number of vars = %lu\n", BC_MAX_VARS);
s = BC_STATUS_SUCCESS;
}
else {
if (s == BC_STATUS_QUIT) return s;
s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
if (s) return s;
}
} }
if (BC_PARSE_CAN_EXEC(&G.prs)) { if (BC_PARSE_CAN_EXEC(&G.prs)) {
s = bc_program_exec(); s = bc_program_exec();
if (!s && G.tty) fflush(stdout); fflush(stdout);
if (s && s != BC_STATUS_QUIT) if (s)
s = bc_vm_error(bc_program_reset(s), G.prs.l.f, 0); s = bc_vm_error(bc_program_reset(s), G.prs.l.f, 0);
} }
@ -7021,7 +7014,7 @@ static BcStatus bc_vm_stdin(void)
// INPUT_EOF will always happen when stdin is // INPUT_EOF will always happen when stdin is
// closed. It's not a problem in that case. // closed. It's not a problem in that case.
if (s == BC_STATUS_INPUT_EOF || s == BC_STATUS_QUIT) if (s == BC_STATUS_INPUT_EOF)
s = BC_STATUS_SUCCESS; s = BC_STATUS_SUCCESS;
if (str) if (str)
@ -7058,13 +7051,11 @@ static BcStatus bc_vm_exec(void)
for (i = 0; !s && i < G.files.len; ++i) for (i = 0; !s && i < G.files.len; ++i)
s = bc_vm_file(*((char **) bc_vec_item(&G.files, i))); s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
if (s && s != BC_STATUS_QUIT) return s; if (s) return s;
if (IS_BC || !G.files.len) s = bc_vm_stdin(); if (IS_BC || !G.files.len) s = bc_vm_stdin();
if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process(""); if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
if (s == BC_STATUS_QUIT)
s = BC_STATUS_SUCCESS;
return s; return s;
} }