aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--miscutils/bc.c177
-rwxr-xr-xtestsuite/bc.tests16
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}
974static 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}
974static ERRORFUNC int bc_error_bad_character(char c) 987static 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}
993static ERRORFUNC int bc_error_bad_function_definition(void)
994{
995 IF_ERROR_RETURN_POSSIBLE(return) bc_error_at("bad function definition");
996}
980static ERRORFUNC int bc_error_bad_expression(void) 997static 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}
1001static 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}
984static ERRORFUNC int bc_error_bad_token(void) 1007static 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}
988static ERRORFUNC int bc_error_stack_has_too_few_elements(void) 1011static 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
3963static BC_STATUS zbc_parse_incdec(BcInst *prev, bool *paren_expr, 3996static 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 4052static 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
4029static 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
4039static BC_STATUS zbc_parse_minus(BcInst *prev, size_t ops_bgn, 4062static 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
111testing "bc define auto array same name" \
112 "bc" \
113 "8\n9\n" \
114 "" "define w(x) { auto x[]; return x; }; w(8); 9"
115
111testing "bc define with body on next line" \ 116testing "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"
142testing "bc -l 'e(0)-2'" \
143 "bc -l" \
144 "-1.00000000000000000000\n" \
145 "" "e(0)-2"
146
147testing "bc (!a&&b)" \
148 "bc" \
149 "0\n" \
150 "" "(!a&&b)"
151
136testing "bc print 1,2,3" \ 152testing "bc print 1,2,3" \
137 "bc" \ 153 "bc" \
138 "123" \ 154 "123" \