aboutsummaryrefslogtreecommitdiffstats
path: root/awkgram.y
diff options
context:
space:
mode:
Diffstat (limited to 'awkgram.y')
-rw-r--r--awkgram.y37
1 files changed, 31 insertions, 6 deletions
diff --git a/awkgram.y b/awkgram.y
index 2157d3e8..08eb9904 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -84,7 +84,7 @@ static int one_line_close(int fd);
static int want_source = FALSE;
static int want_regexp; /* lexical scanning kludge */
-static int can_return; /* parsing kludge */
+static char *in_function; /* parsing kludge */
static int rule = 0;
const char *const ruletab[] = {
@@ -229,7 +229,7 @@ rule
}
| function_prologue action
{
- can_return = FALSE;
+ in_function = NULL;
(void) mk_function($1, $2);
yyerrok;
}
@@ -358,11 +358,11 @@ function_prologue
$1->source_file = source;
if (install_function($2->lextok, $1, $4) < 0)
YYABORT;
+ in_function = $2->lextok;
$2->lextok = NULL;
bcfree($2);
/* $4 already free'd in install_function */
$$ = $1;
- can_return = TRUE;
}
;
@@ -817,15 +817,27 @@ non_compound_stmt
}
| LEX_RETURN
{
- if (! can_return)
+ if (! in_function)
yyerror(_("`return' used outside function context"));
} opt_exp statement_term {
if ($3 == NULL) {
$$ = list_create($1);
(void) list_prepend($$, instruction(Op_push_i));
$$->nexti->memory = dupnode(Nnull_string);
- } else
+ } else {
+ if (do_optimize > 1
+ && $3->lasti->opcode == Op_func_call
+ && STREQ($3->lasti->func_name, in_function)
+ ) {
+ /* Do tail recursion optimization. Tail
+ * call without a return value is recognized
+ * in mk_function().
+ */
+ ($3->lasti + 1)->tail_call = TRUE;
+ }
+
$$ = list_append($3, $1);
+ }
}
| simple_stmt statement_term
;
@@ -3899,6 +3911,19 @@ mk_function(INSTRUCTION *fi, INSTRUCTION *def)
thisfunc = fi->func_body;
assert(thisfunc != NULL);
+ if (do_optimize > 1 && def->lasti->opcode == Op_pop) {
+ /* tail call which does not return any value. */
+
+ INSTRUCTION *t;
+
+ for (t = def->nexti; t->nexti != def->lasti; t = t->nexti)
+ ;
+ if (t->opcode == Op_func_call
+ && STREQ(t->func_name, thisfunc->vname)
+ )
+ (t + 1)->tail_call = TRUE;
+ }
+
/* add an implicit return at end;
* also used by 'return' command in debugger
*/
@@ -4773,7 +4798,7 @@ optimize_assignment(INSTRUCTION *exp)
if ( ! do_optimize
|| ( i1->opcode != Op_assign
&& i1->opcode != Op_field_assign)
- )
+ )
return list_append(exp, instruction(Op_pop));
for (i2 = exp->nexti; i2 != i1; i2 = i2->nexti) {