diff options
-rw-r--r-- | miscutils/bc.c | 49 |
1 files changed, 34 insertions, 15 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c index bdee14de4..7be2d0b9b 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c | |||
@@ -3437,11 +3437,11 @@ static BC_STATUS zdc_lex_token(BcLex *l) | |||
3437 | // break; | 3437 | // break; |
3438 | case '\n': | 3438 | case '\n': |
3439 | // '\n' is BC_LEX_NLINE, not BC_LEX_WHITESPACE | 3439 | // '\n' is BC_LEX_NLINE, not BC_LEX_WHITESPACE |
3440 | // (and "case '\n'" is not just empty here) | 3440 | // (and "case '\n':" is not just empty here) |
3441 | // only to allow interactive dc have a way to exit | 3441 | // only to allow interactive dc have a way to exit |
3442 | // "parse" stage of "parse,execute" loop | 3442 | // "parse" stage of "parse,execute" loop |
3443 | // on '\n', not on _next_ token (which would mean | 3443 | // on <enter>, not on _next_ token (which would mean |
3444 | // command are not executed on pressing <enter>). | 3444 | // commands are not executed on pressing <enter>). |
3445 | // IOW: typing "1p<enter>" should print "1" _at once_, | 3445 | // IOW: typing "1p<enter>" should print "1" _at once_, |
3446 | // not after some more input. | 3446 | // not after some more input. |
3447 | l->t.t = BC_LEX_NLINE; | 3447 | l->t.t = BC_LEX_NLINE; |
@@ -6673,6 +6673,9 @@ static BC_STATUS zbc_vm_process(const char *text) | |||
6673 | if (s) RETURN_STATUS(s); | 6673 | if (s) RETURN_STATUS(s); |
6674 | 6674 | ||
6675 | while (G.prs.l.t.t != BC_LEX_EOF) { | 6675 | while (G.prs.l.t.t != BC_LEX_EOF) { |
6676 | BcInstPtr *ip; | ||
6677 | BcFunc *f; | ||
6678 | |||
6676 | dbg_lex("%s:%d G.prs.l.t.t:%d, parsing...", __func__, __LINE__, G.prs.l.t.t); | 6679 | dbg_lex("%s:%d G.prs.l.t.t:%d, parsing...", __func__, __LINE__, G.prs.l.t.t); |
6677 | if (IS_BC) { | 6680 | if (IS_BC) { |
6678 | // FIXME: "eating" of stmt delimiters is coded inconsistently | 6681 | // FIXME: "eating" of stmt delimiters is coded inconsistently |
@@ -6695,6 +6698,15 @@ static BC_STATUS zbc_vm_process(const char *text) | |||
6695 | bc_program_reset(); | 6698 | bc_program_reset(); |
6696 | break; | 6699 | break; |
6697 | } | 6700 | } |
6701 | |||
6702 | ip = (void*)G.prog.exestack.v; | ||
6703 | #if SANITY_CHECKS | ||
6704 | if (G.prog.exestack.len != 1) // should have only main's IP | ||
6705 | bb_error_msg_and_die("BUG:call stack"); | ||
6706 | if (ip->func != BC_PROG_MAIN) | ||
6707 | bb_error_msg_and_die("BUG:not MAIN"); | ||
6708 | #endif | ||
6709 | f = bc_program_func_BC_PROG_MAIN(); | ||
6698 | // bc discards strings, constants and code after each | 6710 | // bc discards strings, constants and code after each |
6699 | // top-level statement in the "main program". | 6711 | // top-level statement in the "main program". |
6700 | // This prevents "yes 1 | bc" from growing its memory | 6712 | // This prevents "yes 1 | bc" from growing its memory |
@@ -6706,22 +6718,10 @@ static BC_STATUS zbc_vm_process(const char *text) | |||
6706 | // but bc stores function strings/constants in per-function | 6718 | // but bc stores function strings/constants in per-function |
6707 | // storage. | 6719 | // storage. |
6708 | if (IS_BC) { | 6720 | if (IS_BC) { |
6709 | BcFunc *f; | ||
6710 | BcInstPtr *ip = (void*)G.prog.exestack.v; | ||
6711 | |||
6712 | #if SANITY_CHECKS | 6721 | #if SANITY_CHECKS |
6713 | if (G.prog.results.len != 0) // should be empty | 6722 | if (G.prog.results.len != 0) // should be empty |
6714 | bb_error_msg_and_die("BUG:data stack"); | 6723 | bb_error_msg_and_die("BUG:data stack"); |
6715 | if (G.prog.exestack.len != 1) // should have only main's IP | ||
6716 | bb_error_msg_and_die("BUG:call stack"); | ||
6717 | if (ip->func != BC_PROG_MAIN) | ||
6718 | bb_error_msg_and_die("BUG:not MAIN"); | ||
6719 | #endif | 6724 | #endif |
6720 | //bb_error_msg("ip->func:%d >idx:%d >len:%d", ip->func, ip->inst_idx, ip->len); | ||
6721 | f = bc_program_func_BC_PROG_MAIN(); | ||
6722 | //bb_error_msg("MAIN->code.len:%d >strs.len:%d >consts.len:%d", f->code.len, f->strs.len, f->consts.len); // labels, autos, nparams | ||
6723 | bc_vec_pop_all(&f->code); | ||
6724 | ip->inst_idx = 0; | ||
6725 | IF_BC(bc_vec_pop_all(&f->strs);) | 6725 | IF_BC(bc_vec_pop_all(&f->strs);) |
6726 | IF_BC(bc_vec_pop_all(&f->consts);) | 6726 | IF_BC(bc_vec_pop_all(&f->consts);) |
6727 | } else { | 6727 | } else { |
@@ -6731,7 +6731,26 @@ static BC_STATUS zbc_vm_process(const char *text) | |||
6731 | s = zbc_lex_next(&G.prs.l); | 6731 | s = zbc_lex_next(&G.prs.l); |
6732 | if (s) RETURN_STATUS(s); | 6732 | if (s) RETURN_STATUS(s); |
6733 | } | 6733 | } |
6734 | |||
6735 | if (G.prog.results.len == 0 | ||
6736 | && G.prog.vars.len == 0 | ||
6737 | ) { | ||
6738 | // If stack is empty and no registers exist (TODO: or they are all empty), | ||
6739 | // we can get rid of accumulated strings and constants. | ||
6740 | // In this example dc process should not grow | ||
6741 | // its memory consumption with time: | ||
6742 | // yes 1pc | dc | ||
6743 | IF_DC(bc_vec_pop_all(&G.prog.strs);) | ||
6744 | IF_DC(bc_vec_pop_all(&G.prog.consts);) | ||
6745 | } | ||
6746 | // The code is discarded always (below), thus this example | ||
6747 | // should also not grow its memory consumption with time, | ||
6748 | // even though its data stack is not empty: | ||
6749 | // { echo 1; yes dk; } | dc | ||
6734 | } | 6750 | } |
6751 | // We drop generated and executed code for both bc and dc: | ||
6752 | bc_vec_pop_all(&f->code); | ||
6753 | ip->inst_idx = 0; | ||
6735 | } | 6754 | } |
6736 | 6755 | ||
6737 | dbg_lex_done("%s:%d done", __func__, __LINE__); | 6756 | dbg_lex_done("%s:%d done", __func__, __LINE__); |