gawk-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gawk-diffs] [SCM] gawk branch, gawk_performance, updated. bf958505d3b16


From: John Haque
Subject: [gawk-diffs] [SCM] gawk branch, gawk_performance, updated. bf958505d3b1681a91f10e866636e9088d732a60
Date: Fri, 07 Oct 2011 10:13:55 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "gawk".

The branch, gawk_performance has been updated
       via  bf958505d3b1681a91f10e866636e9088d732a60 (commit)
      from  a95ec08516e3a7693274ac75a87eea6cf651de22 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://git.sv.gnu.org/cgit/gawk.git/commit/?id=bf958505d3b1681a91f10e866636e9088d732a60

commit bf958505d3b1681a91f10e866636e9088d732a60
Author: john haque <address@hidden>
Date:   Fri Oct 7 05:13:25 2011 -0500

    Optimize tail-recursive calls.

diff --git a/ChangeLog b/ChangeLog
index c093ad2..535d30a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2011-10-07         John Haque     <address@hidden>
+       Tail recursion optimization.
+       * awkgram.y (grammar, mk_function): Recognize tail-recursive
+       calls.
+       * awk.h (tail_call, num_tail_calls): New defines.
+       * eval.c (setup_frame): Reuse function call stack for
+       tail-recursive calls.
+       (dump_fcall_stack): Reworked.
+
 2011-09-08         John Haque     <address@hidden>
        Optimization for compound assignment, increment and
        decrement operators; Avoid unref and make_number calls
diff --git a/array.c b/array.c
index 436002a..e6e0c26 100644
--- a/array.c
+++ b/array.c
@@ -1285,6 +1285,7 @@ assoc_list(NODE *symbol, const char *sort_str, SORT_CTXT 
sort_ctxt)
        qsort_compfunc cmp_func = 0;
        INSTRUCTION *code = NULL;
        extern int currule;
+       int save_rule;
        
        num_elems = symbol->table_size;
        assert(num_elems > 0);
@@ -1345,7 +1346,7 @@ assoc_list(NODE *symbol, const char *sort_str, SORT_CTXT 
sort_ctxt)
                 * to undefined (0). `exit' is handled in sort_user_func.
                 */
 
-               (code + 1)->inrule = currule;   /* save current rule */
+               save_rule = currule;    /* save current rule */
                currule = 0;
 
                PUSH_CODE(code);
@@ -1360,7 +1361,7 @@ assoc_list(NODE *symbol, const char *sort_str, SORT_CTXT 
sort_ctxt)
 
        if (cmp_func == sort_user_func) {
                code = POP_CODE();
-               currule = (code + 1)->inrule;   /* restore current rule */ 
+               currule = save_rule;            /* restore current rule */ 
                bcfree(code->nexti);            /* Op_stop */
                bcfree(code);                   /* Op_func_call */
        }
diff --git a/awk.h b/awk.h
index f5e1325..cef1bc3 100644
--- a/awk.h
+++ b/awk.h
@@ -454,6 +454,7 @@ typedef struct exp_node {
 #define stack        sub.nodep.r.av
 #define func_node    sub.nodep.x.extra
 #define reti         sub.nodep.reflags
+#define num_tail_calls    sub.nodep.cnt
 
 /* Node_var: */
 #define var_value    lnode
@@ -706,7 +707,6 @@ typedef struct exp_instruction {
 #define lextok          d.name
 #define param_count     x.xl
 
-
 /* Op_rule */
 #define in_rule         x.xl
 #define source_file     d.name
@@ -743,7 +743,8 @@ typedef struct exp_instruction {
 #define func_body       x.xn
 
 /* Op_func_call */
-#define inrule         d.dl
+#define tail_call      d.dl
+
 
 /* Op_subscript */
 #define sub_count       d.dl
diff --git a/awkgram.c b/awkgram.c
index d6474f2..432473f 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -128,7 +128,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[] = {
@@ -707,20 +707,20 @@ static const yytype_uint16 yyrline[] =
      317,   326,   336,   338,   340,   346,   351,   352,   356,   375,
      374,   408,   410,   415,   416,   429,   434,   435,   439,   441,
      443,   450,   540,   582,   624,   739,   746,   753,   763,   772,
-     781,   790,   805,   821,   820,   832,   844,   844,   938,   938,
-     963,   986,   992,   993,   999,  1000,  1007,  1012,  1024,  1038,
-    1040,  1046,  1051,  1053,  1061,  1063,  1072,  1073,  1081,  1086,
-    1086,  1097,  1101,  1109,  1110,  1113,  1115,  1120,  1121,  1130,
-    1131,  1136,  1141,  1147,  1149,  1151,  1158,  1159,  1165,  1166,
-    1171,  1173,  1178,  1180,  1182,  1184,  1190,  1197,  1199,  1201,
-    1217,  1227,  1234,  1236,  1241,  1243,  1245,  1253,  1255,  1260,
-    1262,  1267,  1269,  1271,  1321,  1323,  1325,  1327,  1329,  1331,
-    1333,  1335,  1358,  1363,  1368,  1393,  1399,  1401,  1403,  1405,
-    1407,  1409,  1414,  1418,  1449,  1451,  1457,  1463,  1476,  1477,
-    1478,  1483,  1488,  1492,  1496,  1509,  1522,  1527,  1563,  1581,
-    1582,  1588,  1589,  1594,  1596,  1603,  1620,  1637,  1639,  1646,
-    1651,  1659,  1669,  1682,  1691,  1695,  1699,  1703,  1707,  1711,
-    1714,  1716,  1720,  1724,  1728
+     781,   790,   805,   821,   820,   844,   856,   856,   950,   950,
+     975,   998,  1004,  1005,  1011,  1012,  1019,  1024,  1036,  1050,
+    1052,  1058,  1063,  1065,  1073,  1075,  1084,  1085,  1093,  1098,
+    1098,  1109,  1113,  1121,  1122,  1125,  1127,  1132,  1133,  1142,
+    1143,  1148,  1153,  1159,  1161,  1163,  1170,  1171,  1177,  1178,
+    1183,  1185,  1190,  1192,  1194,  1196,  1202,  1209,  1211,  1213,
+    1229,  1239,  1246,  1248,  1253,  1255,  1257,  1265,  1267,  1272,
+    1274,  1279,  1281,  1283,  1333,  1335,  1337,  1339,  1341,  1343,
+    1345,  1347,  1370,  1375,  1380,  1405,  1411,  1413,  1415,  1417,
+    1419,  1421,  1426,  1430,  1461,  1463,  1469,  1475,  1488,  1489,
+    1490,  1495,  1500,  1504,  1508,  1521,  1534,  1539,  1575,  1593,
+    1594,  1600,  1601,  1606,  1608,  1615,  1632,  1649,  1651,  1658,
+    1663,  1671,  1681,  1694,  1703,  1707,  1711,  1715,  1719,  1723,
+    1726,  1728,  1732,  1736,  1740
 };
 #endif
 
@@ -2099,7 +2099,7 @@ yyreduce:
 /* Line 1821 of yacc.c  */
 #line 231 "awkgram.y"
     {
-               can_return = FALSE;
+               in_function = NULL;
                (void) mk_function((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
                yyerrok;
          }
@@ -2293,11 +2293,11 @@ yyreduce:
                (yyvsp[(1) - (6)])->source_file = source;
                if (install_function((yyvsp[(2) - (6)])->lextok, (yyvsp[(1) - 
(6)]), (yyvsp[(4) - (6)])) < 0)
                        YYABORT;
+               in_function = (yyvsp[(2) - (6)])->lextok;
                (yyvsp[(2) - (6)])->lextok = NULL;
                bcfree((yyvsp[(2) - (6)]));
                /* $4 already free'd in install_function */
                (yyval) = (yyvsp[(1) - (6)]);
-               can_return = TRUE;
          }
     break;
 
@@ -2839,7 +2839,7 @@ regular_loop:
 /* Line 1821 of yacc.c  */
 #line 821 "awkgram.y"
     {
-               if (! can_return)
+               if (! in_function)
                        yyerror(_("`return' used outside function context"));
          }
     break;
@@ -2853,22 +2853,34 @@ regular_loop:
                        (yyval) = list_create((yyvsp[(1) - (4)]));
                        (void) list_prepend((yyval), instruction(Op_push_i));
                        (yyval)->nexti->memory = dupnode(Nnull_string);
-               } else
+               } else {
+                       if (do_optimize > 1
+                               && (yyvsp[(3) - (4)])->lasti->opcode == 
Op_func_call
+                               && STREQ((yyvsp[(3) - (4)])->lasti->func_name, 
in_function)
+                       ) {
+                               /* Do tail recursion optimization. Tail
+                                * call without a return value is recognized
+                                * in mk_function().
+                                */
+                               ((yyvsp[(3) - (4)])->lasti + 1)->tail_call = 
TRUE;
+                       }
+
                        (yyval) = list_append((yyvsp[(3) - (4)]), (yyvsp[(1) - 
(4)]));
+               }
          }
     break;
 
   case 56:
 
 /* Line 1821 of yacc.c  */
-#line 844 "awkgram.y"
+#line 856 "awkgram.y"
     { in_print = TRUE; in_parens = 0; }
     break;
 
   case 57:
 
 /* Line 1821 of yacc.c  */
-#line 845 "awkgram.y"
+#line 857 "awkgram.y"
     {
                /*
                 * Optimization: plain `print' has no expression list, so $3 is 
null.
@@ -2966,14 +2978,14 @@ regular_loop:
   case 58:
 
 /* Line 1821 of yacc.c  */
-#line 938 "awkgram.y"
+#line 950 "awkgram.y"
     { sub_counter = 0; }
     break;
 
   case 59:
 
 /* Line 1821 of yacc.c  */
-#line 939 "awkgram.y"
+#line 951 "awkgram.y"
     {
                char *arr = (yyvsp[(2) - (4)])->lextok;
 
@@ -3003,7 +3015,7 @@ regular_loop:
   case 60:
 
 /* Line 1821 of yacc.c  */
-#line 968 "awkgram.y"
+#line 980 "awkgram.y"
     {
                static short warned = FALSE;
                char *arr = (yyvsp[(3) - (4)])->lextok;
@@ -3027,35 +3039,35 @@ regular_loop:
   case 61:
 
 /* Line 1821 of yacc.c  */
-#line 987 "awkgram.y"
+#line 999 "awkgram.y"
     {  (yyval) = optimize_assignment((yyvsp[(1) - (1)])); }
     break;
 
   case 62:
 
 /* Line 1821 of yacc.c  */
-#line 992 "awkgram.y"
+#line 1004 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 63:
 
 /* Line 1821 of yacc.c  */
-#line 994 "awkgram.y"
+#line 1006 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 64:
 
 /* Line 1821 of yacc.c  */
-#line 999 "awkgram.y"
+#line 1011 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 65:
 
 /* Line 1821 of yacc.c  */
-#line 1001 "awkgram.y"
+#line 1013 "awkgram.y"
     {
                if ((yyvsp[(1) - (2)]) == NULL)
                        (yyval) = list_create((yyvsp[(2) - (2)]));
@@ -3067,14 +3079,14 @@ regular_loop:
   case 66:
 
 /* Line 1821 of yacc.c  */
-#line 1008 "awkgram.y"
+#line 1020 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 67:
 
 /* Line 1821 of yacc.c  */
-#line 1013 "awkgram.y"
+#line 1025 "awkgram.y"
     {
                INSTRUCTION *casestmt = (yyvsp[(5) - (5)]);
                if ((yyvsp[(5) - (5)]) == NULL)
@@ -3091,7 +3103,7 @@ regular_loop:
   case 68:
 
 /* Line 1821 of yacc.c  */
-#line 1025 "awkgram.y"
+#line 1037 "awkgram.y"
     {
                INSTRUCTION *casestmt = (yyvsp[(4) - (4)]);
                if ((yyvsp[(4) - (4)]) == NULL)
@@ -3107,14 +3119,14 @@ regular_loop:
   case 69:
 
 /* Line 1821 of yacc.c  */
-#line 1039 "awkgram.y"
+#line 1051 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 70:
 
 /* Line 1821 of yacc.c  */
-#line 1041 "awkgram.y"
+#line 1053 "awkgram.y"
     { 
                (yyvsp[(2) - (2)])->memory->numbr = -(force_number((yyvsp[(2) - 
(2)])->memory));
                bcfree((yyvsp[(1) - (2)]));
@@ -3125,7 +3137,7 @@ regular_loop:
   case 71:
 
 /* Line 1821 of yacc.c  */
-#line 1047 "awkgram.y"
+#line 1059 "awkgram.y"
     {
                bcfree((yyvsp[(1) - (2)]));
                (yyval) = (yyvsp[(2) - (2)]);
@@ -3135,14 +3147,14 @@ regular_loop:
   case 72:
 
 /* Line 1821 of yacc.c  */
-#line 1052 "awkgram.y"
+#line 1064 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 73:
 
 /* Line 1821 of yacc.c  */
-#line 1054 "awkgram.y"
+#line 1066 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_push_re;
                (yyval) = (yyvsp[(1) - (1)]);
@@ -3152,21 +3164,21 @@ regular_loop:
   case 74:
 
 /* Line 1821 of yacc.c  */
-#line 1062 "awkgram.y"
+#line 1074 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 75:
 
 /* Line 1821 of yacc.c  */
-#line 1064 "awkgram.y"
+#line 1076 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 77:
 
 /* Line 1821 of yacc.c  */
-#line 1074 "awkgram.y"
+#line 1086 "awkgram.y"
     {
                (yyval) = (yyvsp[(2) - (3)]);
          }
@@ -3175,7 +3187,7 @@ regular_loop:
   case 78:
 
 /* Line 1821 of yacc.c  */
-#line 1081 "awkgram.y"
+#line 1093 "awkgram.y"
     {
                in_print = FALSE;
                in_parens = 0;
@@ -3186,14 +3198,14 @@ regular_loop:
   case 79:
 
 /* Line 1821 of yacc.c  */
-#line 1086 "awkgram.y"
+#line 1098 "awkgram.y"
     { in_print = FALSE; in_parens = 0; }
     break;
 
   case 80:
 
 /* Line 1821 of yacc.c  */
-#line 1087 "awkgram.y"
+#line 1099 "awkgram.y"
     {
                if ((yyvsp[(1) - (3)])->redir_type == redirect_twoway
                        && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_K_getline_redir
@@ -3206,7 +3218,7 @@ regular_loop:
   case 81:
 
 /* Line 1821 of yacc.c  */
-#line 1098 "awkgram.y"
+#line 1110 "awkgram.y"
     {
                (yyval) = mk_condition((yyvsp[(3) - (6)]), (yyvsp[(1) - (6)]), 
(yyvsp[(6) - (6)]), NULL, NULL);
          }
@@ -3215,7 +3227,7 @@ regular_loop:
   case 82:
 
 /* Line 1821 of yacc.c  */
-#line 1103 "awkgram.y"
+#line 1115 "awkgram.y"
     {
                (yyval) = mk_condition((yyvsp[(3) - (9)]), (yyvsp[(1) - (9)]), 
(yyvsp[(6) - (9)]), (yyvsp[(7) - (9)]), (yyvsp[(9) - (9)]));
          }
@@ -3224,14 +3236,14 @@ regular_loop:
   case 87:
 
 /* Line 1821 of yacc.c  */
-#line 1120 "awkgram.y"
+#line 1132 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 88:
 
 /* Line 1821 of yacc.c  */
-#line 1122 "awkgram.y"
+#line 1134 "awkgram.y"
     {
                bcfree((yyvsp[(1) - (2)]));
                (yyval) = (yyvsp[(2) - (2)]);
@@ -3241,21 +3253,21 @@ regular_loop:
   case 89:
 
 /* Line 1821 of yacc.c  */
-#line 1130 "awkgram.y"
+#line 1142 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 90:
 
 /* Line 1821 of yacc.c  */
-#line 1132 "awkgram.y"
+#line 1144 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]) ; }
     break;
 
   case 91:
 
 /* Line 1821 of yacc.c  */
-#line 1137 "awkgram.y"
+#line 1149 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->param_count = 0;
                (yyval) = list_create((yyvsp[(1) - (1)]));
@@ -3265,7 +3277,7 @@ regular_loop:
   case 92:
 
 /* Line 1821 of yacc.c  */
-#line 1142 "awkgram.y"
+#line 1154 "awkgram.y"
     {
                (yyvsp[(3) - (3)])->param_count =  (yyvsp[(1) - 
(3)])->lasti->param_count + 1;
                (yyval) = list_append((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]));
@@ -3276,63 +3288,63 @@ regular_loop:
   case 93:
 
 /* Line 1821 of yacc.c  */
-#line 1148 "awkgram.y"
+#line 1160 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 94:
 
 /* Line 1821 of yacc.c  */
-#line 1150 "awkgram.y"
+#line 1162 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
   case 95:
 
 /* Line 1821 of yacc.c  */
-#line 1152 "awkgram.y"
+#line 1164 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (3)]); }
     break;
 
   case 96:
 
 /* Line 1821 of yacc.c  */
-#line 1158 "awkgram.y"
+#line 1170 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 97:
 
 /* Line 1821 of yacc.c  */
-#line 1160 "awkgram.y"
+#line 1172 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 98:
 
 /* Line 1821 of yacc.c  */
-#line 1165 "awkgram.y"
+#line 1177 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 99:
 
 /* Line 1821 of yacc.c  */
-#line 1167 "awkgram.y"
+#line 1179 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 100:
 
 /* Line 1821 of yacc.c  */
-#line 1172 "awkgram.y"
+#line 1184 "awkgram.y"
     {  (yyval) = mk_expression_list(NULL, (yyvsp[(1) - (1)])); }
     break;
 
   case 101:
 
 /* Line 1821 of yacc.c  */
-#line 1174 "awkgram.y"
+#line 1186 "awkgram.y"
     {
                (yyval) = mk_expression_list((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)]));
                yyerrok;
@@ -3342,35 +3354,35 @@ regular_loop:
   case 102:
 
 /* Line 1821 of yacc.c  */
-#line 1179 "awkgram.y"
+#line 1191 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 103:
 
 /* Line 1821 of yacc.c  */
-#line 1181 "awkgram.y"
+#line 1193 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 104:
 
 /* Line 1821 of yacc.c  */
-#line 1183 "awkgram.y"
+#line 1195 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 105:
 
 /* Line 1821 of yacc.c  */
-#line 1185 "awkgram.y"
+#line 1197 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 106:
 
 /* Line 1821 of yacc.c  */
-#line 1191 "awkgram.y"
+#line 1203 "awkgram.y"
     {
                if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_match_rec)
                        lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3382,21 +3394,21 @@ regular_loop:
   case 107:
 
 /* Line 1821 of yacc.c  */
-#line 1198 "awkgram.y"
+#line 1210 "awkgram.y"
     {  (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
     break;
 
   case 108:
 
 /* Line 1821 of yacc.c  */
-#line 1200 "awkgram.y"
+#line 1212 "awkgram.y"
     {  (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
     break;
 
   case 109:
 
 /* Line 1821 of yacc.c  */
-#line 1202 "awkgram.y"
+#line 1214 "awkgram.y"
     {
                if ((yyvsp[(1) - (3)])->lasti->opcode == Op_match_rec)
                        warning_ln((yyvsp[(2) - (3)])->source_line,
@@ -3417,7 +3429,7 @@ regular_loop:
   case 110:
 
 /* Line 1821 of yacc.c  */
-#line 1218 "awkgram.y"
+#line 1230 "awkgram.y"
     {
                if (do_lint_old)
                        warning_ln((yyvsp[(2) - (3)])->source_line,
@@ -3432,7 +3444,7 @@ regular_loop:
   case 111:
 
 /* Line 1821 of yacc.c  */
-#line 1228 "awkgram.y"
+#line 1240 "awkgram.y"
     {
                if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_match_rec)
                        lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3444,35 +3456,35 @@ regular_loop:
   case 112:
 
 /* Line 1821 of yacc.c  */
-#line 1235 "awkgram.y"
+#line 1247 "awkgram.y"
     { (yyval) = mk_condition((yyvsp[(1) - (5)]), (yyvsp[(2) - (5)]), 
(yyvsp[(3) - (5)]), (yyvsp[(4) - (5)]), (yyvsp[(5) - (5)])); }
     break;
 
   case 113:
 
 /* Line 1821 of yacc.c  */
-#line 1237 "awkgram.y"
+#line 1249 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 114:
 
 /* Line 1821 of yacc.c  */
-#line 1242 "awkgram.y"
+#line 1254 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 115:
 
 /* Line 1821 of yacc.c  */
-#line 1244 "awkgram.y"
+#line 1256 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 116:
 
 /* Line 1821 of yacc.c  */
-#line 1246 "awkgram.y"
+#line 1258 "awkgram.y"
     {  
                (yyvsp[(2) - (2)])->opcode = Op_assign_quotient;
                (yyval) = (yyvsp[(2) - (2)]);
@@ -3482,49 +3494,49 @@ regular_loop:
   case 117:
 
 /* Line 1821 of yacc.c  */
-#line 1254 "awkgram.y"
+#line 1266 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 118:
 
 /* Line 1821 of yacc.c  */
-#line 1256 "awkgram.y"
+#line 1268 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 119:
 
 /* Line 1821 of yacc.c  */
-#line 1261 "awkgram.y"
+#line 1273 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 120:
 
 /* Line 1821 of yacc.c  */
-#line 1263 "awkgram.y"
+#line 1275 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 121:
 
 /* Line 1821 of yacc.c  */
-#line 1268 "awkgram.y"
+#line 1280 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 122:
 
 /* Line 1821 of yacc.c  */
-#line 1270 "awkgram.y"
+#line 1282 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 123:
 
 /* Line 1821 of yacc.c  */
-#line 1272 "awkgram.y"
+#line 1284 "awkgram.y"
     {
                int count = 2;
                int is_simple_var = FALSE;
@@ -3576,49 +3588,49 @@ regular_loop:
   case 125:
 
 /* Line 1821 of yacc.c  */
-#line 1324 "awkgram.y"
+#line 1336 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 126:
 
 /* Line 1821 of yacc.c  */
-#line 1326 "awkgram.y"
+#line 1338 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 127:
 
 /* Line 1821 of yacc.c  */
-#line 1328 "awkgram.y"
+#line 1340 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 128:
 
 /* Line 1821 of yacc.c  */
-#line 1330 "awkgram.y"
+#line 1342 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 129:
 
 /* Line 1821 of yacc.c  */
-#line 1332 "awkgram.y"
+#line 1344 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 130:
 
 /* Line 1821 of yacc.c  */
-#line 1334 "awkgram.y"
+#line 1346 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 131:
 
 /* Line 1821 of yacc.c  */
-#line 1336 "awkgram.y"
+#line 1348 "awkgram.y"
     {
                /*
                 * In BEGINFILE/ENDFILE, allow `getline var < file'
@@ -3646,7 +3658,7 @@ regular_loop:
   case 132:
 
 /* Line 1821 of yacc.c  */
-#line 1359 "awkgram.y"
+#line 1371 "awkgram.y"
     {
                (yyvsp[(2) - (2)])->opcode = Op_postincrement;
                (yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - 
(2)]));
@@ -3656,7 +3668,7 @@ regular_loop:
   case 133:
 
 /* Line 1821 of yacc.c  */
-#line 1364 "awkgram.y"
+#line 1376 "awkgram.y"
     {
                (yyvsp[(2) - (2)])->opcode = Op_postdecrement;
                (yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - 
(2)]));
@@ -3666,7 +3678,7 @@ regular_loop:
   case 134:
 
 /* Line 1821 of yacc.c  */
-#line 1369 "awkgram.y"
+#line 1381 "awkgram.y"
     {
                if (do_lint_old) {
                    warning_ln((yyvsp[(4) - (5)])->source_line,
@@ -3691,7 +3703,7 @@ regular_loop:
   case 135:
 
 /* Line 1821 of yacc.c  */
-#line 1394 "awkgram.y"
+#line 1406 "awkgram.y"
     {
                  (yyval) = mk_getline((yyvsp[(3) - (4)]), (yyvsp[(4) - (4)]), 
(yyvsp[(1) - (4)]), (yyvsp[(2) - (4)])->redir_type);
                  bcfree((yyvsp[(2) - (4)]));
@@ -3701,49 +3713,49 @@ regular_loop:
   case 136:
 
 /* Line 1821 of yacc.c  */
-#line 1400 "awkgram.y"
+#line 1412 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 137:
 
 /* Line 1821 of yacc.c  */
-#line 1402 "awkgram.y"
+#line 1414 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 138:
 
 /* Line 1821 of yacc.c  */
-#line 1404 "awkgram.y"
+#line 1416 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 139:
 
 /* Line 1821 of yacc.c  */
-#line 1406 "awkgram.y"
+#line 1418 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 140:
 
 /* Line 1821 of yacc.c  */
-#line 1408 "awkgram.y"
+#line 1420 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 141:
 
 /* Line 1821 of yacc.c  */
-#line 1410 "awkgram.y"
+#line 1422 "awkgram.y"
     { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
     break;
 
   case 142:
 
 /* Line 1821 of yacc.c  */
-#line 1415 "awkgram.y"
+#line 1427 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@ -3752,7 +3764,7 @@ regular_loop:
   case 143:
 
 /* Line 1821 of yacc.c  */
-#line 1419 "awkgram.y"
+#line 1431 "awkgram.y"
     {
                if ((yyvsp[(2) - (2)])->opcode == Op_match_rec) {
                        (yyvsp[(2) - (2)])->opcode = Op_nomatch;
@@ -3788,14 +3800,14 @@ regular_loop:
   case 144:
 
 /* Line 1821 of yacc.c  */
-#line 1450 "awkgram.y"
+#line 1462 "awkgram.y"
     { (yyval) = (yyvsp[(2) - (3)]); }
     break;
 
   case 145:
 
 /* Line 1821 of yacc.c  */
-#line 1452 "awkgram.y"
+#line 1464 "awkgram.y"
     {
                (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
                if ((yyval) == NULL)
@@ -3806,7 +3818,7 @@ regular_loop:
   case 146:
 
 /* Line 1821 of yacc.c  */
-#line 1458 "awkgram.y"
+#line 1470 "awkgram.y"
     {
                (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
                if ((yyval) == NULL)
@@ -3817,7 +3829,7 @@ regular_loop:
   case 147:
 
 /* Line 1821 of yacc.c  */
-#line 1464 "awkgram.y"
+#line 1476 "awkgram.y"
     {
                static short warned1 = FALSE;
 
@@ -3835,7 +3847,7 @@ regular_loop:
   case 150:
 
 /* Line 1821 of yacc.c  */
-#line 1479 "awkgram.y"
+#line 1491 "awkgram.y"
     {
                (yyvsp[(1) - (2)])->opcode = Op_preincrement;
                (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - 
(2)]));
@@ -3845,7 +3857,7 @@ regular_loop:
   case 151:
 
 /* Line 1821 of yacc.c  */
-#line 1484 "awkgram.y"
+#line 1496 "awkgram.y"
     {
                (yyvsp[(1) - (2)])->opcode = Op_predecrement;
                (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - 
(2)]));
@@ -3855,7 +3867,7 @@ regular_loop:
   case 152:
 
 /* Line 1821 of yacc.c  */
-#line 1489 "awkgram.y"
+#line 1501 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@ -3864,7 +3876,7 @@ regular_loop:
   case 153:
 
 /* Line 1821 of yacc.c  */
-#line 1493 "awkgram.y"
+#line 1505 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@ -3873,7 +3885,7 @@ regular_loop:
   case 154:
 
 /* Line 1821 of yacc.c  */
-#line 1497 "awkgram.y"
+#line 1509 "awkgram.y"
     {
                if ((yyvsp[(2) - (2)])->lasti->opcode == Op_push_i
                        && ((yyvsp[(2) - (2)])->lasti->memory->flags & 
(STRCUR|STRING)) == 0
@@ -3891,7 +3903,7 @@ regular_loop:
   case 155:
 
 /* Line 1821 of yacc.c  */
-#line 1510 "awkgram.y"
+#line 1522 "awkgram.y"
     {
            /*
             * was: $$ = $2
@@ -3906,7 +3918,7 @@ regular_loop:
   case 156:
 
 /* Line 1821 of yacc.c  */
-#line 1523 "awkgram.y"
+#line 1535 "awkgram.y"
     {
                func_use((yyvsp[(1) - (1)])->lasti->func_name, FUNC_USE);
                (yyval) = (yyvsp[(1) - (1)]);
@@ -3916,7 +3928,7 @@ regular_loop:
   case 157:
 
 /* Line 1821 of yacc.c  */
-#line 1528 "awkgram.y"
+#line 1540 "awkgram.y"
     {
                /* indirect function call */
                INSTRUCTION *f, *t;
@@ -3954,7 +3966,7 @@ regular_loop:
   case 158:
 
 /* Line 1821 of yacc.c  */
-#line 1564 "awkgram.y"
+#line 1576 "awkgram.y"
     {
                param_sanity((yyvsp[(3) - (4)]));
                (yyvsp[(1) - (4)])->opcode = Op_func_call;
@@ -3973,42 +3985,42 @@ regular_loop:
   case 159:
 
 /* Line 1821 of yacc.c  */
-#line 1581 "awkgram.y"
+#line 1593 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 160:
 
 /* Line 1821 of yacc.c  */
-#line 1583 "awkgram.y"
+#line 1595 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 161:
 
 /* Line 1821 of yacc.c  */
-#line 1588 "awkgram.y"
+#line 1600 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 162:
 
 /* Line 1821 of yacc.c  */
-#line 1590 "awkgram.y"
+#line 1602 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
   case 163:
 
 /* Line 1821 of yacc.c  */
-#line 1595 "awkgram.y"
+#line 1607 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 164:
 
 /* Line 1821 of yacc.c  */
-#line 1597 "awkgram.y"
+#line 1609 "awkgram.y"
     {
                (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@ -4017,7 +4029,7 @@ regular_loop:
   case 165:
 
 /* Line 1821 of yacc.c  */
-#line 1604 "awkgram.y"
+#line 1616 "awkgram.y"
     {
                INSTRUCTION *ip = (yyvsp[(1) - (1)])->lasti; 
                int count = ip->sub_count;      /* # of SUBSEP-seperated 
expressions */
@@ -4036,7 +4048,7 @@ regular_loop:
   case 166:
 
 /* Line 1821 of yacc.c  */
-#line 1621 "awkgram.y"
+#line 1633 "awkgram.y"
     {
                INSTRUCTION *t = (yyvsp[(2) - (3)]);
                if ((yyvsp[(2) - (3)]) == NULL) {
@@ -4055,14 +4067,14 @@ regular_loop:
   case 167:
 
 /* Line 1821 of yacc.c  */
-#line 1638 "awkgram.y"
+#line 1650 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 168:
 
 /* Line 1821 of yacc.c  */
-#line 1640 "awkgram.y"
+#line 1652 "awkgram.y"
     {
                (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@ -4071,14 +4083,14 @@ regular_loop:
   case 169:
 
 /* Line 1821 of yacc.c  */
-#line 1647 "awkgram.y"
+#line 1659 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
   case 170:
 
 /* Line 1821 of yacc.c  */
-#line 1652 "awkgram.y"
+#line 1664 "awkgram.y"
     {
                char *var_name = (yyvsp[(1) - (1)])->lextok;
 
@@ -4091,7 +4103,7 @@ regular_loop:
   case 171:
 
 /* Line 1821 of yacc.c  */
-#line 1660 "awkgram.y"
+#line 1672 "awkgram.y"
     {
                char *arr = (yyvsp[(1) - (2)])->lextok;
                (yyvsp[(1) - (2)])->memory = variable((yyvsp[(1) - 
(2)])->source_line, arr, Node_var_new);
@@ -4103,7 +4115,7 @@ regular_loop:
   case 172:
 
 /* Line 1821 of yacc.c  */
-#line 1670 "awkgram.y"
+#line 1682 "awkgram.y"
     {
                INSTRUCTION *ip = (yyvsp[(1) - (1)])->nexti;
                if (ip->opcode == Op_push
@@ -4121,7 +4133,7 @@ regular_loop:
   case 173:
 
 /* Line 1821 of yacc.c  */
-#line 1683 "awkgram.y"
+#line 1695 "awkgram.y"
     {
                (yyval) = list_append((yyvsp[(2) - (3)]), (yyvsp[(1) - (3)]));
                if ((yyvsp[(3) - (3)]) != NULL)
@@ -4132,7 +4144,7 @@ regular_loop:
   case 174:
 
 /* Line 1821 of yacc.c  */
-#line 1692 "awkgram.y"
+#line 1704 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_postincrement;
          }
@@ -4141,7 +4153,7 @@ regular_loop:
   case 175:
 
 /* Line 1821 of yacc.c  */
-#line 1696 "awkgram.y"
+#line 1708 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_postdecrement;
          }
@@ -4150,49 +4162,49 @@ regular_loop:
   case 176:
 
 /* Line 1821 of yacc.c  */
-#line 1699 "awkgram.y"
+#line 1711 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 178:
 
 /* Line 1821 of yacc.c  */
-#line 1707 "awkgram.y"
+#line 1719 "awkgram.y"
     { yyerrok; }
     break;
 
   case 179:
 
 /* Line 1821 of yacc.c  */
-#line 1711 "awkgram.y"
+#line 1723 "awkgram.y"
     { yyerrok; }
     break;
 
   case 182:
 
 /* Line 1821 of yacc.c  */
-#line 1720 "awkgram.y"
+#line 1732 "awkgram.y"
     { yyerrok; }
     break;
 
   case 183:
 
 /* Line 1821 of yacc.c  */
-#line 1724 "awkgram.y"
+#line 1736 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); yyerrok; }
     break;
 
   case 184:
 
 /* Line 1821 of yacc.c  */
-#line 1728 "awkgram.y"
+#line 1740 "awkgram.y"
     { yyerrok; }
     break;
 
 
 
 /* Line 1821 of yacc.c  */
-#line 4208 "awkgram.c"
+#line 4220 "awkgram.c"
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -4423,7 +4435,7 @@ yyreturn:
 
 
 /* Line 2067 of yacc.c  */
-#line 1730 "awkgram.y"
+#line 1742 "awkgram.y"
 
 
 struct token {
@@ -6586,6 +6598,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
         */
@@ -7461,7 +7486,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) {
diff --git a/awkgram.y b/awkgram.y
index b606453..12ea769 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;
          }
        ;
 
@@ -819,15 +819,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
        ;
@@ -3889,6 +3901,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
         */
@@ -4764,7 +4789,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) {
diff --git a/eval.c b/eval.c
index f3d2c26..960dfe6 100644
--- a/eval.c
+++ b/eval.c
@@ -687,7 +687,7 @@ pop_frame()
 }
 #else  /* not PROFILING or DEBUGGING */
 #define push_frame(p)  /* nothing */
-#define pop_frame()            /* nothing */
+#define pop_frame()    /* nothing */
 #endif
 
 
@@ -698,9 +698,8 @@ pop_frame()
 void
 dump_fcall_stack(FILE *fp)
 {
-
        NODE *f, *func;
-       long i = 0;
+       long i = 0, j, k = 0;
 
        if (fcall_count == 0)
                return;
@@ -708,16 +707,18 @@ dump_fcall_stack(FILE *fp)
 
        /* current frame */
        func = frame_ptr->func_node;
-       fprintf(fp, "\t# %3ld. %s\n", i, func->lnode->param);
+       for (j = 0; j <= frame_ptr->num_tail_calls; j++)
+               fprintf(fp, "\t# %3ld. %s\n", k++, func->vname);
 
        /* outer frames except main */
        for (i = 1; i < fcall_count; i++) {
                f = fcall_list[i];
                func = f->func_node;
-               fprintf(fp, "\t# %3ld. %s\n", i, func->lnode->param);
+               for (j = 0; j <= f->num_tail_calls; j++)
+                       fprintf(fp, "\t# %3ld. %s\n", k++, func->vname);
        }
 
-       fprintf(fp, "\t# %3ld. -- main --\n", fcall_count);
+       fprintf(fp, "\t# %3ld. -- main --\n", k);
 }
 
 #endif /* PROFILING */
@@ -1111,6 +1112,7 @@ grow_stack()
                frame_ptr->type = Node_frame;
                frame_ptr->stack = NULL;
                frame_ptr->func_node = NULL;    /* in main */
+               frame_ptr->num_tail_calls = 0;
                frame_ptr->vname = NULL;
                return stack_ptr;
        }
@@ -1249,6 +1251,7 @@ calc_exp(AWKNUM x1, AWKNUM x2)
 
 /* setup_frame --- setup new frame for function call */ 
 
+
 static void
 setup_frame(INSTRUCTION *pc)
 {
@@ -1256,12 +1259,40 @@ setup_frame(INSTRUCTION *pc)
        NODE *m, *f, *fp;
        NODE **sp = NULL;
        int pcount, arg_count, i, j;
+       int tail_optimize = FALSE;
 
        f = pc->func_body;
        pcount = f->param_cnt;
        fp = f->fparms;
        arg_count = (pc + 1)->expr_count;
 
+#ifndef DEBUGGING
+       /* tail recursion optimization */
+       tail_optimize =  (do_optimize > 1 && (pc + 1)->tail_call);
+#endif
+
+       if (tail_optimize) {
+               /* free local vars of calling frame */
+
+               NODE *func;
+               int n;
+
+               func = frame_ptr->func_node;
+               for (n = func->param_cnt, sp = frame_ptr->stack; n > 0; n--) {
+                       r = *sp++;
+                       if (r->type == Node_var)     /* local variable */
+                               DEREF(r->var_value);
+                       else if (r->type == Node_var_array)     /* local array 
*/
+                               assoc_clear(r);
+               }
+               sp = frame_ptr->stack;
+
+       } else if (pcount > 0) {
+               emalloc(sp, NODE **, pcount * sizeof(NODE *), "setup_frame");
+               memset(sp, 0, pcount * sizeof(NODE *));
+       }
+
+
        /* check for extra args */ 
        if (arg_count > pcount) {
                warning(
@@ -1274,15 +1305,15 @@ setup_frame(INSTRUCTION *pc)
                } while (--arg_count > pcount);
        }
 
-       if (pcount > 0) {
-               emalloc(sp, NODE **, pcount * sizeof(NODE *), "setup_frame");
-               memset(sp, 0, pcount * sizeof(NODE *));
-       }
-
        for (i = 0, j = arg_count - 1; i < pcount; i++, j--) {
-               getnode(r);
-               memset(r, 0, sizeof(NODE));
-               sp[i] = r;
+               if (tail_optimize)
+                       r = sp[i];
+               else {
+                       getnode(r);
+                       memset(r, 0, sizeof(NODE));
+                       sp[i] = r;
+               }
+
                if (i >= arg_count) {
                        /* local variable */
                        r->type = Node_var_new;
@@ -1328,8 +1359,14 @@ setup_frame(INSTRUCTION *pc)
                }
                r->vname = fp[i].param;
        }
+
        stack_adj(-arg_count);  /* adjust stack pointer */
 
+       if (tail_optimize) {
+               frame_ptr->num_tail_calls++;
+               return;
+       }
+
        if (pc->opcode == Op_indirect_func_call) {
                r = POP();      /* indirect var */
                DEREF(r);
@@ -1345,6 +1382,7 @@ setup_frame(INSTRUCTION *pc)
        frame_ptr->type = Node_frame;   
        frame_ptr->stack = sp;
        frame_ptr->func_node = f;
+       frame_ptr->num_tail_calls = 0;
        frame_ptr->vname = NULL;
 
        frame_ptr->reti = (unsigned long) pc; /* on return execute pc->nexti */
@@ -1374,6 +1412,7 @@ restore_frame(NODE *fp)
                        assoc_clear(r);
                freenode(r);
        }
+
        if (frame_ptr->stack != NULL)
                efree(frame_ptr->stack);
        ri = (INSTRUCTION *) frame_ptr->reti; /* execution in calling frame
@@ -1651,7 +1690,7 @@ top:
                        /* avoid false source indications */
                        source = NULL;
                        sourceline = 0;
-                       (void) nextfile(&curfile, TRUE);        /* close input 
data file */ 
+                       (void) nextfile(& curfile, TRUE);       /* close input 
data file */ 
                        /*
                         * This used to be:
                         *
@@ -2404,6 +2443,7 @@ match_re:
                                f = pc->func_body;
                                if (f != NULL && STREQ(f->vname, t1->stptr)) {
                                        /* indirect var hasn't been reassigned 
*/
+
                                        goto func_call;
                                }
                                f = lookup(t1->stptr);

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog |    9 ++
 array.c   |    5 +-
 awk.h     |    5 +-
 awkgram.c |  305 +++++++++++++++++++++++++++++++++----------------------------
 awkgram.y |   37 ++++++-
 eval.c    |   70 +++++++++++---
 6 files changed, 266 insertions(+), 165 deletions(-)


hooks/post-receive
-- 
gawk



reply via email to

[Prev in Thread] Current Thread [Next in Thread]