aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--miscutils/bc.c108
1 files changed, 51 insertions, 57 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c
index 56a2bca71..9f23a0601 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -3556,6 +3556,18 @@ static void bc_parse_pushIndex(BcParse *p, size_t idx)
3556 } 3556 }
3557} 3557}
3558 3558
3559static void bc_parse_pushJUMP(BcParse *p, size_t idx)
3560{
3561 bc_parse_push(p, BC_INST_JUMP);
3562 bc_parse_pushIndex(p, idx);
3563}
3564
3565static void bc_parse_pushJUMP_ZERO(BcParse *p, size_t idx)
3566{
3567 bc_parse_push(p, BC_INST_JUMP_ZERO);
3568 bc_parse_pushIndex(p, idx);
3569}
3570
3559static void bc_parse_number(BcParse *p) 3571static void bc_parse_number(BcParse *p)
3560{ 3572{
3561 char *num = xstrdup(p->l.t.v.v); 3573 char *num = xstrdup(p->l.t.v.v);
@@ -3677,14 +3689,19 @@ static BC_STATUS zbc_parse_stmt(BcParse *p)
3677# define zbc_parse_stmt(...) (zbc_parse_stmt(__VA_ARGS__), BC_STATUS_SUCCESS) 3689# define zbc_parse_stmt(...) (zbc_parse_stmt(__VA_ARGS__), BC_STATUS_SUCCESS)
3678#endif 3690#endif
3679 3691
3680static BC_STATUS zbc_parse_stmt_fail_if_bare_NLINE(BcParse *p, bool auto_allowed, const char *after_X) 3692static BC_STATUS zbc_parse_stmt_allow_NLINE_before(BcParse *p, const char *after_X)
3681{ 3693{
3694 // "if(cond)<newline>stmt" is accepted too, but not 2+ newlines.
3695 // Same for "else", "while()", "for()".
3696 BcStatus s = zbc_lex_next_and_skip_NLINE(&p->l);
3697 if (s) RETURN_STATUS(s);
3682 if (p->l.t.t == BC_LEX_NLINE) 3698 if (p->l.t.t == BC_LEX_NLINE)
3683 RETURN_STATUS(bc_error_fmt("no statement after '%s'", after_X)); 3699 RETURN_STATUS(bc_error_fmt("no statement after '%s'", after_X));
3684 RETURN_STATUS(zbc_parse_stmt_possibly_auto(p, auto_allowed)); 3700
3701 RETURN_STATUS(zbc_parse_stmt(p));
3685} 3702}
3686#if ERRORS_ARE_FATAL 3703#if ERRORS_ARE_FATAL
3687# define zbc_parse_stmt_fail_if_bare_NLINE(...) (zbc_parse_stmt_fail_if_bare_NLINE(__VA_ARGS__), BC_STATUS_SUCCESS) 3704# define zbc_parse_stmt_allow_NLINE_before(...) (zbc_parse_stmt_allow_NLINE_before(__VA_ARGS__), BC_STATUS_SUCCESS)
3688#endif 3705#endif
3689 3706
3690static void bc_parse_operator(BcParse *p, BcLexType type, size_t start, 3707static void bc_parse_operator(BcParse *p, BcLexType type, size_t start,
@@ -4106,11 +4123,16 @@ static BC_STATUS zbc_parse_return(BcParse *p)
4106# define zbc_parse_return(...) (zbc_parse_return(__VA_ARGS__), BC_STATUS_SUCCESS) 4123# define zbc_parse_return(...) (zbc_parse_return(__VA_ARGS__), BC_STATUS_SUCCESS)
4107#endif 4124#endif
4108 4125
4126static void rewrite_label_to_current(BcParse *p, size_t idx)
4127{
4128 size_t *label = bc_vec_item(&p->func->labels, idx);
4129 *label = p->func->code.len;
4130}
4131
4109static BC_STATUS zbc_parse_if(BcParse *p) 4132static BC_STATUS zbc_parse_if(BcParse *p)
4110{ 4133{
4111 BcStatus s; 4134 BcStatus s;
4112 size_t ip_idx; 4135 size_t ip_idx;
4113 size_t *label;
4114 4136
4115 dbg_lex_enter("%s:%d entered", __func__, __LINE__); 4137 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
4116 s = zbc_lex_next(&p->l); 4138 s = zbc_lex_next(&p->l);
@@ -4123,45 +4145,35 @@ static BC_STATUS zbc_parse_if(BcParse *p)
4123 if (s) RETURN_STATUS(s); 4145 if (s) RETURN_STATUS(s);
4124 4146
4125 if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); 4147 if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
4126 // if(cond)<newline>stmt is accepted too (but not 2+ newlines)
4127 s = zbc_lex_next_and_skip_NLINE(&p->l);
4128 if (s) RETURN_STATUS(s);
4129 4148
4130 bc_parse_push(p, BC_INST_JUMP_ZERO);
4131 ip_idx = p->func->labels.len; 4149 ip_idx = p->func->labels.len;
4132 bc_parse_pushIndex(p, ip_idx); 4150 bc_parse_pushJUMP_ZERO(p, ip_idx);
4133 bc_vec_push(&p->func->labels, &ip_idx); 4151 bc_vec_push(&p->func->labels, &ip_idx);
4134 4152
4135 s = zbc_parse_stmt_fail_if_bare_NLINE(p, false, "if"); 4153 s = zbc_parse_stmt_allow_NLINE_before(p, "if");
4136 if (s) RETURN_STATUS(s); 4154 if (s) RETURN_STATUS(s);
4137 4155
4138 dbg_lex("%s:%d in if after stmt: p->l.t.t:%d", __func__, __LINE__, p->l.t.t); 4156 dbg_lex("%s:%d in if after stmt: p->l.t.t:%d", __func__, __LINE__, p->l.t.t);
4139 if (p->l.t.t == BC_LEX_KEY_ELSE) { 4157 if (p->l.t.t == BC_LEX_KEY_ELSE) {
4140 size_t ip2_idx; 4158 size_t ip2_idx;
4141 4159
4142 s = zbc_lex_next_and_skip_NLINE(&p->l);
4143 if (s) RETURN_STATUS(s);
4144
4145 ip2_idx = p->func->labels.len; 4160 ip2_idx = p->func->labels.len;
4146 4161
4147 dbg_lex("%s:%d after if() body: BC_INST_JUMP to %d", __func__, __LINE__, ip2_idx); 4162 dbg_lex("%s:%d after if() body: BC_INST_JUMP to %d", __func__, __LINE__, ip2_idx);
4148 bc_parse_push(p, BC_INST_JUMP); 4163 bc_parse_pushJUMP(p, ip2_idx);
4149 bc_parse_pushIndex(p, ip2_idx);
4150 4164
4151 label = bc_vec_item(&p->func->labels, ip_idx); 4165 dbg_lex("%s:%d rewriting 'if_zero' label to jump to 'else'-> %d", __func__, __LINE__, p->func->code.len);
4152 dbg_lex("%s:%d rewriting 'if_zero' label to jump to 'else': %d -> %d", __func__, __LINE__, *label, p->func->code.len); 4166 rewrite_label_to_current(p, ip_idx);
4153 *label = p->func->code.len;
4154 4167
4155 bc_vec_push(&p->func->labels, &ip2_idx); 4168 bc_vec_push(&p->func->labels, &ip2_idx);
4156 ip_idx = ip2_idx; 4169 ip_idx = ip2_idx;
4157 4170
4158 s = zbc_parse_stmt_fail_if_bare_NLINE(p, false, "else"); 4171 s = zbc_parse_stmt_allow_NLINE_before(p, "else");
4159 if (s) RETURN_STATUS(s); 4172 if (s) RETURN_STATUS(s);
4160 } 4173 }
4161 4174
4162 label = bc_vec_item(&p->func->labels, ip_idx); 4175 dbg_lex("%s:%d rewriting label to jump after 'if' body-> %d", __func__, __LINE__, p->func->code.len);
4163 dbg_lex("%s:%d rewriting label to jump after 'if' body: %d -> %d", __func__, __LINE__, *label, p->func->code.len); 4176 rewrite_label_to_current(p, ip_idx);
4164 *label = p->func->code.len;
4165 4177
4166 dbg_lex_done("%s:%d done", __func__, __LINE__); 4178 dbg_lex_done("%s:%d done", __func__, __LINE__);
4167 RETURN_STATUS(s); 4179 RETURN_STATUS(s);
@@ -4173,7 +4185,6 @@ static BC_STATUS zbc_parse_if(BcParse *p)
4173static BC_STATUS zbc_parse_while(BcParse *p) 4185static BC_STATUS zbc_parse_while(BcParse *p)
4174{ 4186{
4175 BcStatus s; 4187 BcStatus s;
4176 size_t *label;
4177 size_t cond_idx; 4188 size_t cond_idx;
4178 size_t ip_idx; 4189 size_t ip_idx;
4179 4190
@@ -4196,23 +4207,16 @@ static BC_STATUS zbc_parse_while(BcParse *p)
4196 if (s) RETURN_STATUS(s); 4207 if (s) RETURN_STATUS(s);
4197 if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); 4208 if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
4198 4209
4199 // while(cond)<newline>stmt is accepted too 4210 bc_parse_pushJUMP_ZERO(p, ip_idx);
4200 s = zbc_lex_next_and_skip_NLINE(&p->l);
4201 if (s) RETURN_STATUS(s);
4202 4211
4203 bc_parse_push(p, BC_INST_JUMP_ZERO); 4212 s = zbc_parse_stmt_allow_NLINE_before(p, "while");
4204 bc_parse_pushIndex(p, ip_idx);
4205
4206 s = zbc_parse_stmt_fail_if_bare_NLINE(p, false, "while");
4207 if (s) RETURN_STATUS(s); 4213 if (s) RETURN_STATUS(s);
4208 4214
4209 dbg_lex("%s:%d BC_INST_JUMP to %d", __func__, __LINE__, cond_idx); 4215 dbg_lex("%s:%d BC_INST_JUMP to %d", __func__, __LINE__, cond_idx);
4210 bc_parse_push(p, BC_INST_JUMP); 4216 bc_parse_pushJUMP(p, cond_idx);
4211 bc_parse_pushIndex(p, cond_idx);
4212 4217
4213 label = bc_vec_item(&p->func->labels, ip_idx); 4218 dbg_lex("%s:%d rewriting label-> %d", __func__, __LINE__, p->func->code.len);
4214 dbg_lex("%s:%d rewriting label: %d -> %d", __func__, __LINE__, *label, p->func->code.len); 4219 rewrite_label_to_current(p, ip_idx);
4215 *label = p->func->code.len;
4216 4220
4217 bc_vec_pop(&p->exits); 4221 bc_vec_pop(&p->exits);
4218 bc_vec_pop(&p->conds); 4222 bc_vec_pop(&p->conds);
@@ -4226,7 +4230,6 @@ static BC_STATUS zbc_parse_while(BcParse *p)
4226static BC_STATUS zbc_parse_for(BcParse *p) 4230static BC_STATUS zbc_parse_for(BcParse *p)
4227{ 4231{
4228 BcStatus s; 4232 BcStatus s;
4229 size_t *label;
4230 size_t cond_idx, exit_idx, body_idx, update_idx; 4233 size_t cond_idx, exit_idx, body_idx, update_idx;
4231 4234
4232 dbg_lex("%s:%d p->l.t.t:%d", __func__, __LINE__, p->l.t.t); 4235 dbg_lex("%s:%d p->l.t.t:%d", __func__, __LINE__, p->l.t.t);
@@ -4264,10 +4267,8 @@ static BC_STATUS zbc_parse_for(BcParse *p)
4264 s = zbc_lex_next(&p->l); 4267 s = zbc_lex_next(&p->l);
4265 if (s) RETURN_STATUS(s); 4268 if (s) RETURN_STATUS(s);
4266 4269
4267 bc_parse_push(p, BC_INST_JUMP_ZERO); 4270 bc_parse_pushJUMP_ZERO(p, exit_idx);
4268 bc_parse_pushIndex(p, exit_idx); 4271 bc_parse_pushJUMP(p, body_idx);
4269 bc_parse_push(p, BC_INST_JUMP);
4270 bc_parse_pushIndex(p, body_idx);
4271 4272
4272 bc_vec_push(&p->conds, &update_idx); 4273 bc_vec_push(&p->conds, &update_idx);
4273 bc_vec_push(&p->func->labels, &p->func->code.len); 4274 bc_vec_push(&p->func->labels, &p->func->code.len);
@@ -4280,28 +4281,20 @@ static BC_STATUS zbc_parse_for(BcParse *p)
4280 if (s) RETURN_STATUS(s); 4281 if (s) RETURN_STATUS(s);
4281 4282
4282 if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); 4283 if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
4283 bc_parse_push(p, BC_INST_JUMP); 4284 bc_parse_pushJUMP(p, cond_idx);
4284 bc_parse_pushIndex(p, cond_idx);
4285 bc_vec_push(&p->func->labels, &p->func->code.len); 4285 bc_vec_push(&p->func->labels, &p->func->code.len);
4286 4286
4287 bc_vec_push(&p->exits, &exit_idx); 4287 bc_vec_push(&p->exits, &exit_idx);
4288 bc_vec_push(&p->func->labels, &exit_idx); 4288 bc_vec_push(&p->func->labels, &exit_idx);
4289 4289
4290 // for(...)<newline>stmt is accepted as well 4290 s = zbc_parse_stmt_allow_NLINE_before(p, "for");
4291 s = zbc_lex_next_and_skip_NLINE(&p->l);
4292 if (s) RETURN_STATUS(s);
4293
4294 s = zbc_parse_stmt_fail_if_bare_NLINE(p, false, "for");
4295 if (s) RETURN_STATUS(s); 4291 if (s) RETURN_STATUS(s);
4296 4292
4297//TODO: commonalize?
4298 dbg_lex("%s:%d BC_INST_JUMP to %d", __func__, __LINE__, update_idx); 4293 dbg_lex("%s:%d BC_INST_JUMP to %d", __func__, __LINE__, update_idx);
4299 bc_parse_push(p, BC_INST_JUMP); 4294 bc_parse_pushJUMP(p, update_idx);
4300 bc_parse_pushIndex(p, update_idx);
4301 4295
4302 label = bc_vec_item(&p->func->labels, exit_idx); 4296 dbg_lex("%s:%d rewriting label-> %d", __func__, __LINE__, p->func->code.len);
4303 dbg_lex("%s:%d rewriting label: %d -> %d", __func__, __LINE__, *label, p->func->code.len); 4297 rewrite_label_to_current(p, exit_idx);
4304 *label = p->func->code.len;
4305 4298
4306 bc_vec_pop(&p->exits); 4299 bc_vec_pop(&p->exits);
4307 bc_vec_pop(&p->conds); 4300 bc_vec_pop(&p->conds);
@@ -4325,8 +4318,7 @@ static BC_STATUS zbc_parse_break_or_continue(BcParse *p, BcLexType type)
4325 i = *(size_t*)bc_vec_top(&p->conds); 4318 i = *(size_t*)bc_vec_top(&p->conds);
4326 } 4319 }
4327 4320
4328 bc_parse_push(p, BC_INST_JUMP); 4321 bc_parse_pushJUMP(p, i);
4329 bc_parse_pushIndex(p, i);
4330 4322
4331 s = zbc_lex_next(&p->l); 4323 s = zbc_lex_next(&p->l);
4332 if (s) RETURN_STATUS(s); 4324 if (s) RETURN_STATUS(s);
@@ -4407,10 +4399,12 @@ static BC_STATUS zbc_parse_funcdef(BcParse *p)
4407 // Prevent "define z()<newline>" from being interpreted as function with empty stmt as body 4399 // Prevent "define z()<newline>" from being interpreted as function with empty stmt as body
4408 s = zbc_lex_skip_if_at_NLINE(&p->l); 4400 s = zbc_lex_skip_if_at_NLINE(&p->l);
4409 if (s) RETURN_STATUS(s); 4401 if (s) RETURN_STATUS(s);
4410//TODO: GNU bc requires a {} block even if function body has single stmt, enforce this? 4402 //GNU bc requires a {} block even if function body has single stmt, enforce this?
4403 if (p->l.t.t != BC_LEX_LBRACE)
4404 RETURN_STATUS(bc_error("function { body } expected"));
4411 4405
4412 p->in_funcdef++; // to determine whether "return" stmt is allowed, and such 4406 p->in_funcdef++; // to determine whether "return" stmt is allowed, and such
4413 s = zbc_parse_stmt_fail_if_bare_NLINE(p, true, "define"); 4407 s = zbc_parse_stmt_possibly_auto(p, true);
4414 p->in_funcdef--; 4408 p->in_funcdef--;
4415 if (s) RETURN_STATUS(s); 4409 if (s) RETURN_STATUS(s);
4416 4410