aboutsummaryrefslogtreecommitdiffstats
path: root/awkgram.y
diff options
context:
space:
mode:
Diffstat (limited to 'awkgram.y')
-rw-r--r--awkgram.y506
1 files changed, 239 insertions, 267 deletions
diff --git a/awkgram.y b/awkgram.y
index aae04a70..4fe2fb76 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -65,11 +65,11 @@ static INSTRUCTION *mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, INSTRUCTIO
static INSTRUCTION *mk_expression_list(INSTRUCTION *list, INSTRUCTION *s1);
static INSTRUCTION *mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond,
INSTRUCTION *incr, INSTRUCTION *body);
-static void fix_break_continue(INSTRUCTION *start, INSTRUCTION *end, int check_continue);
+static void fix_break_continue(INSTRUCTION *list, INSTRUCTION *b_target, INSTRUCTION *c_target);
static INSTRUCTION *mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op);
static INSTRUCTION *mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op);
static INSTRUCTION *mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op);
-static INSTRUCTION *mk_getline(INSTRUCTION *op, INSTRUCTION *opt_var, INSTRUCTION *redir, OPCODE redirtype);
+static INSTRUCTION *mk_getline(INSTRUCTION *op, INSTRUCTION *opt_var, INSTRUCTION *redir, int redirtype);
static NODE *make_regnode(int type, NODE *exp);
static int count_expressions(INSTRUCTION **list, int isarg);
static INSTRUCTION *optimize_assignment(INSTRUCTION *exp);
@@ -485,115 +485,182 @@ statement
else
$$ = $1;
}
- | LEX_SWITCH '(' exp r_paren opt_nls l_brace switch_body opt_nls r_brace
+ | LEX_SWITCH '(' exp r_paren opt_nls l_brace case_statements opt_nls r_brace
{
- INSTRUCTION *ip;
+ INSTRUCTION *dflt, *curr = NULL, *cexp, *cstmt;
+ INSTRUCTION *ip, *nextc, *tbreak;
+ const char **case_values = NULL;
+ int maxcount = 128;
+ int case_count = 0;
+ int i;
+
+ tbreak = instruction(Op_no_op);
+ cstmt = list_create(tbreak);
+ cexp = list_create(instruction(Op_pop));
+ dflt = instruction(Op_jmp);
+ dflt->target_jmp = tbreak; /* if no case match and no explicit default */
+
+ if ($7 != NULL) {
+ curr = $7->nexti;
+ bcfree($7); /* Op_list */
+ } /* else
+ curr = NULL; */
+
+ for(; curr != NULL; curr = nextc) {
+ INSTRUCTION *caseexp = curr->case_exp;
+ INSTRUCTION *casestmt = curr->case_stmt;
+
+ nextc = curr->nexti;
+ if (curr->opcode == Op_K_case) {
+ if (caseexp->opcode == Op_push_i) {
+ /* a constant scalar */
+ char *caseval;
+ caseval = force_string(caseexp->memory)->stptr;
+ for (i = 0; i < case_count; i++) {
+ if (strcmp(caseval, case_values[i]) == 0) {
+ /* can't use yyerror, since may have overshot the source line */
+ errcount++;
+ error(_("duplicate case values in switch body: %s"), caseval);
+ }
+ }
+
+ if (case_values == NULL)
+ emalloc(case_values, const char **, sizeof(char *) * maxcount, "statement");
+ else if (case_count >= maxcount) {
+ maxcount += 128;
+ erealloc(case_values, const char **, sizeof(char*) * maxcount, "statement");
+ }
+ case_values[case_count++] = caseval;
+ } else {
+ /* match a constant regex against switch expression. */
+ (curr + 1)->match_exp = TRUE;
+ }
+ curr->stmt_start = casestmt->nexti;
+ curr->stmt_end = casestmt->lasti;
+ (void) list_prepend(cexp, curr);
+ (void) list_prepend(cexp, caseexp);
+ } else {
+ if (dflt->target_jmp != tbreak) {
+ /* can't use yyerror, since may have overshot the source line */
+ errcount++;
+ error(_("duplicate `default' detected in switch body"));
+ } else
+ dflt->target_jmp = casestmt->nexti;
+
+ if (do_profiling) {
+ curr->stmt_start = casestmt->nexti;
+ curr->stmt_end = casestmt->lasti;
+ (void) list_prepend(cexp, curr);
+ } else
+ bcfree(curr);
+ }
+
+ cstmt = list_merge(casestmt, cstmt);
+ }
+
+ if (case_values != NULL)
+ efree(case_values);
- $1->opcode = Op_push_loop;
- $1->target_continue = NULL;
- ip = list_prepend($3, $1);
- if ($7->nexti->switch_dflt == NULL)
- $7->nexti->switch_dflt = $1; /* implicit break */
+ ip = $3;
if (do_profiling) {
+ (void) list_prepend(ip, $1);
(void) list_prepend(ip, instruction(Op_exec_count));
- ($1 + 1)->opcode = Op_K_switch;
- ($1 + 1)->switch_body = $7->nexti;
- }
- (void) list_merge(ip, $7);
- $$ = list_append(ip, instruction(Op_pop_loop));
- $1->target_break = $$->lasti;
+ $1->target_break = tbreak;
+ ($1 + 1)->switch_start = cexp->nexti;
+ ($1 + 1)->switch_end = cexp->lasti;
+ }/* else
+ $1 is NULL */
+
+ (void) list_append(cexp, dflt);
+ (void) list_merge(ip, cexp);
+ $$ = list_merge(ip, cstmt);
break_allowed--;
- fix_break_continue($1, $$->lasti, FALSE);
+ fix_break_continue(ip, tbreak, NULL);
}
| LEX_WHILE '(' exp r_paren opt_nls statement
{
- /*
- * [Op_push_loop| z| y]
- * -----------------
- * z:
- * cond
- * -----------------
- * [Op_jmp_false y ]
- * -----------------
- * body
- * -----------------
- * [Op_jmp z ]
- * y: [Op_pop_loop ]
- */
-
- INSTRUCTION *ip, *tp;
+ /*
+ * -----------------
+ * tc:
+ * cond
+ * -----------------
+ * [Op_jmp_false tb ]
+ * -----------------
+ * body
+ * -----------------
+ * [Op_jmp tc ]
+ * tb:[Op_no_op ]
+ */
- tp = instruction(Op_pop_loop);
+ INSTRUCTION *ip, *tbreak, *tcont;
+ tbreak = instruction(Op_no_op);
add_lint($3, LINT_assign_in_cond);
- $1->opcode = Op_push_loop;
- $1->target_continue = $3->nexti;
- $1->target_break = tp;
- ip = list_create($1);
-
- (void) list_merge(ip, $3);
- (void) list_append(ip, instruction(Op_jmp_false));
- ip->lasti->target_jmp = tp;
+ tcont = $3->nexti;
+ ip = list_append($3, instruction(Op_jmp_false));
+ ip->lasti->target_jmp = tbreak;
if (do_profiling) {
(void) list_append(ip, instruction(Op_exec_count));
- ($1 + 1)->opcode = Op_K_while;
+ $1->target_break = tbreak;
+ $1->target_continue = tcont;
($1 + 1)->while_body = ip->lasti;
- }
+ (void) list_prepend(ip, $1);
+ }/* else
+ $1 is NULL */
if ($6 != NULL)
(void) list_merge(ip, $6);
(void) list_append(ip, instruction(Op_jmp));
- ip->lasti->target_jmp = $1->target_continue;
- $$ = list_append(ip, tp);
+ ip->lasti->target_jmp = tcont;
+ $$ = list_append(ip, tbreak);
break_allowed--;
continue_allowed--;
- fix_break_continue($1, tp, TRUE);
+ fix_break_continue(ip, tbreak, tcont);
}
| LEX_DO opt_nls statement LEX_WHILE '(' exp r_paren opt_nls
{
- /*
- * [Op_push_loop | x | y]
- * -----------------
- * z:
- * body
- * -----------------
- * x:
- * cond
- * -----------------
- * [Op_jmp_true | z ]
- * y: [Op_pop_loop ]
- */
-
- INSTRUCTION *ip;
+ /*
+ * -----------------
+ * z:
+ * body
+ * -----------------
+ * tc:
+ * cond
+ * -----------------
+ * [Op_jmp_true | z ]
+ * tb:[Op_no_op ]
+ */
- $4->opcode = Op_pop_loop;
- $1->opcode = Op_push_loop;
- $1->target_continue = $6->nexti;
- $1->target_break = $4;
+ INSTRUCTION *ip, *tbreak, *tcont;
+ tbreak = instruction(Op_no_op);
+ tcont = $6->nexti;
add_lint($6, LINT_assign_in_cond);
if ($3 != NULL)
ip = list_merge($3, $6);
else
ip = list_prepend($6, instruction(Op_no_op));
-
- if (do_profiling) {
+ if (do_profiling)
(void) list_prepend(ip, instruction(Op_exec_count));
- ($1 + 1)->opcode = Op_K_do;
- ($1 + 1)->doloop_cond = $1->target_continue;
- }
-
(void) list_append(ip, instruction(Op_jmp_true));
ip->lasti->target_jmp = ip->nexti;
- $$ = list_prepend(ip, $1);
- (void) list_append(ip, $4);
+ $$ = list_append(ip, tbreak);
break_allowed--;
continue_allowed--;
- fix_break_continue($1, $4, TRUE);
+ fix_break_continue(ip, tbreak, tcont);
+
+ if (do_profiling) {
+ $1->target_break = tbreak;
+ $1->target_continue = tcont;
+ ($1 + 1)->doloop_cond = tcont;
+ $$ = list_prepend(ip, $1);
+ bcfree($4);
+ } /* else
+ $1 and $4 are NULLs */
}
| LEX_FOR '(' NAME LEX_IN simple_variable r_paren opt_nls statement
{
@@ -634,7 +701,8 @@ statement
(void) make_assignable($8->nexti);
$8->lasti->opcode = Op_K_delete_loop;
$8->lasti->expr_count = 0;
- bcfree($1);
+ if ($1 != NULL)
+ bcfree($1);
efree(var_name);
bcfree($3);
bcfree($4);
@@ -643,31 +711,38 @@ statement
} else
goto regular_loop;
} else {
+ INSTRUCTION *tbreak, *tcont;
- /* [ Op_push_array a ]
- * [ Op_arrayfor_init| w ]
- * [ Op_push_loop | z | y ]
- * z: [ Op_arrayfor_incr | y ]
- * [ Op_var_assign if any ]
+ /* [ Op_push_array a ]
+ * [ Op_arrayfor_init | ib ]
+ * ic:[ Op_arrayfor_incr | ib ]
+ * [ Op_var_assign if any ]
*
* body
*
- * [Op_jmp | z ]
- * y: [Op_pop_loop ]
- * w: [Op_arrayfor_final ]
+ * [Op_jmp | ic ]
+ * ib:[Op_arrayfor_final ]
*/
regular_loop:
ip = $5;
ip->nexti->opcode = Op_push_array;
- $3->opcode = Op_arrayfor_init;
- (void) list_append(ip, $3);
+ tbreak = instruction(Op_arrayfor_final);
$4->opcode = Op_arrayfor_incr;
$4->array_var = variable(var_name, Node_var);
- $1->opcode = Op_push_loop;
- $1->target_continue = $4;
+ $4->target_jmp = tbreak;
+ tcont = $4;
+ $3->opcode = Op_arrayfor_init;
+ $3->target_jmp = tbreak;
+ (void) list_append(ip, $3);
- (void) list_append(ip, $1);
+ if (do_profiling) {
+ $1->opcode = Op_K_arrayfor;
+ $1->target_continue = tcont;
+ $1->target_break = tbreak;
+ (void) list_append(ip, $1);
+ } /* else
+ $1 is NULL */
/* add update_FOO instruction if necessary */
if ($4->array_var->type == Node_var && $4->array_var->var_update) {
@@ -684,7 +759,6 @@ regular_loop:
if (do_profiling) {
(void) list_append(ip, instruction(Op_exec_count));
- ($1 + 1)->opcode = Op_K_arrayfor;
($1 + 1)->forloop_cond = $4;
($1 + 1)->forloop_body = ip->lasti;
}
@@ -694,12 +768,8 @@ regular_loop:
(void) list_append(ip, instruction(Op_jmp));
ip->lasti->target_jmp = $4;
- (void) list_append(ip, instruction(Op_pop_loop));
- $4->target_jmp = $1->target_break = ip->lasti;
- $$ = list_append(ip, instruction(Op_arrayfor_final));
- $3->target_jmp = $$->lasti;
-
- fix_break_continue($1, $4->target_jmp, TRUE);
+ $$ = list_append(ip, tbreak);
+ fix_break_continue(ip, tbreak, tcont);
}
break_allowed--;
@@ -978,72 +1048,15 @@ opt_simple_stmt
{ $$ = $1; }
;
-switch_body
- : case_statements
- {
- INSTRUCTION *dflt = NULL;
-
- if ($1 != NULL) {
- INSTRUCTION *curr;
- const char **case_values = NULL;
- int maxcount = 128;
- int case_count = 0;
- int i;
-
- emalloc(case_values, const char **, sizeof(char *) * maxcount, "statement");
-
- for (curr = $1->case_val->nexti; curr != NULL; curr = curr->nexti) {
- if (curr->opcode == Op_K_case) {
- char *caseval;
- if (curr->memory->type == Node_regex)
- caseval = curr->memory->re_exp->stptr;
- else
- caseval = force_string(curr->memory)->stptr;
- for (i = 0; i < case_count; i++)
- if (strcmp(caseval, case_values[i]) == 0)
- yyerror(_("duplicate case values in switch body: %s"), caseval);
-
- if (case_count >= maxcount) {
- maxcount += 128;
- erealloc(case_values, const char **, sizeof(char*) * maxcount, "statement");
- }
- case_values[case_count++] = caseval;
- } else {
- /* Otherwise save a pointer to the default node. */
- if (dflt != NULL)
- yyerror(_("duplicate `default' detected in switch body"));
- dflt = curr;
- }
- }
-
- efree(case_values);
- $$ = list_prepend($1->case_stmt, instruction(Op_K_switch));
- $$->nexti->case_val = $1->case_val->nexti;
- $$->nexti->switch_dflt = dflt;
- bcfree($1->case_val); /* Op_list */
- bcfree($1); /* Op_case_list */
- } else {
- $$ = list_create(instruction(Op_K_switch));
- $$->nexti->case_val = NULL;
- $$->nexti->switch_dflt = NULL;
- }
- }
- ;
-
case_statements
: /* empty */
{ $$ = NULL; }
| case_statements case_statement
{
- if ($1 == NULL) {
- $2->case_val = list_create($2->case_val);
- $$ = $2;
- } else {
- (void) list_append($1->case_val, $2->case_val);
- (void) list_merge($1->case_stmt, $2->case_stmt);
- bcfree($2); /* Op_case_list */
- $$ = $1;
- }
+ if ($1 == NULL)
+ $$ = list_create($2);
+ else
+ $$ = list_prepend($1, $2);
}
| case_statements error
{ $$ = NULL; }
@@ -1053,66 +1066,47 @@ case_statement
: LEX_CASE case_value colon opt_nls statements
{
INSTRUCTION *casestmt = $5;
-
- $1->memory = $2->memory;
- bcfree($2);
if ($5 == NULL)
casestmt = list_create(instruction(Op_no_op));
if (do_profiling)
(void) list_prepend(casestmt, instruction(Op_exec_count));
-
- $1->target_stmt = casestmt->nexti;
-
- /* recycle $3 as Op_case_list */
- $3->opcode = Op_case_list;
- $3->case_val = $1; /* Op_K_case */
- $3->case_stmt = casestmt; /* Op_list */
- $$ = $3;
+ $1->case_exp = $2;
+ $1->case_stmt = casestmt;
+ bcfree($3);
+ $$ = $1;
}
| LEX_DEFAULT colon opt_nls statements
{
INSTRUCTION *casestmt = $4;
-
if ($4 == NULL)
casestmt = list_create(instruction(Op_no_op));
if (do_profiling)
(void) list_prepend(casestmt, instruction(Op_exec_count));
-
- $1->target_stmt = casestmt->nexti;
- $2->opcode = Op_case_list;
- $2->case_val = $1; /* Op_K_default */
- $2->case_stmt = casestmt; /* Op_list */
- $$ = $2;
+ bcfree($2);
+ $1->case_stmt = casestmt;
+ $$ = $1;
}
;
case_value
: YNUMBER
- {
- $1->opcode = Op_K_case;
- $$ = $1;
- }
+ { $$ = $1; }
| '-' YNUMBER %prec UNARY
{
$2->memory->numbr = -(force_number($2->memory));
bcfree($1);
- $2->opcode = Op_K_case;
$$ = $2;
}
| '+' YNUMBER %prec UNARY
{
bcfree($1);
- $2->opcode = Op_K_case;
$$ = $2;
}
| YSTRING
- {
- $1->opcode = Op_K_case;
- $$ = $1;
- }
+ { $$ = $1; }
| regexp
{
- $1->opcode = Op_K_case;
+ $1->opcode = Op_push_re;
$$ = $1;
}
;
@@ -1846,14 +1840,14 @@ static const struct token tokentab[] = {
{"dcngettext", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3)|A(4)|A(5), do_dcngettext},
{"default", Op_K_default, LEX_DEFAULT, GAWKX, 0},
{"delete", Op_K_delete, LEX_DELETE, NOT_OLD, 0},
-{"do", Op_symbol, LEX_DO, NOT_OLD|BREAK|CONTINUE, 0},
+{"do", Op_K_do, LEX_DO, NOT_OLD|BREAK|CONTINUE, 0},
{"else", Op_K_else, LEX_ELSE, 0, 0},
{"eval", Op_symbol, LEX_EVAL, 0, 0},
{"exit", Op_K_exit, LEX_EXIT, 0, 0},
{"exp", Op_builtin, LEX_BUILTIN, A(1), do_exp},
{"extension", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_ext},
{"fflush", Op_builtin, LEX_BUILTIN, RESX|A(0)|A(1), do_fflush},
-{"for", Op_symbol, LEX_FOR, BREAK|CONTINUE, 0},
+{"for", Op_K_for, LEX_FOR, BREAK|CONTINUE, 0},
{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0},
{"function",Op_func, LEX_FUNCTION, NOT_OLD, 0},
{"gensub", Op_builtin, LEX_BUILTIN, GAWKX|A(3)|A(4), do_gensub},
@@ -1891,12 +1885,12 @@ static const struct token tokentab[] = {
{"strtonum", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_strtonum},
{"sub", Op_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), do_sub},
{"substr", Op_builtin, LEX_BUILTIN, A(2)|A(3), do_substr},
-{"switch", Op_symbol, LEX_SWITCH, GAWKX|BREAK, 0},
+{"switch", Op_K_switch, LEX_SWITCH, GAWKX|BREAK, 0},
{"system", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_system},
{"systime", Op_builtin, LEX_BUILTIN, GAWKX|A(0), do_systime},
{"tolower", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_tolower},
{"toupper", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_toupper},
-{"while", Op_symbol, LEX_WHILE, BREAK|CONTINUE, 0},
+{"while", Op_K_while, LEX_WHILE, BREAK|CONTINUE, 0},
{"xor", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_xor},
};
@@ -3431,12 +3425,15 @@ retry:
yylval = bcalloc(tokentab[mid].value, 3, sourceline);
break;
+ case LEX_FOR:
case LEX_WHILE:
case LEX_DO:
- case LEX_FOR:
case LEX_SWITCH:
- yylval = bcalloc(tokentab[mid].value,
- !!do_profiling + 1, sourceline);
+ if (! do_profiling)
+ return lasttok = class;
+ /* fall through */
+ case LEX_CASE:
+ yylval = bcalloc(tokentab[mid].value, 2, sourceline);
break;
default:
@@ -4503,13 +4500,6 @@ mk_rexp(INSTRUCTION *list)
/* isnoeffect --- when used as a statement, has no side effects */
-/*
- * To be completely general, we should recursively walk the parse
- * tree, to make sure that all the subexpressions also have no effect.
- * Instead, we just weaken the actual warning that's printed, up above
- * in the grammar.
- */
-
static int
isnoeffect(OPCODE type)
{
@@ -4840,23 +4830,26 @@ mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, INSTRUCTION *true_branch,
INSTRUCTION *ip;
- /* FIXME else { } -- add elsep */
-
if (false_branch == NULL) {
- if (elsep != NULL) /* else { } */
- false_branch = list_append(list_create(elsep), instruction(Op_no_op));
- else
- false_branch = list_create(instruction(Op_no_op));
+ false_branch = list_create(instruction(Op_no_op));
+ if (elsep != NULL) { /* else { } */
+ if (do_profiling)
+ (void) list_prepend(false_branch, elsep);
+ else
+ bcfree(elsep);
+ }
} else {
/* assert(elsep != NULL); */
/* avoid a series of no_op's: if .. else if .. else if .. */
if (false_branch->lasti->opcode != Op_no_op)
(void) list_append(false_branch, instruction(Op_no_op));
- (void) list_prepend(false_branch, elsep);
- false_branch->nexti->branch_end = false_branch->lasti;
- if (do_profiling)
+ if (do_profiling) {
+ (void) list_prepend(false_branch, elsep);
+ false_branch->nexti->branch_end = false_branch->lasti;
(void) list_prepend(false_branch, instruction(Op_exec_count));
+ } else
+ bcfree(elsep);
}
(void) list_prepend(false_branch, instruction(Op_jmp));
@@ -4866,12 +4859,13 @@ mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, INSTRUCTION *true_branch,
ip = list_append(cond, instruction(Op_jmp_false));
ip->lasti->target_jmp = false_branch->nexti->nexti;
- (void) list_prepend(ip, ifp);
if (do_profiling) {
+ (void) list_prepend(ip, ifp);
(void) list_append(ip, instruction(Op_exec_count));
ip->nexti->branch_if = ip->lasti;
ip->nexti->branch_else = false_branch->nexti;
- }
+ } else
+ bcfree(ifp);
if (true_branch != NULL)
list_merge(ip, true_branch);
@@ -5055,7 +5049,7 @@ optimize_assignment(INSTRUCTION *exp)
* 1) Array element assignment array[subs] = x:
* Replaces Op_push_array + Op_subscript_lhs + Op_assign + Op_pop
* with single instruction Op_store_sub.
- * Limitation (FIXME): 1 dimension and sub is simple var/value.
+ * Limitation: 1 dimension and sub is simple var/value.
*
* 2) Simple variable assignment var = x:
* Replaces Op_push_lhs + Op_assign + Op_pop with Op_store_var.
@@ -5100,7 +5094,7 @@ optimize_assignment(INSTRUCTION *exp)
/* avoid stuff like x = x (x = y) or x = x gsub(/./, "b", x);
* check for l-value reference to this variable in the r.h.s.
- * Also avoid function calls in general, to guard against
+ * Also, avoid function calls in general to guard against
* global variable assignment.
*/
@@ -5191,7 +5185,7 @@ optimize_assignment(INSTRUCTION *exp)
/* mk_getline --- make instructions for getline */
static INSTRUCTION *
-mk_getline(INSTRUCTION *op, INSTRUCTION *var, INSTRUCTION *redir, OPCODE redirtype)
+mk_getline(INSTRUCTION *op, INSTRUCTION *var, INSTRUCTION *redir, int redirtype)
{
INSTRUCTION *ip;
INSTRUCTION *tp;
@@ -5254,73 +5248,72 @@ mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond,
INSTRUCTION *incr, INSTRUCTION *body)
{
/*
- * [ Op_push_loop | z| y] <-- continue | break
* ------------------------
* init (may be NULL)
* ------------------------
* x:
* cond (Op_no_op if NULL)
* ------------------------
- * [ Op_jmp_false y ]
+ * [ Op_jmp_false tb ]
* ------------------------
* body (may be NULL)
* ------------------------
- * z:
- * incr (may be NULL)
- * [ Op_jmp x ]
+ * tc:
+ * incr (may be NULL)
+ * [ Op_jmp x ]
* ------------------------
- * y:[ Op_pop_loop ]
+ * tb:[ Op_no_op ]
*/
- INSTRUCTION *ip;
- INSTRUCTION *cp;
+ INSTRUCTION *ip, *tbreak, *tcont;
INSTRUCTION *jmp;
INSTRUCTION *pp_cond;
INSTRUCTION *ret;
- cp = instruction(Op_pop_loop);
-
- forp->opcode = Op_push_loop;
- forp->target_break = cp;
- ip = list_create(forp);
-
- if (init != NULL)
- (void) list_merge(ip, init);
+ tbreak = instruction(Op_no_op);
if (cond != NULL) {
add_lint(cond, LINT_assign_in_cond);
pp_cond = cond->nexti;
- (void) list_merge(ip, cond);
+ ip = cond;
(void) list_append(ip, instruction(Op_jmp_false));
- ip->lasti->target_jmp = cp;
+ ip->lasti->target_jmp = tbreak;
} else {
pp_cond = instruction(Op_no_op);
- (void) list_append(ip, pp_cond);
+ ip = list_create(pp_cond);
}
+ if (init != NULL)
+ ip = list_merge(init, ip);
+
if (do_profiling) {
(void) list_append(ip, instruction(Op_exec_count));
- (forp + 1)->opcode = Op_K_for;
(forp + 1)->forloop_cond = pp_cond;
(forp + 1)->forloop_body = ip->lasti;
}
if (body != NULL)
(void) list_merge(ip, body);
-
- if (incr != NULL) {
- forp->target_continue = incr->nexti;
- (void) list_merge(ip, incr);
- }
+
jmp = instruction(Op_jmp);
jmp->target_jmp = pp_cond;
if (incr == NULL)
- forp->target_continue = jmp;
- (void) list_append(ip, jmp);
+ tcont = jmp;
+ else {
+ tcont = incr->nexti;
+ (void) list_merge(ip, incr);
+ }
- ret = list_append(ip, cp);
+ (void) list_append(ip, jmp);
+ ret = list_append(ip, tbreak);
+ fix_break_continue(ret, tbreak, tcont);
- fix_break_continue(forp, cp, TRUE);
+ if (do_profiling) {
+ forp->target_break = tbreak;
+ forp->target_continue = tcont;
+ ret = list_prepend(ret, forp);
+ } /* else
+ forp is NULL */
return ret;
}
@@ -5446,20 +5439,16 @@ count_expressions(INSTRUCTION **list, int isarg)
return count;
}
-/* fix_break_continue --- fix up break & continue nodes in loop bodies */
+/* fix_break_continue --- fix up break & continue codes in loop bodies */
static void
-fix_break_continue(INSTRUCTION *start, INSTRUCTION *end, int check_continue)
+fix_break_continue(INSTRUCTION *list, INSTRUCTION *b_target, INSTRUCTION *c_target)
{
- INSTRUCTION *ip, *b_target, *c_target;
-
- assert(start->opcode == Op_push_loop);
- assert(end->opcode == Op_pop_loop);
+ INSTRUCTION *ip;
- b_target = start->target_break;
- c_target = start->target_continue;
+ list->lasti->nexti = NULL; /* just to make sure */
- for (ip = start; ip != end; ip = ip->nexti) {
+ for (ip = list->nexti; ip != NULL; ip = ip->nexti) {
switch (ip->opcode) {
case Op_K_break:
if (ip->target_jmp == NULL)
@@ -5467,7 +5456,7 @@ fix_break_continue(INSTRUCTION *start, INSTRUCTION *end, int check_continue)
break;
case Op_K_continue:
- if (check_continue && ip->target_jmp == NULL)
+ if (ip->target_jmp == NULL)
ip->target_jmp = c_target;
break;
@@ -5524,7 +5513,6 @@ release_symbols(NODE *symlist, int keep_globals)
* and free all associated memory.
*/
-
void
destroy_symbol(char *name)
{
@@ -5687,22 +5675,6 @@ free_bc_internal(INSTRUCTION *cp)
)
efree(cp->func_name);
break;
- case Op_K_switch:
- for (curr = cp->case_val; curr != NULL; curr = curr->nexti) {
- if (curr->opcode == Op_K_case &&
- curr->memory->type != Node_val
- ) {
- m = curr->memory;
- if (m->re_text != NULL)
- unref(m->re_text);
- if (m->re_reg != NULL)
- refree(m->re_reg);
- if (m->re_exp != NULL)
- unref(m->re_exp);
- freenode(m);
- }
- }
- break;
case Op_push_re:
case Op_match_rec:
case Op_match: