Added two new statements: prepush and postpop. These are code blocks that are
authorthurston <thurston@052ea7fc-9027-0410-9066-f65837a77df0>
Sat, 15 Sep 2007 19:46:38 +0000 (19:46 +0000)
committerthurston <thurston@052ea7fc-9027-0410-9066-f65837a77df0>
Sat, 15 Sep 2007 19:46:38 +0000 (19:46 +0000)
written out during call and return statements immediately before pushing the
current state to the state stack on a call and immediately after popping the
current state on a return. These can be used to implement a dynamically
resizable stack. Test cases are in test/recdescent?.rl.

git-svn-id: http://svn.complang.org/ragel/trunk@280 052ea7fc-9027-0410-9066-f65837a77df0

23 files changed:
ragel.vim
ragel/parsedata.cpp
ragel/parsedata.h
ragel/rlparse.kh
ragel/rlparse.kl
ragel/rlscan.rl
ragel/xmlcodegen.cpp
redfsm/gendata.cpp
redfsm/gendata.h
redfsm/xmlparse.kh
redfsm/xmlparse.kl
redfsm/xmltags.gperf
rlgen-cd/flatcodegen.cpp
rlgen-cd/gotocodegen.cpp
rlgen-cd/ipgotocodegen.cpp
rlgen-cd/tabcodegen.cpp
rlgen-java/javacodegen.cpp
rlgen-ruby/rbx-gotocodegen.cpp
rlgen-ruby/ruby-flatcodegen.cpp
rlgen-ruby/ruby-tabcodegen.cpp
test/recdescent1.rl [new file with mode: 0644]
test/recdescent2.rl [new file with mode: 0644]
test/recdescent3.rl [new file with mode: 0644]

index b321cde..10cf395 100644 (file)
--- a/ragel.vim
+++ b/ragel.vim
@@ -98,7 +98,7 @@ syntax match rlOtherOps "<:" contained
 " Keywords
 " FIXME: Enable the range keyword post 5.17.
 " syntax keyword rlKeywords machine action context include range contained
-syntax keyword rlKeywords machine action context include import export contained
+syntax keyword rlKeywords machine action context include import export prepush postpop contained
 syntax keyword rlExprKeywords when inwhen outwhen err lerr eof from to contained
 
 " Case Labels
index 6abe995..26fb13c 100644 (file)
@@ -429,6 +429,8 @@ ParseData::ParseData( char *fileName, char *sectionName,
        alphTypeSet(false),
        getKeyExpr(0),
        accessExpr(0),
+       prePushExpr(0),
+       postPopExpr(0),
        pExpr(0),
        peExpr(0),
        csExpr(0),
index 4f8d04c..6394abf 100644 (file)
@@ -261,6 +261,10 @@ struct ParseData
        InlineList *getKeyExpr;
        InlineList *accessExpr;
 
+       /* Stack management */
+       InlineList *prePushExpr;
+       InlineList *postPopExpr;
+
        /* Overriding variables. */
        InlineList *pExpr;
        InlineList *peExpr;
index 915ca0e..6535cb6 100644 (file)
@@ -82,7 +82,7 @@ struct Parser
        token KW_Machine, KW_Include, KW_Import, KW_Write, KW_Action, KW_AlphType,
                KW_Range, KW_GetKey, KW_Include, KW_Write, KW_Machine, KW_InWhen,
                KW_When, KW_OutWhen, KW_Eof, KW_Err, KW_Lerr, KW_To, KW_From,
-               KW_Export;
+               KW_Export, KW_PrePush, KW_PostPop;
 
        # Specials in code blocks.
        token KW_Break, KW_Exec, KW_Hold, KW_PChar, KW_Char, KW_Goto, KW_Call,
index bf93978..7490a81 100644 (file)
@@ -54,6 +54,32 @@ statement: getkey_spec commit;
 statement: access_spec commit;
 statement: variable_spec commit;
 statement: export_block commit;
+statement: pre_push_spec commit;
+statement: post_pop_spec commit;
+
+pre_push_spec:
+       KW_PrePush '{' inline_block '}' 
+       final {
+               if ( pd->prePushExpr != 0 ) {
+                       /* Recover by just ignoring the duplicate. */
+                       error($2->loc) << "pre_push code already defined" << endl;
+               }
+
+               pd->prePushExpr = $3->inlineList;
+       };
+
+
+post_pop_spec:
+       KW_PostPop '{' inline_block '}' 
+       final {
+               if ( pd->postPopExpr != 0 ) {
+                       /* Recover by just ignoring the duplicate. */
+                       error($2->loc) << "post_pop code already defined" << endl;
+               }
+
+               pd->postPopExpr = $3->inlineList;
+       };
+
 
 export_open: KW_Export 
        final {
index b9b018b..ab23d86 100644 (file)
@@ -836,6 +836,8 @@ void Scanner::endSection( )
                };
                'action' => { token( KW_Action ); };
                'alphtype' => { token( KW_AlphType ); };
+               'prepush' => { token( KW_PrePush ); };
+               'postpop' => { token( KW_PostPop ); };
 
                # FIXME: Enable this post 5.17.
                # 'range' => { token( KW_Range ); };
index 54e4a2b..096e382 100644 (file)
@@ -620,6 +620,20 @@ void XMLCodeGen::writeXML()
                out << "</access>\n";
        }
 
+       /* PrePush expression. */
+       if ( pd->prePushExpr != 0 ) {
+               out << "  <prepush>";
+               writeInlineList( pd->prePushExpr );
+               out << "</prepush>\n";
+       }
+
+       /* PostPop expression. */
+       if ( pd->postPopExpr != 0 ) {
+               out << "  <postpop>";
+               writeInlineList( pd->postPopExpr );
+               out << "</postpop>\n";
+       }
+
        /*
         * Variable expressions.
         */
index dac4f6b..22dc5f9 100644 (file)
@@ -44,6 +44,8 @@ CodeGenData::CodeGenData( ostream &out )
        errState(-1),
        getKeyExpr(0),
        accessExpr(0),
+       prePushExpr(0),
+       postPopExpr(0),
        pExpr(0),
        peExpr(0),
        csExpr(0),
index d1ea1ec..52a5406 100644 (file)
@@ -101,6 +101,8 @@ struct CodeGenData
        CondSpaceList condSpaceList;
        InlineList *getKeyExpr;
        InlineList *accessExpr;
+       InlineList *prePushExpr;
+       InlineList *postPopExpr;
 
        /* Overriding variables. */
        InlineList *pExpr;
index 439ab1c..ebb98e9 100644 (file)
@@ -117,7 +117,7 @@ struct Parser
 
                token TAG_p_expr, TAG_pe_expr, TAG_cs_expr, TAG_top_expr,
                        TAG_stack_expr, TAG_act_expr, TAG_tokstart_expr, TAG_tokend_expr,
-                       TAG_data_expr;
+                       TAG_data_expr, TAG_prepush, TAG_postpop;
        }%%
 
        %% write instance_data;
index 8bf526f..b9d167f 100644 (file)
@@ -159,6 +159,8 @@ ragel_def_item_list: ;
 ragel_def_item: tag_alph_type;
 ragel_def_item: tag_getkey_expr;
 ragel_def_item: tag_access_expr;
+ragel_def_item: tag_prepush_expr;
+ragel_def_item: tag_postpop_expr;
 ragel_def_item: tag_export_list;
 ragel_def_item: tag_machine;
 ragel_def_item: tag_p_expr;
@@ -204,6 +206,16 @@ tag_access_expr: TAG_access inline_list '/' TAG_access
                cgd->accessExpr = $2->inlineList;
        };
 
+tag_prepush_expr: TAG_prepush inline_list '/' TAG_prepush
+       final {
+               cgd->prePushExpr = $2->inlineList;
+       };
+
+tag_postpop_expr: TAG_postpop inline_list '/' TAG_postpop
+       final {
+               cgd->postPopExpr = $2->inlineList;
+       };
+
 tag_p_expr: TAG_p_expr inline_list '/' TAG_p_expr
        final { cgd->pExpr = $2->inlineList; };
 tag_pe_expr: TAG_pe_expr inline_list '/' TAG_pe_expr
index 4a5b840..754001f 100644 (file)
@@ -88,3 +88,5 @@ act_expr, TAG_act_expr
 tokstart_expr, TAG_tokstart_expr
 tokend_expr, TAG_tokend_expr
 data_expr, TAG_data_expr
+prepush, TAG_prepush
+postpop, TAG_postpop
index f2712dd..36fb0d9 100644 (file)
@@ -461,23 +461,46 @@ void FlatCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
 
 void FlatCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
 {
+       if ( prePushExpr != 0 ) {
+               ret << "{";
+               INLINE_LIST( ret, prePushExpr, 0, false );
+       }
+
        ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " << 
                        callDest << "; " << CTRL_FLOW() << "goto _again;}";
+
+       if ( prePushExpr != 0 )
+               ret << "}";
 }
 
 
 void FlatCodeGen::CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish )
 {
+       if ( prePushExpr != 0 ) {
+               ret << "{";
+               INLINE_LIST( ret, prePushExpr, 0, false );
+       }
+
        ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
        INLINE_LIST( ret, ilItem->children, targState, inFinish );
        ret << "); " << CTRL_FLOW() << "goto _again;}";
+
+       if ( prePushExpr != 0 )
+               ret << "}";
 }
 
 
 void FlatCodeGen::RET( ostream &ret, bool inFinish )
 {
-       ret << "{" << CS() << " = " << STACK() << "[--" << TOP() << "]; " << 
-                       CTRL_FLOW() << "goto _again;}";
+       ret << "{" << CS() << " = " << STACK() << "[--" << TOP() << "];";
+
+       if ( postPopExpr != 0 ) {
+               ret << "{";
+               INLINE_LIST( ret, postPopExpr, 0, false );
+               ret << "}";
+       }
+
+       ret << CTRL_FLOW() << "goto _again;}";
 }
 
 void FlatCodeGen::BREAK( ostream &ret, int targState )
index 0f5e92f..89f3107 100644 (file)
@@ -578,21 +578,44 @@ void GotoCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
 
 void GotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
 {
+       if ( prePushExpr != 0 ) {
+               ret << "{";
+               INLINE_LIST( ret, prePushExpr, 0, false );
+       }
+
        ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " << 
                        callDest << "; " << CTRL_FLOW() << "goto _again;}";
+
+       if ( prePushExpr != 0 )
+               ret << "}";
 }
 
 void GotoCodeGen::CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish )
 {
+       if ( prePushExpr != 0 ) {
+               ret << "{";
+               INLINE_LIST( ret, prePushExpr, 0, false );
+       }
+
        ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
        INLINE_LIST( ret, ilItem->children, targState, inFinish );
        ret << "); " << CTRL_FLOW() << "goto _again;}";
+
+       if ( prePushExpr != 0 )
+               ret << "}";
 }
 
 void GotoCodeGen::RET( ostream &ret, bool inFinish )
 {
-       ret << "{" << CS() << " = " << STACK() << "[--" << TOP() << "]; " << 
-                       CTRL_FLOW() << "goto _again;}";
+       ret << "{" << CS() << " = " << STACK() << "[--" << TOP() << "];";
+
+       if ( postPopExpr != 0 ) {
+               ret << "{";
+               INLINE_LIST( ret, postPopExpr, 0, false );
+               ret << "}";
+       }
+
+       ret << CTRL_FLOW() << "goto _again;}";
 }
 
 void GotoCodeGen::BREAK( ostream &ret, int targState )
index 4e55e1f..d7cb931 100644 (file)
@@ -41,26 +41,49 @@ void IpGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
 
 void IpGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
 {
+       if ( prePushExpr != 0 ) {
+               ret << "{";
+               INLINE_LIST( ret, prePushExpr, 0, false );
+       }
+
        ret << "{" << STACK() << "[" << TOP() << "++] = " << targState << 
                        "; " << CTRL_FLOW() << "goto st" << callDest << ";}";
-}
 
-void IpGotoCodeGen::RET( ostream &ret, bool inFinish )
-{
-       ret << "{" << CS() << " = " << STACK() << "[--" << TOP() << "]; " << 
-                       CTRL_FLOW() << "goto _again;}";
+       if ( prePushExpr != 0 )
+               ret << "}";
 }
 
-void IpGotoCodeGen::GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
+void IpGotoCodeGen::CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish )
 {
-       ret << "{" << CS() << " = (";
+       if ( prePushExpr != 0 ) {
+               ret << "{";
+               INLINE_LIST( ret, prePushExpr, 0, false );
+       }
+
+       ret << "{" << STACK() << "[" << TOP() << "++] = " << targState << "; " << CS() << " = (";
        INLINE_LIST( ret, ilItem->children, 0, inFinish );
        ret << "); " << CTRL_FLOW() << "goto _again;}";
+
+       if ( prePushExpr != 0 )
+               ret << "}";
 }
 
-void IpGotoCodeGen::CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish )
+void IpGotoCodeGen::RET( ostream &ret, bool inFinish )
 {
-       ret << "{" << STACK() << "[" << TOP() << "++] = " << targState << "; " << CS() << " = (";
+       ret << "{" << CS() << " = " << STACK() << "[--" << TOP() << "];";
+
+       if ( postPopExpr != 0 ) {
+               ret << "{";
+               INLINE_LIST( ret, postPopExpr, 0, false );
+               ret << "}";
+       }
+
+       ret << CTRL_FLOW() << "goto _again;}";
+}
+
+void IpGotoCodeGen::GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
+{
+       ret << "{" << CS() << " = (";
        INLINE_LIST( ret, ilItem->children, 0, inFinish );
        ret << "); " << CTRL_FLOW() << "goto _again;}";
 }
index 8c39825..7dccb4d 100644 (file)
@@ -651,21 +651,45 @@ void TabCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish )
 
 void TabCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
 {
+       if ( prePushExpr != 0 ) {
+               ret << "{";
+               INLINE_LIST( ret, prePushExpr, 0, false );
+       }
+
        ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " << 
                        callDest << "; " << CTRL_FLOW() << "goto _again;}";
+
+       if ( prePushExpr != 0 )
+               ret << "}";
 }
 
 void TabCodeGen::CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish )
 {
+       if ( prePushExpr != 0 ) {
+               ret << "{";
+               INLINE_LIST( ret, prePushExpr, 0, false );
+       }
+
        ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
        INLINE_LIST( ret, ilItem->children, targState, inFinish );
        ret << "); " << CTRL_FLOW() << "goto _again;}";
+
+       if ( prePushExpr != 0 )
+               ret << "}";
 }
 
 void TabCodeGen::RET( ostream &ret, bool inFinish )
 {
        ret << "{" << CS() << " = " << STACK() << "[--" << 
-                       TOP() << "]; " << CTRL_FLOW() <<  "goto _again;}";
+                       TOP() << "]; ";
+
+       if ( postPopExpr != 0 ) {
+               ret << "{";
+               INLINE_LIST( ret, postPopExpr, 0, false );
+               ret << "}";
+       }
+
+       ret << CTRL_FLOW() <<  "goto _again;}";
 }
 
 void TabCodeGen::BREAK( ostream &ret, int targState )
index e288d32..9b65c95 100644 (file)
@@ -75,21 +75,44 @@ void JavaTabCodeGen::GOTO_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish
 
 void JavaTabCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
 {
+       if ( prePushExpr != 0 ) {
+               ret << "{";
+               INLINE_LIST( ret, prePushExpr, 0, false );
+       }
+
        ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " << 
                        callDest << "; " << CTRL_FLOW() << "break _again;}";
+
+       if ( prePushExpr != 0 )
+               ret << "}";
 }
 
 void JavaTabCodeGen::CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish )
 {
+       if ( prePushExpr != 0 ) {
+               ret << "{";
+               INLINE_LIST( ret, prePushExpr, 0, false );
+       }
+
        ret << "{" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
        INLINE_LIST( ret, ilItem->children, targState, inFinish );
        ret << "); " << CTRL_FLOW() << "break _again;}";
+
+       if ( prePushExpr != 0 )
+               ret << "}";
 }
 
 void JavaTabCodeGen::RET( ostream &ret, bool inFinish )
 {
-       ret << "{" << CS() << " = " << STACK() << "[--" << TOP() 
-                       << "]; " << CTRL_FLOW() << "break _again;}";
+       ret << "{" << CS() << " = " << STACK() << "[--" << TOP() << "];";
+
+       if ( postPopExpr != 0 ) {
+               ret << "{";
+               INLINE_LIST( ret, postPopExpr, 0, false );
+               ret << "}";
+       }
+
+       ret << CTRL_FLOW() << "break _again;}";
 }
 
 void JavaTabCodeGen::BREAK( ostream &ret, int targState )
index 65f5a55..d6ba375 100644 (file)
@@ -600,25 +600,48 @@ void RbxGotoCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish
 
 void RbxGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
 {
+       if ( prePushExpr != 0 ) {
+               ret << "{";
+               INLINE_LIST( ret, prePushExpr, 0, false );
+       }
+
        ret << "begin\n" 
            << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = " << 
                callDest << "; ";
        rbxGoto(ret, "_again") << 
                "\nend\n";
+
+       if ( prePushExpr != 0 )
+               ret << "}";
 }
 
 void RbxGotoCodeGen::CALL_EXPR( ostream &ret, InlineItem *ilItem, int targState, bool inFinish )
 {
+       if ( prePushExpr != 0 ) {
+               ret << "{";
+               INLINE_LIST( ret, prePushExpr, 0, false );
+       }
+
        ret << "begin\n" << STACK() << "[" << TOP() << "++] = " << CS() << "; " << CS() << " = (";
        INLINE_LIST( ret, ilItem->children, targState, inFinish );
        ret << "); ";
        rbxGoto(ret, "_again") << 
                "\nend\n";
+
+       if ( prePushExpr != 0 )
+               ret << "}";
 }
 
 void RbxGotoCodeGen::RET( ostream &ret, bool inFinish )
 {
        ret << "begin\n" << CS() << " = " << STACK() << "[--" << TOP() << "]; " ;
+
+       if ( postPopExpr != 0 ) {
+               ret << "{";
+               INLINE_LIST( ret, postPopExpr, 0, false );
+               ret << "}";
+       }
+
        rbxGoto(ret, "_again") << 
                "\nend\n";
 }
index eebca6e..9bbed39 100644 (file)
@@ -392,6 +392,11 @@ void RubyFlatCodeGen::GOTO( ostream &out, int gotoDest, bool inFinish )
 
 void RubyFlatCodeGen::CALL( ostream &out, int callDest, int targState, bool inFinish )
 {
+       if ( prePushExpr != 0 ) {
+               out << "begin\n";
+               INLINE_LIST( out, prePushExpr, 0, false );
+       }
+
        out <<
                "       begin\n"
                "               " << STACK() << "[" << TOP() << "] = " << CS() << "\n"
@@ -400,6 +405,52 @@ void RubyFlatCodeGen::CALL( ostream &out, int callDest, int targState, bool inFi
                "               _break_again = true\n"
                "               break\n" // break _again
                "       end\n";
+
+       if ( prePushExpr != 0 )
+               out << "end\n";
+}
+
+void RubyFlatCodeGen::CALL_EXPR(ostream &out, InlineItem *ilItem, int targState, bool inFinish )
+{
+       if ( prePushExpr != 0 ) {
+               out << "begin\n";
+               INLINE_LIST( out, prePushExpr, 0, false );
+       }
+
+       out <<
+               "       begin\n"
+               "               " << STACK() << "[" << TOP() << "] = " << CS() << "\n"
+               "               " << TOP() << " += 1\n"
+               "               " << CS() << " = (";
+       INLINE_LIST( out, ilItem->children, targState, inFinish );
+       out << ")\n";
+
+       out << 
+               "               _break_again = true\n"
+               "               break\n" // break _again
+               "       end\n";
+
+       if ( prePushExpr != 0 )
+               out << "end\n";
+}
+
+void RubyFlatCodeGen::RET( ostream &out, bool inFinish )
+{
+       out <<
+               "       begin\n"
+               "               " << TOP() << " -= 1\n"
+               "               " << CS() << " = " << STACK() << "[" << TOP() << "]\n";
+
+       if ( postPopExpr != 0 ) {
+               out << "begin\n";
+               INLINE_LIST( out, postPopExpr, 0, false );
+               out << "end\n";
+       }
+
+       out <<
+               "               _break_again = true\n"
+               "               break\n" // break _again
+               "       end\n";
 }
 
 void RubyFlatCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
@@ -428,22 +479,6 @@ void RubyFlatCodeGen::NEXT_EXPR( ostream &ret, InlineItem *ilItem, bool inFinish
 }
 
 
-void RubyFlatCodeGen::CALL_EXPR(ostream &out, InlineItem *ilItem, int targState, bool inFinish )
-{
-       out <<
-               "       begin\n"
-               "               " << STACK() << "[" << TOP() << "] = " << CS() << "\n"
-               "               " << TOP() << " += 1\n"
-               "               " << CS() << " = (";
-       INLINE_LIST( out, ilItem->children, targState, inFinish );
-       out << ")\n";
-
-       out << 
-               "               _break_again = true\n"
-               "               break\n" // break _again
-               "       end\n";
-}
-
 void RubyFlatCodeGen::CURS( ostream &ret, bool inFinish )
 {
        ret << "(_ps)";
@@ -454,17 +489,6 @@ void RubyFlatCodeGen::TARGS( ostream &ret, bool inFinish, int targState )
        ret << "(" << CS() << ")";
 }
 
-void RubyFlatCodeGen::RET( ostream &out, bool inFinish )
-{
-       out <<
-               "       begin\n"
-               "               " << TOP() << " -= 1\n"
-               "               " << CS() << " = " << STACK() << "[" << TOP() << "]\n"
-               "               _break_again = true\n"
-               "               break\n" // break _again
-               "       end\n";
-}
-
 void RubyFlatCodeGen::BREAK( ostream &out, int targState )
 {
        out << 
index c037730..c307e45 100644 (file)
@@ -60,6 +60,11 @@ void RubyTabCodeGen::GOTO_EXPR( ostream &out, InlineItem *ilItem, bool inFinish
 
 void RubyTabCodeGen::CALL( ostream &out, int callDest, int targState, bool inFinish )
 {
+       if ( prePushExpr != 0 ) {
+               out << "begin\n";
+               INLINE_LIST( out, prePushExpr, 0, false );
+       }
+
        out <<
                "       begin\n"
                "               " << STACK() << "[" << TOP() << "] = " << CS() << "\n"
@@ -68,10 +73,18 @@ void RubyTabCodeGen::CALL( ostream &out, int callDest, int targState, bool inFin
                "               _break_again = true\n"
                "               break\n" // break _again
                "       end\n";
+
+       if ( prePushExpr != 0 )
+               out << "end\n";
 }
 
 void RubyTabCodeGen::CALL_EXPR(ostream &out, InlineItem *ilItem, int targState, bool inFinish )
 {
+       if ( prePushExpr != 0 ) {
+               out << "begin\n";
+               INLINE_LIST( out, prePushExpr, 0, false );
+       }
+
        out <<
                "       begin\n"
                "               " << STACK() << "[" << TOP() << "] = " << CS() << "\n"
@@ -84,6 +97,9 @@ void RubyTabCodeGen::CALL_EXPR(ostream &out, InlineItem *ilItem, int targState,
                "               _break_again = true\n"
                "               break\n" // break _again
                "       end\n";
+
+       if ( prePushExpr != 0 )
+               out << "end\n";
 }
 
 void RubyTabCodeGen::RET( ostream &out, bool inFinish )
@@ -91,7 +107,15 @@ void RubyTabCodeGen::RET( ostream &out, bool inFinish )
        out <<
                "       begin\n"
                "               " << TOP() << " -= 1\n"
-               "               " << CS() << " = " << STACK() << "[" << TOP() << "]\n"
+               "               " << CS() << " = " << STACK() << "[" << TOP() << "]\n";
+
+       if ( postPopExpr != 0 ) {
+               out << "begin\n";
+               INLINE_LIST( out, postPopExpr, 0, false );
+               out << "end\n";
+       }
+
+       out <<
                "               _break_again = true\n"
                "               break\n" // break _again
                "       end\n";
diff --git a/test/recdescent1.rl b/test/recdescent1.rl
new file mode 100644 (file)
index 0000000..c184ba7
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * @LANG: c
+ * Test growable stack.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+%%{
+       machine recdescent;
+
+       prepush { 
+               if ( top == stack_size ) {
+                       printf( "growing stack\n" );
+                       stack_size = top * 2;
+                       stack = (int*)realloc( stack, sizeof(int)*stack_size );
+               }
+       }
+
+       postpop { 
+               if ( stack_size > (top * 4) ) {
+                       stack_size = top * 2;
+                       stack = (int*)realloc( stack, sizeof(int)*stack_size );
+                       printf( "shrinking stack\n" );
+               }
+       }
+
+       action item_start { item = p; }
+
+       action item_finish
+       {
+               printf( "item: " );
+               fwrite( item, 1, p-item, stdout );
+               printf( "\n" );
+       }
+
+       action call_main
+       {
+               printf( "calling main\n" );
+               fcall main;
+       }
+
+       action return_main
+       {
+               if ( top == 0 ) {
+                       printf( "STRAY CLOSE\n" );
+                       fbreak;
+               }
+
+               printf( "returning from main\n" );
+               fhold;
+               fret;
+       }
+
+       id = [a-zA-Z_]+;
+       number = [0-9]+;
+       ws = [ \t\n]+;
+
+       main := ( 
+               ws |
+               ( number | id ) >item_start %item_finish |
+
+               '{' @call_main '}' |
+
+               '}' @return_main
+       )**;
+}%%
+
+%% write data;
+
+void test( char *buf )
+{
+       int cs;
+       int *stack;
+       int top, stack_size;
+       char *p, *pe, *item = 0;
+
+       int len = strlen( buf );
+
+       %% write init;
+
+       stack_size = 1;
+       stack = (int*)malloc( sizeof(int) * stack_size );
+
+       p = buf;
+       pe = buf + len;
+
+       %% write exec;
+       %% write eof;
+
+       if ( cs == recdescent_error ) {
+               /* Machine failed before finding a token. */
+               printf( "PARSE ERROR\n" );
+       }
+}
+
+int main()
+{
+       test( "88 foo { 99 {{{{}}}}{ } }");
+       test( "76 } sadf");
+       return 0;
+}
+
+#ifdef _____OUTPUT_____
+item: 88
+item: foo
+calling main
+item: 99
+calling main
+growing stack
+calling main
+growing stack
+calling main
+calling main
+growing stack
+returning from main
+returning from main
+returning from main
+returning from main
+shrinking stack
+calling main
+returning from main
+returning from main
+shrinking stack
+item: 76
+STRAY CLOSE
+#endif
diff --git a/test/recdescent2.rl b/test/recdescent2.rl
new file mode 100644 (file)
index 0000000..2f3ef80
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * @LANG: java
+ */
+
+class recdescent2
+{
+       %%{
+               machine recdescent;
+
+               prepush { 
+                       if ( top == stack_size ) {
+                               System.out.print( "growing stack\n" );
+                               stack_size = top * 2;
+                               // Don't actually bother to resize here, but we do print messages.
+                               //stack = (int*)realloc( stack, sizeof(int)*stack_size );
+                       }
+               }
+
+               postpop { 
+                       if ( stack_size > (top * 4) ) {
+                               stack_size = top * 2;
+                               // Don't actually bother to resize here, but we do print messages.
+                               //stack = (int*)realloc( stack, sizeof(int)*stack_size );
+                               System.out.print( "shrinking stack\n" );
+                       }
+               }
+
+               action item_start { item = p; }
+
+               action item_finish
+               {
+                       String item_data = new String ( data, item, p-item );
+                       System.out.print( "item: " );
+                       System.out.print( item_data );
+                       System.out.print( "\n" );
+               }
+
+               action call_main
+               {
+                       System.out.print( "calling main\n" );
+                       fcall main;
+               }
+
+               action return_main
+               {
+                       if ( top == 0 ) {
+                               System.out.print( "STRAY CLOSE\n" );
+                               fbreak;
+                       }
+
+                       System.out.print( "returning from main\n" );
+                       fhold;
+                       fret;
+               }
+
+               id = [a-zA-Z_]+;
+               number = [0-9]+;
+               ws = [ \t\n]+;
+
+               main := ( 
+                       ws |
+                       ( number | id ) >item_start %item_finish |
+
+                       '{' @call_main '}' |
+
+                       '}' @return_main
+               )**;
+       }%%
+
+       %% write data;
+
+       static void test( char data[] )
+       {
+               int cs, p = 0, pe = data.length, item = 0;
+               int stack[] = new int[1024];
+               int stack_size = 1;
+               int top;
+
+               %% write init;
+               %% write exec;
+               %% write eof;
+
+               if ( cs == recdescent_error )
+                       System.out.println( "SCANNER ERROR" );
+       }
+
+       public static void main( String args[] )
+       {
+               test( "88 foo { 99 {{{{}}}}{ } }".toCharArray() );
+               test( "76 } sadf".toCharArray() );
+       }
+}
+
+/* _____OUTPUT_____
+item: 88
+item: foo
+calling main
+item: 99
+calling main
+growing stack
+calling main
+growing stack
+calling main
+calling main
+growing stack
+returning from main
+returning from main
+returning from main
+returning from main
+shrinking stack
+calling main
+returning from main
+returning from main
+shrinking stack
+item: 76
+STRAY CLOSE
+*/
diff --git a/test/recdescent3.rl b/test/recdescent3.rl
new file mode 100644 (file)
index 0000000..35a8e08
--- /dev/null
@@ -0,0 +1,117 @@
+#
+# @LANG: ruby
+#
+
+%%{
+    machine recdescent3;
+
+       prepush { 
+               if top == stack_size
+                       print( "growing stack\n" );
+                       stack_size = top * 2;
+                       # Don't actually bother to resize here, but we do print messages.
+                       # stack = (int*)realloc( stack, sizeof(int)*stack_size );
+               end 
+       }
+
+       postpop { 
+               if stack_size > (top * 4)
+                       print( "shrinking stack\n" );
+                       stack_size = top * 2;
+                       # Don't actually bother to resize here, but we do print messages.
+                       # stack = (int*)realloc( stack, sizeof(int)*stack_size );
+               end
+       }
+
+       action item_start { item = p; }
+
+       action item_finish
+       {
+               print( "item: " );
+               print( data[item..p-1] );
+               print( "\n" );
+       }
+
+       action call_main
+       {
+               print( "calling main\n" );
+               fcall main;
+       }
+
+       action return_main
+       {
+               if top == 0 
+                       print( "STRAY CLOSE\n" );
+                       fbreak;
+               end
+
+               print( "returning from main\n" );
+               fhold;
+               fret;
+       }
+
+       id = [a-zA-Z_]+;
+       number = [0-9]+;
+       ws = [ \t\n]+;
+
+       main := ( 
+               ws |
+               ( number | id ) >item_start %item_finish |
+
+               '{' @call_main '}' |
+
+               '}' @return_main
+       )**;
+}%%
+
+%% write data;
+
+def run_machine( data )
+       item = 0;
+       p = 0;
+       pe = data.length;
+       cs = 0;
+       stack = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
+       stack_size = 1;
+       top = 0;
+
+       %% write init;
+       %% write exec;
+       %% write eof;
+
+       if cs == recdescent3_error
+               puts "SCANNER_ERROR"
+       end
+end
+
+inp = [
+               "88 foo { 99 {{{{}}}}{ } }",
+               "76 } sadf"
+]
+
+inp.each { |str| run_machine(str) }
+
+=begin _____OUTPUT_____
+item: 88
+item: foo
+calling main
+item: 99
+calling main
+growing stack
+calling main
+growing stack
+calling main
+calling main
+growing stack
+returning from main
+returning from main
+returning from main
+returning from main
+shrinking stack
+calling main
+returning from main
+returning from main
+shrinking stack
+item: 76
+STRAY CLOSE
+=end _____OUTPUT_____