diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2019-01-01 21:50:14 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2019-01-01 21:50:14 +0100 |
commit | 2231468a2f28e99cb6b65dc40da044e37af16ed1 (patch) | |
tree | 5c465febbb98e80314452e6114e3c4b78d36a381 | |
parent | ff65355b8a44d1d546443f69382459eb2176cb44 (diff) | |
download | busybox-w32-2231468a2f28e99cb6b65dc40da044e37af16ed1.tar.gz busybox-w32-2231468a2f28e99cb6b65dc40da044e37af16ed1.tar.bz2 busybox-w32-2231468a2f28e99cb6b65dc40da044e37af16ed1.zip |
bc: upstream fixes
function old new delta
bc_parse_expr_empty_ok 1764 1843 +79
bc_error_at - 62 +62
bc_parse_inst_isLeaf - 30 +30
zbc_func_insert 100 120 +20
bc_error_bad_function_definition - 10 +10
bc_error_bad_assignment - 10 +10
zxc_lex_next 1608 1614 +6
ok_in_expr 30 - -30
zxc_vm_process 874 839 -35
------------------------------------------------------------------------------
(add/remove: 4/1 grow/shrink: 3/1 up/down: 217/-65) Total: 152 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | miscutils/bc.c | 177 | ||||
-rwxr-xr-x | testsuite/bc.tests | 16 |
2 files changed, 110 insertions, 83 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c index 23b3521d4..1b9cdce5e 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c | |||
@@ -971,19 +971,42 @@ static ERRORFUNC int bc_error(const char *msg) | |||
971 | { | 971 | { |
972 | IF_ERROR_RETURN_POSSIBLE(return) bc_error_fmt("%s", msg); | 972 | IF_ERROR_RETURN_POSSIBLE(return) bc_error_fmt("%s", msg); |
973 | } | 973 | } |
974 | static ERRORFUNC int bc_error_at(const char *msg) | ||
975 | { | ||
976 | const char *err_at = G.prs.lex_next_at; | ||
977 | if (err_at) { | ||
978 | IF_ERROR_RETURN_POSSIBLE(return) bc_error_fmt( | ||
979 | "%s at '%.*s'", | ||
980 | msg, | ||
981 | (int)(strchrnul(err_at, '\n') - err_at), | ||
982 | err_at | ||
983 | ); | ||
984 | } | ||
985 | IF_ERROR_RETURN_POSSIBLE(return) bc_error_fmt("%s", msg); | ||
986 | } | ||
974 | static ERRORFUNC int bc_error_bad_character(char c) | 987 | static ERRORFUNC int bc_error_bad_character(char c) |
975 | { | 988 | { |
976 | if (!c) | 989 | if (!c) |
977 | IF_ERROR_RETURN_POSSIBLE(return) bc_error("NUL character"); | 990 | IF_ERROR_RETURN_POSSIBLE(return) bc_error("NUL character"); |
978 | IF_ERROR_RETURN_POSSIBLE(return) bc_error_fmt("bad character '%c'", c); | 991 | IF_ERROR_RETURN_POSSIBLE(return) bc_error_fmt("bad character '%c'", c); |
979 | } | 992 | } |
993 | static ERRORFUNC int bc_error_bad_function_definition(void) | ||
994 | { | ||
995 | IF_ERROR_RETURN_POSSIBLE(return) bc_error_at("bad function definition"); | ||
996 | } | ||
980 | static ERRORFUNC int bc_error_bad_expression(void) | 997 | static ERRORFUNC int bc_error_bad_expression(void) |
981 | { | 998 | { |
982 | IF_ERROR_RETURN_POSSIBLE(return) bc_error("bad expression"); | 999 | IF_ERROR_RETURN_POSSIBLE(return) bc_error_at("bad expression"); |
1000 | } | ||
1001 | static ERRORFUNC int bc_error_bad_assignment(void) | ||
1002 | { | ||
1003 | IF_ERROR_RETURN_POSSIBLE(return) bc_error_at( | ||
1004 | "bad assignment: left side must be variable or array element" | ||
1005 | ); | ||
983 | } | 1006 | } |
984 | static ERRORFUNC int bc_error_bad_token(void) | 1007 | static ERRORFUNC int bc_error_bad_token(void) |
985 | { | 1008 | { |
986 | IF_ERROR_RETURN_POSSIBLE(return) bc_error("bad token"); | 1009 | IF_ERROR_RETURN_POSSIBLE(return) bc_error_at("bad token"); |
987 | } | 1010 | } |
988 | static ERRORFUNC int bc_error_stack_has_too_few_elements(void) | 1011 | static ERRORFUNC int bc_error_stack_has_too_few_elements(void) |
989 | { | 1012 | { |
@@ -2853,6 +2876,7 @@ static BC_STATUS zxc_lex_number(char last) | |||
2853 | if (c == '\\' && p->lex_inbuf[1] == '\n') { | 2876 | if (c == '\\' && p->lex_inbuf[1] == '\n') { |
2854 | p->lex_inbuf += 2; | 2877 | p->lex_inbuf += 2; |
2855 | p->lex_line++; | 2878 | p->lex_line++; |
2879 | dbg_lex("++p->lex_line=%zd", p->lex_line); | ||
2856 | c = peek_inbuf(); // force next line to be read | 2880 | c = peek_inbuf(); // force next line to be read |
2857 | goto check_c; | 2881 | goto check_c; |
2858 | } | 2882 | } |
@@ -2919,6 +2943,7 @@ static BC_STATUS zxc_lex_next(void) | |||
2919 | BcParse *p = &G.prs; | 2943 | BcParse *p = &G.prs; |
2920 | BcStatus s; | 2944 | BcStatus s; |
2921 | 2945 | ||
2946 | G.err_line = p->lex_line; | ||
2922 | p->lex_last = p->lex; | 2947 | p->lex_last = p->lex; |
2923 | //why? | 2948 | //why? |
2924 | // if (p->lex_last == XC_LEX_EOF) | 2949 | // if (p->lex_last == XC_LEX_EOF) |
@@ -3031,8 +3056,10 @@ static BC_STATUS zbc_lex_string(void) | |||
3031 | } | 3056 | } |
3032 | if (c == '"') | 3057 | if (c == '"') |
3033 | break; | 3058 | break; |
3034 | if (c == '\n') | 3059 | if (c == '\n') { |
3035 | p->lex_line++; | 3060 | p->lex_line++; |
3061 | dbg_lex("++p->lex_line=%zd", p->lex_line); | ||
3062 | } | ||
3036 | bc_vec_push(&p->lex_strnumbuf, p->lex_inbuf); | 3063 | bc_vec_push(&p->lex_strnumbuf, p->lex_inbuf); |
3037 | p->lex_inbuf++; | 3064 | p->lex_inbuf++; |
3038 | } | 3065 | } |
@@ -3079,8 +3106,10 @@ static BC_STATUS zbc_lex_comment(void) | |||
3079 | if (c == '\0') { | 3106 | if (c == '\0') { |
3080 | RETURN_STATUS(bc_error("unterminated comment")); | 3107 | RETURN_STATUS(bc_error("unterminated comment")); |
3081 | } | 3108 | } |
3082 | if (c == '\n') | 3109 | if (c == '\n') { |
3083 | p->lex_line++; | 3110 | p->lex_line++; |
3111 | dbg_lex("++p->lex_line=%zd", p->lex_line); | ||
3112 | } | ||
3084 | } | 3113 | } |
3085 | p->lex_inbuf++; // skip trailing '/' | 3114 | p->lex_inbuf++; // skip trailing '/' |
3086 | 3115 | ||
@@ -3105,6 +3134,7 @@ static BC_STATUS zbc_lex_token(void) | |||
3105 | // break; | 3134 | // break; |
3106 | case '\n': | 3135 | case '\n': |
3107 | p->lex_line++; | 3136 | p->lex_line++; |
3137 | dbg_lex("++p->lex_line=%zd", p->lex_line); | ||
3108 | p->lex = XC_LEX_NLINE; | 3138 | p->lex = XC_LEX_NLINE; |
3109 | break; | 3139 | break; |
3110 | case '\t': | 3140 | case '\t': |
@@ -3341,8 +3371,10 @@ static BC_STATUS zdc_lex_string(void) | |||
3341 | if (c == ']') | 3371 | if (c == ']') |
3342 | if (--depth == 0) | 3372 | if (--depth == 0) |
3343 | break; | 3373 | break; |
3344 | if (c == '\n') | 3374 | if (c == '\n') { |
3345 | p->lex_line++; | 3375 | p->lex_line++; |
3376 | dbg_lex("++p->lex_line=%zd", p->lex_line); | ||
3377 | } | ||
3346 | bc_vec_push(&p->lex_strnumbuf, p->lex_inbuf); | 3378 | bc_vec_push(&p->lex_strnumbuf, p->lex_inbuf); |
3347 | p->lex_inbuf++; | 3379 | p->lex_inbuf++; |
3348 | } | 3380 | } |
@@ -3399,6 +3431,7 @@ static BC_STATUS zdc_lex_token(void) | |||
3399 | // IOW: typing "1p<enter>" should print "1" _at once_, | 3431 | // IOW: typing "1p<enter>" should print "1" _at once_, |
3400 | // not after some more input. | 3432 | // not after some more input. |
3401 | p->lex_line++; | 3433 | p->lex_line++; |
3434 | dbg_lex("++p->lex_line=%zd", p->lex_line); | ||
3402 | p->lex = XC_LEX_NLINE; | 3435 | p->lex = XC_LEX_NLINE; |
3403 | break; | 3436 | break; |
3404 | case '\t': | 3437 | case '\t': |
@@ -3960,8 +3993,7 @@ static BC_STATUS zbc_parse_scale(BcInst *type, uint8_t flags) | |||
3960 | } | 3993 | } |
3961 | #define zbc_parse_scale(...) (zbc_parse_scale(__VA_ARGS__) COMMA_SUCCESS) | 3994 | #define zbc_parse_scale(...) (zbc_parse_scale(__VA_ARGS__) COMMA_SUCCESS) |
3962 | 3995 | ||
3963 | static BC_STATUS zbc_parse_incdec(BcInst *prev, bool *paren_expr, | 3996 | static BC_STATUS zbc_parse_incdec(BcInst *prev, size_t *nexs, uint8_t flags) |
3964 | size_t *nexprs, uint8_t flags) | ||
3965 | { | 3997 | { |
3966 | BcParse *p = &G.prs; | 3998 | BcParse *p = &G.prs; |
3967 | BcStatus s; | 3999 | BcStatus s; |
@@ -3978,7 +4010,6 @@ static BC_STATUS zbc_parse_incdec(BcInst *prev, bool *paren_expr, | |||
3978 | s = zxc_lex_next(); | 4010 | s = zxc_lex_next(); |
3979 | } else { | 4011 | } else { |
3980 | *prev = inst = BC_INST_INC_PRE + (p->lex != BC_LEX_OP_INC); | 4012 | *prev = inst = BC_INST_INC_PRE + (p->lex != BC_LEX_OP_INC); |
3981 | *paren_expr = true; | ||
3982 | 4013 | ||
3983 | s = zxc_lex_next(); | 4014 | s = zxc_lex_next(); |
3984 | if (s) RETURN_STATUS(s); | 4015 | if (s) RETURN_STATUS(s); |
@@ -3986,7 +4017,7 @@ static BC_STATUS zbc_parse_incdec(BcInst *prev, bool *paren_expr, | |||
3986 | 4017 | ||
3987 | // Because we parse the next part of the expression | 4018 | // Because we parse the next part of the expression |
3988 | // right here, we need to increment this. | 4019 | // right here, we need to increment this. |
3989 | *nexprs = *nexprs + 1; | 4020 | *nexs = *nexs + 1; |
3990 | 4021 | ||
3991 | switch (type) { | 4022 | switch (type) { |
3992 | case XC_LEX_NAME: | 4023 | case XC_LEX_NAME: |
@@ -4018,36 +4049,27 @@ static BC_STATUS zbc_parse_incdec(BcInst *prev, bool *paren_expr, | |||
4018 | } | 4049 | } |
4019 | #define zbc_parse_incdec(...) (zbc_parse_incdec(__VA_ARGS__) COMMA_SUCCESS) | 4050 | #define zbc_parse_incdec(...) (zbc_parse_incdec(__VA_ARGS__) COMMA_SUCCESS) |
4020 | 4051 | ||
4021 | #if 0 | 4052 | static int bc_parse_inst_isLeaf(BcInst p) |
4022 | #define BC_PARSE_LEAF(p, rparen) \ | ||
4023 | ((rparen) \ | ||
4024 | || ((p) >= XC_INST_NUM && (p) <= XC_INST_SQRT) \ | ||
4025 | || (p) == BC_INST_INC_POST \ | ||
4026 | || (p) == BC_INST_DEC_POST \ | ||
4027 | ) | ||
4028 | #else | ||
4029 | static int ok_in_expr(BcInst p) | ||
4030 | { | 4053 | { |
4031 | return (p >= XC_INST_NUM && p <= XC_INST_SQRT) | 4054 | return (p >= XC_INST_NUM && p <= XC_INST_SQRT) |
4032 | || p == BC_INST_INC_POST | 4055 | || p == BC_INST_INC_POST |
4033 | || p == BC_INST_DEC_POST | 4056 | || p == BC_INST_DEC_POST |
4034 | ; | 4057 | ; |
4035 | } | 4058 | } |
4036 | #define BC_PARSE_LEAF(p, rparen) ((rparen) || ok_in_expr(p)) | 4059 | #define BC_PARSE_LEAF(prev, bin_last, rparen) \ |
4037 | #endif | 4060 | (!(bin_last) && ((rparen) || bc_parse_inst_isLeaf(prev))) |
4038 | 4061 | ||
4039 | static BC_STATUS zbc_parse_minus(BcInst *prev, size_t ops_bgn, | 4062 | static BC_STATUS zbc_parse_minus(BcInst *prev, size_t ops_bgn, |
4040 | bool rparen, size_t *nexprs) | 4063 | bool rparen, bool bin_last, size_t *nexprs) |
4041 | { | 4064 | { |
4042 | BcParse *p = &G.prs; | 4065 | BcParse *p = &G.prs; |
4043 | BcStatus s; | 4066 | BcStatus s; |
4044 | BcLexType type; | 4067 | BcLexType type; |
4045 | BcInst etype = *prev; | ||
4046 | 4068 | ||
4047 | s = zxc_lex_next(); | 4069 | s = zxc_lex_next(); |
4048 | if (s) RETURN_STATUS(s); | 4070 | if (s) RETURN_STATUS(s); |
4049 | 4071 | ||
4050 | type = BC_PARSE_LEAF(etype, rparen) ? XC_LEX_OP_MINUS : XC_LEX_NEG; | 4072 | type = BC_PARSE_LEAF(*prev, bin_last, rparen) ? XC_LEX_OP_MINUS : XC_LEX_NEG; |
4051 | *prev = BC_TOKEN_2_INST(type); | 4073 | *prev = BC_TOKEN_2_INST(type); |
4052 | 4074 | ||
4053 | // We can just push onto the op stack because this is the largest | 4075 | // We can just push onto the op stack because this is the largest |
@@ -4334,8 +4356,11 @@ static BC_STATUS zbc_func_insert(BcFunc *f, char *name, bool var) | |||
4334 | 4356 | ||
4335 | autoid = (void*)f->autos.v; | 4357 | autoid = (void*)f->autos.v; |
4336 | for (i = 0; i < f->autos.len; i++, autoid++) { | 4358 | for (i = 0; i < f->autos.len; i++, autoid++) { |
4337 | if (strcmp(name, autoid->name) == 0) | 4359 | if (strcmp(name, autoid->name) == 0 |
4360 | && var == autoid->idx | ||
4361 | ) { | ||
4338 | RETURN_STATUS(bc_error("duplicate function parameter or auto name")); | 4362 | RETURN_STATUS(bc_error("duplicate function parameter or auto name")); |
4363 | } | ||
4339 | } | 4364 | } |
4340 | 4365 | ||
4341 | a.idx = var; | 4366 | a.idx = var; |
@@ -4358,7 +4383,7 @@ static BC_STATUS zbc_parse_funcdef(void) | |||
4358 | s = zxc_lex_next(); | 4383 | s = zxc_lex_next(); |
4359 | if (s) RETURN_STATUS(s); | 4384 | if (s) RETURN_STATUS(s); |
4360 | if (p->lex != XC_LEX_NAME) | 4385 | if (p->lex != XC_LEX_NAME) |
4361 | RETURN_STATUS(bc_error("bad function definition")); | 4386 | RETURN_STATUS(bc_error_bad_function_definition()); |
4362 | 4387 | ||
4363 | name = xstrdup(p->lex_strnumbuf.v); | 4388 | name = xstrdup(p->lex_strnumbuf.v); |
4364 | p->fidx = bc_program_addFunc(name); | 4389 | p->fidx = bc_program_addFunc(name); |
@@ -4367,13 +4392,13 @@ static BC_STATUS zbc_parse_funcdef(void) | |||
4367 | s = zxc_lex_next(); | 4392 | s = zxc_lex_next(); |
4368 | if (s) RETURN_STATUS(s); | 4393 | if (s) RETURN_STATUS(s); |
4369 | if (p->lex != BC_LEX_LPAREN) | 4394 | if (p->lex != BC_LEX_LPAREN) |
4370 | RETURN_STATUS(bc_error("bad function definition")); | 4395 | RETURN_STATUS(bc_error_bad_function_definition()); |
4371 | s = zxc_lex_next(); | 4396 | s = zxc_lex_next(); |
4372 | if (s) RETURN_STATUS(s); | 4397 | if (s) RETURN_STATUS(s); |
4373 | 4398 | ||
4374 | while (p->lex != BC_LEX_RPAREN) { | 4399 | while (p->lex != BC_LEX_RPAREN) { |
4375 | if (p->lex != XC_LEX_NAME) | 4400 | if (p->lex != XC_LEX_NAME) |
4376 | RETURN_STATUS(bc_error("bad function definition")); | 4401 | RETURN_STATUS(bc_error_bad_function_definition()); |
4377 | 4402 | ||
4378 | ++p->func->nparams; | 4403 | ++p->func->nparams; |
4379 | 4404 | ||
@@ -4388,7 +4413,7 @@ static BC_STATUS zbc_parse_funcdef(void) | |||
4388 | if (s) goto err; | 4413 | if (s) goto err; |
4389 | 4414 | ||
4390 | if (p->lex != BC_LEX_RBRACKET) { | 4415 | if (p->lex != BC_LEX_RBRACKET) { |
4391 | s = bc_error("bad function definition"); | 4416 | s = bc_error_bad_function_definition(); |
4392 | goto err; | 4417 | goto err; |
4393 | } | 4418 | } |
4394 | 4419 | ||
@@ -4406,7 +4431,7 @@ static BC_STATUS zbc_parse_funcdef(void) | |||
4406 | if (s) goto err; | 4431 | if (s) goto err; |
4407 | } | 4432 | } |
4408 | 4433 | ||
4409 | if (comma) RETURN_STATUS(bc_error("bad function definition")); | 4434 | if (comma) RETURN_STATUS(bc_error_bad_function_definition()); |
4410 | 4435 | ||
4411 | s = zxc_lex_next(); | 4436 | s = zxc_lex_next(); |
4412 | if (s) RETURN_STATUS(s); | 4437 | if (s) RETURN_STATUS(s); |
@@ -4457,7 +4482,7 @@ static BC_STATUS zbc_parse_auto(void) | |||
4457 | bool var; | 4482 | bool var; |
4458 | 4483 | ||
4459 | if (p->lex != XC_LEX_NAME) | 4484 | if (p->lex != XC_LEX_NAME) |
4460 | RETURN_STATUS(bc_error("bad 'auto' syntax")); | 4485 | RETURN_STATUS(bc_error_at("bad 'auto' syntax")); |
4461 | 4486 | ||
4462 | name = xstrdup(p->lex_strnumbuf.v); | 4487 | name = xstrdup(p->lex_strnumbuf.v); |
4463 | s = zxc_lex_next(); | 4488 | s = zxc_lex_next(); |
@@ -4469,7 +4494,7 @@ static BC_STATUS zbc_parse_auto(void) | |||
4469 | if (s) goto err; | 4494 | if (s) goto err; |
4470 | 4495 | ||
4471 | if (p->lex != BC_LEX_RBRACKET) { | 4496 | if (p->lex != BC_LEX_RBRACKET) { |
4472 | s = bc_error("bad 'auto' syntax"); | 4497 | s = bc_error_at("bad 'auto' syntax"); |
4473 | goto err; | 4498 | goto err; |
4474 | } | 4499 | } |
4475 | s = zxc_lex_next(); | 4500 | s = zxc_lex_next(); |
@@ -4486,7 +4511,7 @@ static BC_STATUS zbc_parse_auto(void) | |||
4486 | break; | 4511 | break; |
4487 | } | 4512 | } |
4488 | if (p->lex != BC_LEX_COMMA) | 4513 | if (p->lex != BC_LEX_COMMA) |
4489 | RETURN_STATUS(bc_error("bad 'auto' syntax")); | 4514 | RETURN_STATUS(bc_error_at("bad 'auto' syntax")); |
4490 | s = zxc_lex_next(); // skip comma | 4515 | s = zxc_lex_next(); // skip comma |
4491 | if (s) RETURN_STATUS(s); | 4516 | if (s) RETURN_STATUS(s); |
4492 | } | 4517 | } |
@@ -4643,12 +4668,12 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags) | |||
4643 | BcInst prev = XC_INST_PRINT; | 4668 | BcInst prev = XC_INST_PRINT; |
4644 | size_t nexprs = 0, ops_bgn = p->ops.len; | 4669 | size_t nexprs = 0, ops_bgn = p->ops.len; |
4645 | unsigned nparens, nrelops; | 4670 | unsigned nparens, nrelops; |
4646 | bool paren_first, paren_expr, rprn, assign, bin_last; | 4671 | bool paren_first, rprn, assign, bin_last, incdec; |
4647 | 4672 | ||
4648 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); | 4673 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); |
4649 | paren_first = (p->lex == BC_LEX_LPAREN); | 4674 | paren_first = (p->lex == BC_LEX_LPAREN); |
4650 | nparens = nrelops = 0; | 4675 | nparens = nrelops = 0; |
4651 | paren_expr = rprn = assign = false; | 4676 | rprn = assign = incdec = false; |
4652 | bin_last = true; | 4677 | bin_last = true; |
4653 | 4678 | ||
4654 | for (;;) { | 4679 | for (;;) { |
@@ -4666,16 +4691,19 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags) | |||
4666 | case BC_LEX_OP_INC: | 4691 | case BC_LEX_OP_INC: |
4667 | case BC_LEX_OP_DEC: | 4692 | case BC_LEX_OP_DEC: |
4668 | dbg_lex("%s:%d LEX_OP_INC/DEC", __func__, __LINE__); | 4693 | dbg_lex("%s:%d LEX_OP_INC/DEC", __func__, __LINE__); |
4669 | s = zbc_parse_incdec(&prev, &paren_expr, &nexprs, flags); | 4694 | if (incdec) return bc_error_bad_assignment(); |
4695 | s = zbc_parse_incdec(&prev, &nexprs, flags); | ||
4696 | incdec = true; | ||
4670 | rprn = bin_last = false; | 4697 | rprn = bin_last = false; |
4671 | //get_token = false; - already is | 4698 | //get_token = false; - already is |
4672 | break; | 4699 | break; |
4673 | case XC_LEX_OP_MINUS: | 4700 | case XC_LEX_OP_MINUS: |
4674 | dbg_lex("%s:%d LEX_OP_MINUS", __func__, __LINE__); | 4701 | dbg_lex("%s:%d LEX_OP_MINUS", __func__, __LINE__); |
4675 | s = zbc_parse_minus(&prev, ops_bgn, rprn, &nexprs); | 4702 | s = zbc_parse_minus(&prev, ops_bgn, rprn, bin_last, &nexprs); |
4676 | rprn = false; | 4703 | rprn = false; |
4677 | //get_token = false; - already is | 4704 | //get_token = false; - already is |
4678 | bin_last = (prev == XC_INST_MINUS); | 4705 | bin_last = (prev == XC_INST_MINUS); |
4706 | if (bin_last) incdec = false; | ||
4679 | break; | 4707 | break; |
4680 | case BC_LEX_OP_ASSIGN_POWER: | 4708 | case BC_LEX_OP_ASSIGN_POWER: |
4681 | case BC_LEX_OP_ASSIGN_MULTIPLY: | 4709 | case BC_LEX_OP_ASSIGN_MULTIPLY: |
@@ -4689,10 +4717,7 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags) | |||
4689 | && prev != XC_INST_SCALE && prev != XC_INST_IBASE | 4717 | && prev != XC_INST_SCALE && prev != XC_INST_IBASE |
4690 | && prev != XC_INST_OBASE && prev != BC_INST_LAST | 4718 | && prev != XC_INST_OBASE && prev != BC_INST_LAST |
4691 | ) { | 4719 | ) { |
4692 | return bc_error("bad assignment:" | 4720 | return bc_error_bad_assignment(); |
4693 | " left side must be variable" | ||
4694 | " or array element" | ||
4695 | ); // note: shared string | ||
4696 | } | 4721 | } |
4697 | // Fallthrough. | 4722 | // Fallthrough. |
4698 | case XC_LEX_OP_POWER: | 4723 | case XC_LEX_OP_POWER: |
@@ -4710,64 +4735,63 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags) | |||
4710 | case BC_LEX_OP_BOOL_OR: | 4735 | case BC_LEX_OP_BOOL_OR: |
4711 | case BC_LEX_OP_BOOL_AND: | 4736 | case BC_LEX_OP_BOOL_AND: |
4712 | dbg_lex("%s:%d LEX_OP_xyz", __func__, __LINE__); | 4737 | dbg_lex("%s:%d LEX_OP_xyz", __func__, __LINE__); |
4713 | if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) | 4738 | if (t == BC_LEX_OP_BOOL_NOT) { |
4714 | || (t != BC_LEX_OP_BOOL_NOT && prev == XC_INST_BOOL_NOT) | 4739 | if (!bin_last && p->lex_last != BC_LEX_OP_BOOL_NOT) |
4715 | ) { | 4740 | return bc_error_bad_expression(); |
4741 | } else if (prev == XC_INST_BOOL_NOT) { | ||
4716 | return bc_error_bad_expression(); | 4742 | return bc_error_bad_expression(); |
4717 | } | 4743 | } |
4744 | |||
4718 | nrelops += (t >= XC_LEX_OP_REL_EQ && t <= XC_LEX_OP_REL_GT); | 4745 | nrelops += (t >= XC_LEX_OP_REL_EQ && t <= XC_LEX_OP_REL_GT); |
4719 | prev = BC_TOKEN_2_INST(t); | 4746 | prev = BC_TOKEN_2_INST(t); |
4720 | bc_parse_operator(t, ops_bgn, &nexprs); | 4747 | bc_parse_operator(t, ops_bgn, &nexprs); |
4721 | s = zxc_lex_next(); | 4748 | rprn = incdec = false; |
4722 | rprn = false; | 4749 | get_token = true; |
4723 | //get_token = false; - already is | ||
4724 | bin_last = (t != BC_LEX_OP_BOOL_NOT); | 4750 | bin_last = (t != BC_LEX_OP_BOOL_NOT); |
4725 | break; | 4751 | break; |
4726 | case BC_LEX_LPAREN: | 4752 | case BC_LEX_LPAREN: |
4727 | dbg_lex("%s:%d LEX_LPAREN", __func__, __LINE__); | 4753 | dbg_lex("%s:%d LEX_LPAREN", __func__, __LINE__); |
4728 | if (BC_PARSE_LEAF(prev, rprn)) | 4754 | if (BC_PARSE_LEAF(prev, bin_last, rprn)) |
4729 | return bc_error_bad_expression(); | 4755 | return bc_error_bad_expression(); |
4730 | bc_vec_push(&p->ops, &t); | 4756 | bc_vec_push(&p->ops, &t); |
4731 | nparens++; | 4757 | nparens++; |
4732 | get_token = true; | 4758 | get_token = true; |
4733 | paren_expr = false; | 4759 | rprn = incdec = false; |
4734 | rprn = bin_last = false; | ||
4735 | break; | 4760 | break; |
4736 | case BC_LEX_RPAREN: | 4761 | case BC_LEX_RPAREN: |
4737 | dbg_lex("%s:%d LEX_RPAREN", __func__, __LINE__); | 4762 | dbg_lex("%s:%d LEX_RPAREN", __func__, __LINE__); |
4763 | if (p->lex_last == BC_LEX_LPAREN) { | ||
4764 | dbg_lex_done("%s:%d done (returning EMPTY_EXP)", __func__, __LINE__); | ||
4765 | return BC_STATUS_PARSE_EMPTY_EXP; | ||
4766 | } | ||
4738 | if (bin_last || prev == XC_INST_BOOL_NOT) | 4767 | if (bin_last || prev == XC_INST_BOOL_NOT) |
4739 | return bc_error_bad_expression(); | 4768 | return bc_error_bad_expression(); |
4740 | if (nparens == 0) { | 4769 | if (nparens == 0) { |
4741 | goto exit_loop; | 4770 | goto exit_loop; |
4742 | } | 4771 | } |
4743 | if (!paren_expr) { | ||
4744 | dbg_lex_done("%s:%d done (returning EMPTY_EXP)", __func__, __LINE__); | ||
4745 | return BC_STATUS_PARSE_EMPTY_EXP; | ||
4746 | } | ||
4747 | s = zbc_parse_rightParen(ops_bgn, &nexprs); | 4772 | s = zbc_parse_rightParen(ops_bgn, &nexprs); |
4748 | nparens--; | 4773 | nparens--; |
4749 | get_token = true; | 4774 | get_token = true; |
4750 | paren_expr = rprn = true; | 4775 | rprn = true; |
4751 | bin_last = false; | 4776 | bin_last = incdec = false; |
4752 | break; | 4777 | break; |
4753 | case XC_LEX_NAME: | 4778 | case XC_LEX_NAME: |
4754 | dbg_lex("%s:%d LEX_NAME", __func__, __LINE__); | 4779 | dbg_lex("%s:%d LEX_NAME", __func__, __LINE__); |
4755 | if (BC_PARSE_LEAF(prev, rprn)) | 4780 | if (BC_PARSE_LEAF(prev, bin_last, rprn)) |
4756 | return bc_error_bad_expression(); | 4781 | return bc_error_bad_expression(); |
4757 | s = zbc_parse_name(&prev, flags & ~BC_PARSE_NOCALL); | 4782 | s = zbc_parse_name(&prev, flags & ~BC_PARSE_NOCALL); |
4758 | paren_expr = true; | 4783 | rprn = (prev == BC_INST_CALL); |
4759 | rprn = bin_last = false; | 4784 | bin_last = false; |
4760 | //get_token = false; - already is | 4785 | //get_token = false; - already is |
4761 | nexprs++; | 4786 | nexprs++; |
4762 | break; | 4787 | break; |
4763 | case XC_LEX_NUMBER: | 4788 | case XC_LEX_NUMBER: |
4764 | dbg_lex("%s:%d LEX_NUMBER", __func__, __LINE__); | 4789 | dbg_lex("%s:%d LEX_NUMBER", __func__, __LINE__); |
4765 | if (BC_PARSE_LEAF(prev, rprn)) | 4790 | if (BC_PARSE_LEAF(prev, bin_last, rprn)) |
4766 | return bc_error_bad_expression(); | 4791 | return bc_error_bad_expression(); |
4767 | xc_parse_pushNUM(); | 4792 | xc_parse_pushNUM(); |
4768 | prev = XC_INST_NUM; | 4793 | prev = XC_INST_NUM; |
4769 | get_token = true; | 4794 | get_token = true; |
4770 | paren_expr = true; | ||
4771 | rprn = bin_last = false; | 4795 | rprn = bin_last = false; |
4772 | nexprs++; | 4796 | nexprs++; |
4773 | break; | 4797 | break; |
@@ -4775,45 +4799,40 @@ static BcStatus bc_parse_expr_empty_ok(uint8_t flags) | |||
4775 | case BC_LEX_KEY_LAST: | 4799 | case BC_LEX_KEY_LAST: |
4776 | case BC_LEX_KEY_OBASE: | 4800 | case BC_LEX_KEY_OBASE: |
4777 | dbg_lex("%s:%d LEX_IBASE/LAST/OBASE", __func__, __LINE__); | 4801 | dbg_lex("%s:%d LEX_IBASE/LAST/OBASE", __func__, __LINE__); |
4778 | if (BC_PARSE_LEAF(prev, rprn)) | 4802 | if (BC_PARSE_LEAF(prev, bin_last, rprn)) |
4779 | return bc_error_bad_expression(); | 4803 | return bc_error_bad_expression(); |
4780 | prev = (char) (t - BC_LEX_KEY_IBASE + XC_INST_IBASE); | 4804 | prev = (char) (t - BC_LEX_KEY_IBASE + XC_INST_IBASE); |
4781 | xc_parse_push((char) prev); | 4805 | xc_parse_push((char) prev); |
4782 | get_token = true; | 4806 | get_token = true; |
4783 | paren_expr = true; | ||
4784 | rprn = bin_last = false; | 4807 | rprn = bin_last = false; |
4785 | nexprs++; | 4808 | nexprs++; |
4786 | break; | 4809 | break; |
4787 | case BC_LEX_KEY_LENGTH: | 4810 | case BC_LEX_KEY_LENGTH: |
4788 | case BC_LEX_KEY_SQRT: | 4811 | case BC_LEX_KEY_SQRT: |
4789 | dbg_lex("%s:%d LEX_LEN/SQRT", __func__, __LINE__); | 4812 | dbg_lex("%s:%d LEX_LEN/SQRT", __func__, __LINE__); |
4790 | if (BC_PARSE_LEAF(prev, rprn)) | 4813 | if (BC_PARSE_LEAF(prev, bin_last, rprn)) |
4791 | return bc_error_bad_expression(); | 4814 | return bc_error_bad_expression(); |
4792 | s = zbc_parse_builtin(t, flags, &prev); | 4815 | s = zbc_parse_builtin(t, flags, &prev); |
4793 | get_token = true; | 4816 | get_token = true; |
4794 | paren_expr = true; | 4817 | rprn = bin_last = incdec = false; |
4795 | rprn = bin_last = false; | ||
4796 | nexprs++; | 4818 | nexprs++; |
4797 | break; | 4819 | break; |
4798 | case BC_LEX_KEY_READ: | 4820 | case BC_LEX_KEY_READ: |
4799 | dbg_lex("%s:%d LEX_READ", __func__, __LINE__); | 4821 | dbg_lex("%s:%d LEX_READ", __func__, __LINE__); |
4800 | if (BC_PARSE_LEAF(prev, rprn)) | 4822 | if (BC_PARSE_LEAF(prev, bin_last, rprn)) |
4801 | return bc_error_bad_expression(); | 4823 | return bc_error_bad_expression(); |
4802 | s = zbc_parse_read(); | 4824 | s = zbc_parse_read(); |
4803 | prev = XC_INST_READ; | 4825 | prev = XC_INST_READ; |
4804 | get_token = true; | 4826 | get_token = true; |
4805 | paren_expr = true; | 4827 | rprn = bin_last = incdec = false; |
4806 | rprn = bin_last = false; | ||
4807 | nexprs++; | 4828 | nexprs++; |
4808 | break; | 4829 | break; |
4809 | case BC_LEX_KEY_SCALE: | 4830 | case BC_LEX_KEY_SCALE: |
4810 | dbg_lex("%s:%d LEX_SCALE", __func__, __LINE__); | 4831 | dbg_lex("%s:%d LEX_SCALE", __func__, __LINE__); |
4811 | if (BC_PARSE_LEAF(prev, rprn)) | 4832 | if (BC_PARSE_LEAF(prev, bin_last, rprn)) |
4812 | return bc_error_bad_expression(); | 4833 | return bc_error_bad_expression(); |
4813 | s = zbc_parse_scale(&prev, flags); | 4834 | s = zbc_parse_scale(&prev, flags); |
4814 | prev = XC_INST_SCALE; | ||
4815 | //get_token = false; - already is | 4835 | //get_token = false; - already is |
4816 | paren_expr = true; | ||
4817 | rprn = bin_last = false; | 4836 | rprn = bin_last = false; |
4818 | nexprs++; | 4837 | nexprs++; |
4819 | break; | 4838 | break; |
@@ -5286,7 +5305,7 @@ static BC_STATUS zxc_program_read(void) | |||
5286 | } | 5305 | } |
5287 | if (s) goto exec_err; | 5306 | if (s) goto exec_err; |
5288 | if (G.prs.lex != XC_LEX_NLINE && G.prs.lex != XC_LEX_EOF) { | 5307 | if (G.prs.lex != XC_LEX_NLINE && G.prs.lex != XC_LEX_EOF) { |
5289 | s = bc_error("bad read() expression"); | 5308 | s = bc_error_at("bad read() expression"); |
5290 | goto exec_err; | 5309 | goto exec_err; |
5291 | } | 5310 | } |
5292 | xc_parse_push(XC_INST_RET); | 5311 | xc_parse_push(XC_INST_RET); |
@@ -5794,10 +5813,7 @@ static BC_STATUS zxc_program_assign(char inst) | |||
5794 | #endif | 5813 | #endif |
5795 | 5814 | ||
5796 | if (left->t == XC_RESULT_CONSTANT || left->t == XC_RESULT_TEMP) | 5815 | if (left->t == XC_RESULT_CONSTANT || left->t == XC_RESULT_TEMP) |
5797 | RETURN_STATUS(bc_error("bad assignment:" | 5816 | RETURN_STATUS(bc_error_bad_assignment()); |
5798 | " left side must be variable" | ||
5799 | " or array element" | ||
5800 | )); // note: shared string | ||
5801 | 5817 | ||
5802 | #if ENABLE_BC | 5818 | #if ENABLE_BC |
5803 | if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero)) | 5819 | if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero)) |
@@ -6771,13 +6787,7 @@ static BC_STATUS zxc_vm_process(const char *text) | |||
6771 | && G.prs.lex != XC_LEX_NLINE | 6787 | && G.prs.lex != XC_LEX_NLINE |
6772 | && G.prs.lex != XC_LEX_EOF | 6788 | && G.prs.lex != XC_LEX_EOF |
6773 | ) { | 6789 | ) { |
6774 | const char *err_at; | 6790 | bc_error_at("bad statement terminator"); |
6775 | //TODO: commonalize for other parse errors: | ||
6776 | err_at = G.prs.lex_next_at ? G.prs.lex_next_at : "UNKNOWN"; | ||
6777 | bc_error_fmt("bad statement terminator at '%.*s'", | ||
6778 | (int)(strchrnul(err_at, '\n') - err_at), | ||
6779 | err_at | ||
6780 | ); | ||
6781 | goto err; | 6791 | goto err; |
6782 | } | 6792 | } |
6783 | // The above logic is fragile. Check these examples: | 6793 | // The above logic is fragile. Check these examples: |
@@ -6871,6 +6881,7 @@ static BC_STATUS zxc_vm_execute_FILE(FILE *fp, const char *filename) | |||
6871 | G.prs.lex_filename = filename; | 6881 | G.prs.lex_filename = filename; |
6872 | G.prs.lex_input_fp = fp; | 6882 | G.prs.lex_input_fp = fp; |
6873 | G.err_line = G.prs.lex_line = 1; | 6883 | G.err_line = G.prs.lex_line = 1; |
6884 | dbg_lex("p->lex_line reset to 1"); | ||
6874 | 6885 | ||
6875 | do { | 6886 | do { |
6876 | s = zxc_vm_process(""); | 6887 | s = zxc_vm_process(""); |
diff --git a/testsuite/bc.tests b/testsuite/bc.tests index 1d4545559..13525ea52 100755 --- a/testsuite/bc.tests +++ b/testsuite/bc.tests | |||
@@ -108,6 +108,11 @@ testing "bc define auto" \ | |||
108 | "8\n9\n" \ | 108 | "8\n9\n" \ |
109 | "" "define w() { auto z; return 8; }; w(); 9" | 109 | "" "define w() { auto z; return 8; }; w(); 9" |
110 | 110 | ||
111 | testing "bc define auto array same name" \ | ||
112 | "bc" \ | ||
113 | "8\n9\n" \ | ||
114 | "" "define w(x) { auto x[]; return x; }; w(8); 9" | ||
115 | |||
111 | testing "bc define with body on next line" \ | 116 | testing "bc define with body on next line" \ |
112 | "bc" \ | 117 | "bc" \ |
113 | "8\n9\n" \ | 118 | "8\n9\n" \ |
@@ -133,6 +138,17 @@ testing "bc ifz does not match if keyword" \ | |||
133 | "1\n2\n2\n3\n" \ | 138 | "1\n2\n2\n3\n" \ |
134 | "" "ifz=1;ifz\n++ifz;ifz++\nifz" | 139 | "" "ifz=1;ifz\n++ifz;ifz++\nifz" |
135 | 140 | ||
141 | # had parse error on "f()-N" | ||
142 | testing "bc -l 'e(0)-2'" \ | ||
143 | "bc -l" \ | ||
144 | "-1.00000000000000000000\n" \ | ||
145 | "" "e(0)-2" | ||
146 | |||
147 | testing "bc (!a&&b)" \ | ||
148 | "bc" \ | ||
149 | "0\n" \ | ||
150 | "" "(!a&&b)" | ||
151 | |||
136 | testing "bc print 1,2,3" \ | 152 | testing "bc print 1,2,3" \ |
137 | "bc" \ | 153 | "bc" \ |
138 | "123" \ | 154 | "123" \ |