From b1b7996a2acd8a95ae13dad1f64f86e221167cb7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Dec 2018 18:46:03 +0100 Subject: [PATCH] bc: remove all logic for multi-line buffering function old new delta zbc_vm_process 865 874 +9 zbc_parse_text_init 51 38 -13 bc_read_line 394 345 -49 peek_inbuf 292 69 -223 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/3 up/down: 9/-285) Total: -276 bytes Signed-off-by: Denys Vlasenko --- miscutils/bc.c | 144 +++++++------------------------------------------ 1 file changed, 19 insertions(+), 125 deletions(-) diff --git a/miscutils/bc.c b/miscutils/bc.c index 5789869a7..632158b7f 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c @@ -715,7 +715,6 @@ typedef struct BcParse { smallint lex_last; // was BcLexType size_t lex_line; const char *lex_inbuf; - const char *lex_end; const char *lex_next_at; // last lex_next() was called at this string const char *lex_filename; FILE *lex_input_fp; @@ -2473,21 +2472,6 @@ static FAST_FUNC void bc_result_free(void *result) } } -#if ENABLE_FEATURE_BC_SIGNALS && ENABLE_FEATURE_EDITING -static void bc_vec_concat(BcVec *v, const char *str) -{ - size_t len, slen; - - slen = strlen(str); - len = v->len + slen + 1; - - if (v->cap < len) bc_vec_grow(v, slen); - strcpy(v->v + v->len, str); - - v->len = len; -} -#endif - static int bad_input_byte(char c) { if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'? @@ -2499,10 +2483,10 @@ static int bad_input_byte(char c) return 0; } -// Note: it _appends_ data from fp to vec. static void bc_read_line(BcVec *vec, FILE *fp) { again: + bc_vec_pop_all(vec); fflush_and_check(); #if ENABLE_FEATURE_BC_SIGNALS @@ -2542,7 +2526,7 @@ static void bc_read_line(BcVec *vec, FILE *fp) if (!c) break; if (bad_input_byte(c)) goto again; } - bc_vec_concat(vec, line_buf); + bc_vec_string(vec, n, line_buf); # undef line_buf } else # endif @@ -2550,13 +2534,12 @@ static void bc_read_line(BcVec *vec, FILE *fp) { int c; bool bad_chars = 0; - size_t len = vec->len; do { #if ENABLE_FEATURE_BC_SIGNALS if (G_interrupt) { // ^C was pressed: ignore entire line, get another one - vec->len = len; + bc_vec_pop_all(vec); goto intr; } #endif @@ -2575,7 +2558,6 @@ static void bc_read_line(BcVec *vec, FILE *fp) // Bad chars on this line if (!G.prs.lex_filename) { // stdin // ignore entire line, get another one - vec->len = len; goto again; } bb_perror_msg_and_die("file '%s' is not text", G.prs.lex_filename); @@ -2743,113 +2725,13 @@ static BC_STATUS zbc_num_parse(BcNum *n, const char *val, unsigned base_t) static bool bc_lex_more_input(void) { BcParse *p = &G.prs; - unsigned str; // bool for bc, string nest count for dc - bool comment; bc_vec_pop_all(&G.input_buffer); - // This loop is complex because the vm tries not to send any lines that end - // with a backslash to the parser. The reason for that is because the parser - // treats a backslash+newline combo as whitespace, per the bc spec. In that - // case, and for strings and comments, the parser will expect more stuff. - // - // bc cases to test interactively: - // 1 #comment\ - prints "1" at once (comment is not continued) - // 1 #comment/* - prints "1" at once - // 1 #comment" - prints "1" at once - // 1\#comment - error at once (\ is not a line continuation) - // 1 + /*"*/2 - prints "3" at once - // 1 + /*#*/2 - prints "3" at once - // "str\" - prints "str\" at once - // "str#" - prints "str#" at once - // "str/*" - prints "str/*" at once - // "str#\ - waits for second line - // end" - ...prints "str#\end" -//This is way too complex, we duplicate comment/string logic of lexer -//TODO: switch to char-by-char input like hush does it - str = 0; - comment = false; // stays always false for dc - for (;;) { - size_t prevlen = G.input_buffer.len; - char *string; - - bc_read_line(&G.input_buffer, G.prs.lex_input_fp); - // No more input means EOF - if (G.input_buffer.len <= prevlen + 1) // (we expect +1 for NUL byte) - break; - - string = G.input_buffer.v + prevlen; - while (*string) { - char c = *string++; -#if ENABLE_BC - if (comment) { - // We are in /**/ comment, exit only on "*/" - if (c == '*' && *string == '/') { - comment = false; - string++; - } - continue; - } -#endif - // We are not in /**/ comment - if (str) { - // We are in "string" (bc) or [string] (dc) - if (IS_BC) { - // bc strings have no escapes: \\ is not special, - // \n is not, \" is not, \ is not. - str = (c != '"'); // clear flag when " is seen - } else { - // dc strings have no escapes as well, can nest - if (c == ']') - str--; - if (c == '[') - str++; - } - continue; - } - // We are not in a string or /**/ comment - - // Is it a #comment? Return the string (can't have continuation) - if (c == '#') - goto return_string; -#if ENABLE_BC - if (IS_BC) { - // bc: is it a start of /**/ comment or string? - if (c == '/' && *string == '*') { - comment = true; - string++; - continue; - } - str = (c == '"'); // set flag if " is seen - continue; - } -#endif - // dc: is it a start of string? - str = (c == '['); - } // end of "check all chars in string" loop - - if (str != 0 || comment) { - G.input_buffer.len--; // backstep over the trailing NUL byte - continue; - } - - // Check for backslash+newline. - // We do not check that last char is '\n' - - // if it is not, then it's EOF, and looping back - // to bc_read_line() will detect it: - string -= 2; - if (string >= G.input_buffer.v && *string == '\\') { - G.input_buffer.len--; - continue; - } - - break; - } - return_string: + bc_read_line(&G.input_buffer, G.prs.lex_input_fp); p->lex_inbuf = G.input_buffer.v; // bb_error_msg("G.input_buffer.len:%d '%s'", G.input_buffer.len, G.input_buffer.v); - p->lex_end = p->lex_inbuf + G.input_buffer.len - 1; // do not include NUL return G.input_buffer.len > 1; } @@ -2872,9 +2754,22 @@ static bool bc_lex_more_input(void) // In many cases, you can use fast *p->lex_inbuf instead of peek_inbuf(): // unless prev char might have been '\n', *p->lex_inbuf is '\0' ONLY // on real EOF, not end-of-buffer. +// +// bc cases to test interactively: +// 1 #comment\ - prints "1" at once (comment is not continued) +// 1 #comment/* - prints "1" at once +// 1 #comment" - prints "1" at once +// 1\#comment - error at once (\ is not a line continuation) +// 1 + /*"*/2 - prints "3" at once +// 1 + /*#*/2 - prints "3" at once +// "str\" - prints "str\" at once +// "str#" - prints "str#" at once +// "str/*" - prints "str/*" at once +// "str#\ - waits for second line +// end" - ...prints "str#\end" static char peek_inbuf(void) { - if (G.prs.lex_inbuf == G.prs.lex_end) { + if (*G.prs.lex_inbuf == '\0') { if (G.prs.lex_input_fp) if (!bc_lex_more_input()) G.prs.lex_input_fp = NULL; @@ -3060,7 +2955,6 @@ static BC_STATUS zbc_lex_next_and_skip_NLINE(void) static BC_STATUS zbc_lex_text_init(const char *text) { G.prs.lex_inbuf = text; - G.prs.lex_end = text + strlen(text); G.prs.lex = G.prs.lex_last = XC_LEX_INVALID; RETURN_STATUS(zbc_lex_next()); } @@ -3652,7 +3546,7 @@ static void bc_parse_reset(void) p->func = bc_program_func_BC_PROG_MAIN(); } - p->lex_inbuf = p->lex_end; + p->lex_inbuf += strlen(p->lex_inbuf); p->lex = XC_LEX_EOF; IF_BC(bc_vec_pop_all(&p->exits);) -- 2.25.1