bc: add code to detect errors like "print 1 print 2"
function old new delta zbc_vm_process 831 925 +94 zbc_program_exec 3964 3976 +12 zdc_program_execStr 506 512 +6 zbc_lex_next 2161 2167 +6 zbc_program_assign 419 424 +5 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 5/0 up/down: 123/0) Total: 123 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
		| @@ -711,6 +711,7 @@ dc_LEX_to_INST[] = { // starts at XC_LEX_OP_POWER       // corresponding XC/DC_L | ||||
|  | ||||
| typedef struct BcLex { | ||||
| 	const char *buf; | ||||
| 	const char *lex_next_at; // last lex_next() was called at this string | ||||
| 	size_t i; | ||||
| 	size_t line; | ||||
| 	size_t len; | ||||
| @@ -2990,9 +2991,11 @@ static BC_STATUS zbc_lex_next(BcLex *l) | ||||
| 			} | ||||
| 			// here it's guaranteed that l->i is below l->len | ||||
| 		} | ||||
| 		l->lex_next_at = l->buf + l->i; | ||||
| 		dbg_lex("next string to parse:'%.*s'", | ||||
| 			(int)(strchrnul(l->buf + l->i, '\n') - (l->buf + l->i)), | ||||
| 			l->buf + l->i); | ||||
| 			(int)(strchrnul(l->lex_next_at, '\n') - l->lex_next_at), | ||||
| 			l->lex_next_at | ||||
| 		); | ||||
| 		if (IS_BC) { | ||||
| 			IF_BC(s = zbc_lex_token(l)); | ||||
| 		} else { | ||||
| @@ -6756,13 +6759,38 @@ static BC_STATUS zbc_vm_process(const char *text) | ||||
|  | ||||
| 		dbg_lex("%s:%d G.prs.l.lex:%d, parsing...", __func__, __LINE__, G.prs.l.lex); | ||||
| 		if (IS_BC) { | ||||
| // FIXME: "eating" of stmt delimiters is coded inconsistently | ||||
| // (sometimes zbc_parse_stmt() eats the delimiter, sometimes don't), | ||||
| // which causes bugs such as "print 1 print 2" erroneously accepted, | ||||
| // or "print 1 else 2" detecting parse error only after executing | ||||
| // "print 1" part. | ||||
| 			IF_BC(s = zbc_parse_stmt_or_funcdef(&G.prs)); | ||||
| #if ENABLE_BC | ||||
| 			s = zbc_parse_stmt_or_funcdef(&G.prs); | ||||
| 			if (s) goto err; | ||||
|  | ||||
| 			// Check that next token is not bogus, and skip over | ||||
| 			// stmt delimiter(s) - newlines and semicolons | ||||
| 			s = 1; // s == 1 on first iteration only | ||||
| 			for (;;) { | ||||
| 				if (G.prs.l.lex == XC_LEX_EOF) | ||||
| 					goto execute; // this goto avoids resetting 's' to zero | ||||
| 				if (G.prs.l.lex != BC_LEX_SCOLON | ||||
| 				 && G.prs.l.lex != XC_LEX_NLINE | ||||
| 				) { | ||||
| 					const char *err_at; | ||||
| 					// Not newline and not semicolon | ||||
| 					if (s == 0) // saw at least one NL/semicolon before it? | ||||
| 						break; // yes, good | ||||
| //TODO: commolalize for other parse errors: | ||||
| 					err_at = G.prs.l.lex_next_at ? G.prs.l.lex_next_at : "UNKNOWN"; | ||||
| 					bc_error_fmt("bad statement terminator at '%.*s'", | ||||
| 						(int)(strchrnul(err_at, '\n') - err_at), | ||||
| 						err_at | ||||
| 					); | ||||
| 					goto err; | ||||
| 				} | ||||
| 				// NL or semicolon: skip it, set s = 0, repeat | ||||
| 				s = zbc_lex_next(&G.prs.l); | ||||
| 				if (s) goto err; | ||||
| 			} | ||||
| #endif | ||||
| 		} else { | ||||
| #if ENABLE_DC | ||||
| 			// Most of dc parsing assumes all whitespace, | ||||
| 			// including '\n', is eaten. | ||||
| 			while (G.prs.l.lex == XC_LEX_NLINE) { | ||||
| @@ -6771,14 +6799,15 @@ static BC_STATUS zbc_vm_process(const char *text) | ||||
| 				if (G.prs.l.lex == XC_LEX_EOF) | ||||
| 					goto done; | ||||
| 			} | ||||
| 			IF_DC(s = zdc_parse_expr(&G.prs)); | ||||
| 			s = zdc_parse_expr(&G.prs); | ||||
| #endif | ||||
| 		} | ||||
| 		if (s || G_interrupt) { | ||||
|  err: | ||||
| 			bc_parse_reset(&G.prs); // includes bc_program_reset() | ||||
| 			RETURN_STATUS(BC_STATUS_FAILURE); | ||||
| 		} | ||||
|  | ||||
|  IF_BC(execute:) | ||||
| 		dbg_lex("%s:%d executing...", __func__, __LINE__); | ||||
| 		s = zbc_program_exec(); | ||||
| 		if (s) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user