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;
}
}
-#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'?
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
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
{
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
// 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);
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<newline>" at once (comment is not continued)
- // 1 #comment/* - prints "1<newline>" at once
- // 1 #comment" - prints "1<newline>" at once
- // 1\#comment - error at once (\ is not a line continuation)
- // 1 + /*"*/2 - prints "3<newline>" at once
- // 1 + /*#*/2 - prints "3<newline>" 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#\<newline>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, \<newline> 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;
}
// 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<newline>" at once (comment is not continued)
+// 1 #comment/* - prints "1<newline>" at once
+// 1 #comment" - prints "1<newline>" at once
+// 1\#comment - error at once (\ is not a line continuation)
+// 1 + /*"*/2 - prints "3<newline>" at once
+// 1 + /*#*/2 - prints "3<newline>" 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#\<newline>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;
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());
}
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);)