summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Thurston <thurston@colm.net>2017-03-23 12:38:32 +0800
committerAdrian Thurston <thurston@colm.net>2017-03-23 15:20:56 +0800
commit284f1fb0ba7c2a5de6439761f0df0cc74f96e8b8 (patch)
tree622cfa41b4469dafd19ae7ad187fc9e33aab559a
parentd9abbd783a2d4a6de7a65d94ce61b30eb10d0735 (diff)
downloadragel-284f1fb0ba7c2a5de6439761f0df0cc74f96e8b8.tar.gz
C codegen: test p VS pe in goto/call/ret in EOF actions
If an fgoto, fcall or fret is issued in an EOF action check p VS pe before continuing. If at the end of the block then re-issue the eof test. If a program properly issues an fhold before the control flow the program won't be affected. If the user neglects to do this we won't run off the end of the buffer.
-rw-r--r--ragel/cdcodegen.cpp8
-rw-r--r--ragel/cdcodegen.h2
-rw-r--r--ragel/cdflat.cpp52
-rw-r--r--ragel/cdgoto.cpp56
-rw-r--r--ragel/cdipgoto.cpp67
-rw-r--r--ragel/cdipgoto.h2
-rw-r--r--ragel/cdtable.cpp54
-rw-r--r--ragel/cstable.cpp41
-rw-r--r--test/eofcall1.rl138
-rw-r--r--test/eofcall2.rl138
-rw-r--r--test/eofgoto1.rl137
-rw-r--r--test/eofgoto2.rl138
-rw-r--r--test/eofret1.rl141
13 files changed, 930 insertions, 44 deletions
diff --git a/ragel/cdcodegen.cpp b/ragel/cdcodegen.cpp
index c2f1381c..96d85010 100644
--- a/ragel/cdcodegen.cpp
+++ b/ragel/cdcodegen.cpp
@@ -361,6 +361,14 @@ string FsmCodeGen::WIDE_KEY( RedStateAp *state, Key key )
}
}
+void FsmCodeGen::EOF_CHECK( ostream &ret )
+{
+ ret <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _test_eof;\n";
+
+ testEofUsed = true;
+}
void FsmCodeGen::EXEC( ostream &ret, GenInlineItem *item, int targState, int inFinish )
diff --git a/ragel/cdcodegen.h b/ragel/cdcodegen.h
index d8fe62dd..b9a84906 100644
--- a/ragel/cdcodegen.h
+++ b/ragel/cdcodegen.h
@@ -131,6 +131,8 @@ protected:
string FIRST_FINAL() { return DATA_PREFIX() + "first_final"; }
string CTXDATA() { return DATA_PREFIX() + "ctxdata"; }
+ void EOF_CHECK( ostream &ret );
+
void INLINE_LIST( ostream &ret, GenInlineList *inlineList,
int targState, bool inFinish, bool csForced );
virtual void GOTO( ostream &ret, int gotoDest, bool inFinish ) = 0;
diff --git a/ragel/cdflat.cpp b/ragel/cdflat.cpp
index 6010f980..b28a95a6 100644
--- a/ragel/cdflat.cpp
+++ b/ragel/cdflat.cpp
@@ -454,15 +454,32 @@ void FlatCodeGen::LOCATE_TRANS()
void FlatCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
{
- ret << "{" << vCS() << " = " << gotoDest << "; " <<
- CTRL_FLOW() << "goto _again;}";
+ ret << "{";
+
+ ret << vCS() << " = " << gotoDest << ";";
+
+ if ( inFinish && !noEnd )
+ EOF_CHECK( ret );
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
}
void FlatCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
{
- ret << "{" << vCS() << " = (";
+ ret << "{";
+
+ ret << vCS() << " = (";
INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
- ret << "); " << CTRL_FLOW() << "goto _again;}";
+ ret << "); ";
+
+ if ( inFinish && !noEnd )
+ EOF_CHECK( ret );
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
}
void FlatCodeGen::CURS( ostream &ret, bool inFinish )
@@ -494,8 +511,16 @@ void FlatCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish
INLINE_LIST( ret, prePushExpr, 0, false, false );
}
- ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " <<
- callDest << "; " << CTRL_FLOW() << "goto _again;}";
+ ret << "{";
+
+ ret << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " << callDest << ";";
+
+ if ( inFinish && !noEnd )
+ EOF_CHECK( ret );
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
if ( prePushExpr != 0 )
ret << "}";
@@ -511,7 +536,13 @@ void FlatCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState,
ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = (";
INLINE_LIST( ret, ilItem->children, targState, inFinish, false );
- ret << "); " << CTRL_FLOW() << "goto _again;}";
+ ret << ");";
+
+ if ( inFinish && !noEnd )
+ EOF_CHECK( ret );
+
+ ret << CTRL_FLOW() << "goto _again;";
+ ret << "}";
if ( prePushExpr != 0 )
ret << "}";
@@ -528,7 +559,12 @@ void FlatCodeGen::RET( ostream &ret, bool inFinish )
ret << "}";
}
- ret << CTRL_FLOW() << "goto _again;}";
+ if ( inFinish && !noEnd )
+ EOF_CHECK( ret );
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
}
void FlatCodeGen::BREAK( ostream &ret, int targState, bool csForced )
diff --git a/ragel/cdgoto.cpp b/ragel/cdgoto.cpp
index e434143a..86b3d23f 100644
--- a/ragel/cdgoto.cpp
+++ b/ragel/cdgoto.cpp
@@ -543,15 +543,32 @@ std::ostream &GotoCodeGen::FINISH_CASES()
void GotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
{
- ret << "{" << vCS() << " = " << gotoDest << "; " <<
- CTRL_FLOW() << "goto _again;}";
+ ret << "{";
+
+ ret << vCS() << " = " << gotoDest << ";";
+
+ if ( inFinish && !noEnd )
+ EOF_CHECK( ret );
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
}
void GotoCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
{
- ret << "{" << vCS() << " = (";
+ ret << "{";
+
+ ret << vCS() << " = (";
INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
- ret << "); " << CTRL_FLOW() << "goto _again;}";
+ ret << ");";
+
+ if ( inFinish && !noEnd )
+ EOF_CHECK( ret );
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
}
void GotoCodeGen::CURS( ostream &ret, bool inFinish )
@@ -583,8 +600,16 @@ void GotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish
INLINE_LIST( ret, prePushExpr, 0, false, false );
}
- ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " <<
- callDest << "; " << CTRL_FLOW() << "goto _again;}";
+ ret << "{";
+
+ ret << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " << callDest << ";";
+
+ if ( inFinish && !noEnd )
+ EOF_CHECK( ret );
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
if ( prePushExpr != 0 )
ret << "}";
@@ -597,9 +622,18 @@ void GotoCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState,
INLINE_LIST( ret, prePushExpr, 0, false, false );
}
- ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = (";
+ ret << "{";
+
+ ret << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = (";
INLINE_LIST( ret, ilItem->children, targState, inFinish, false );
- ret << "); " << CTRL_FLOW() << "goto _again;}";
+ ret << ");";
+
+ if ( inFinish && !noEnd )
+ EOF_CHECK( ret );
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
if ( prePushExpr != 0 )
ret << "}";
@@ -615,7 +649,11 @@ void GotoCodeGen::RET( ostream &ret, bool inFinish )
ret << "}";
}
- ret << CTRL_FLOW() << "goto _again;}";
+ if ( inFinish && !noEnd )
+ EOF_CHECK( ret );
+
+ ret << CTRL_FLOW() << "goto _again;";
+ ret << "}";
}
void GotoCodeGen::BREAK( ostream &ret, int targState, bool csForced )
diff --git a/ragel/cdipgoto.cpp b/ragel/cdipgoto.cpp
index 3abbfbe2..05c92994 100644
--- a/ragel/cdipgoto.cpp
+++ b/ragel/cdipgoto.cpp
@@ -34,9 +34,25 @@ bool IpGotoCodeGen::useAgainLabel()
redFsm->anyRegNextStmt();
}
+void IpGotoCodeGen::EOF_CHECK( ostream &ret, int gotoDest )
+{
+ ret <<
+ " if ( " << P() << " == " << PE() << " )\n"
+ " goto _test_eof" << gotoDest << ";\n";
+
+ testEofUsed = true;
+}
+
void IpGotoCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
{
- ret << "{" << CTRL_FLOW() << "goto st" << gotoDest << ";}";
+ ret << "{";
+
+ if ( inFinish && !noEnd )
+ EOF_CHECK( ret, gotoDest );
+
+ ret << CTRL_FLOW() << "goto st" << gotoDest << ";";
+
+ ret << "}";
}
void IpGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish )
@@ -46,8 +62,14 @@ void IpGotoCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFini
INLINE_LIST( ret, prePushExpr, 0, false, false );
}
- ret << "{" << STACK() << "[" << TOP() << "++] = " << targState <<
- "; " << CTRL_FLOW() << "goto st" << callDest << ";}";
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << targState << ";";
+
+ if ( inFinish && !noEnd )
+ EOF_CHECK( ret, callDest );
+
+ ret << CTRL_FLOW() << "goto st" << callDest << ";";
+
+ ret << "}";
if ( prePushExpr != 0 )
ret << "}";
@@ -60,9 +82,18 @@ void IpGotoCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targStat
INLINE_LIST( ret, prePushExpr, 0, false, false );
}
- ret << "{" << STACK() << "[" << TOP() << "++] = " << targState << "; " << vCS() << " = (";
+ ret << "{";
+
+ ret << STACK() << "[" << TOP() << "++] = " << targState << "; " << vCS() << " = (";
INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
- ret << "); " << CTRL_FLOW() << "goto _again;}";
+ ret << ");";
+
+ if ( inFinish && !noEnd )
+ FsmCodeGen::EOF_CHECK( ret );
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
if ( prePushExpr != 0 )
ret << "}";
@@ -78,14 +109,27 @@ void IpGotoCodeGen::RET( ostream &ret, bool inFinish )
ret << "}";
}
- ret << CTRL_FLOW() << "goto _again;}";
+ if ( inFinish && !noEnd )
+ FsmCodeGen::EOF_CHECK( ret );
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
}
void IpGotoCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
{
- ret << "{" << vCS() << " = (";
+ ret << "{";
+
+ ret << vCS() << " = (";
INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
- ret << "); " << CTRL_FLOW() << "goto _again;}";
+ ret << ");";
+
+ if ( inFinish && !noEnd )
+ FsmCodeGen::EOF_CHECK( ret );
+
+ ret << CTRL_FLOW() << "goto _again;";
+ ret << "}";
}
void IpGotoCodeGen::NEXT( ostream &ret, int nextDest, bool inFinish )
@@ -350,6 +394,13 @@ void IpGotoCodeGen::setLabelsNeeded()
}
}
}
+
+ for ( RedStateList::Iter st = redFsm->stateList; st.lte(); st++ ) {
+ if ( st->eofAction != 0 ) {
+ for ( GenActionTable::Iter item = st->eofAction->key; item.lte(); item++ )
+ setLabelsNeeded( item->value->inlineList );
+ }
+ }
}
if ( !noEnd ) {
diff --git a/ragel/cdipgoto.h b/ragel/cdipgoto.h
index c869e1f9..4e92926e 100644
--- a/ragel/cdipgoto.h
+++ b/ragel/cdipgoto.h
@@ -60,6 +60,8 @@ public:
protected:
bool useAgainLabel();
+ void EOF_CHECK( ostream &ret, int gotoDest );
+
/* Called from GotoCodeGen::STATE_GOTOS just before writing the gotos for
* each state. */
bool IN_TRANS_ACTIONS( RedStateAp *state );
diff --git a/ragel/cdtable.cpp b/ragel/cdtable.cpp
index 2218839e..6bcb79ea 100644
--- a/ragel/cdtable.cpp
+++ b/ragel/cdtable.cpp
@@ -666,15 +666,31 @@ void TabCodeGen::LOCATE_TRANS()
void TabCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
{
- ret << "{" << vCS() << " = " << gotoDest << "; " <<
- CTRL_FLOW() << "goto _again;}";
+ ret << "{";
+
+ ret << vCS() << " = " << gotoDest << ";";
+
+ if ( inFinish && !noEnd )
+ EOF_CHECK( ret );
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
}
void TabCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
{
- ret << "{" << vCS() << " = (";
+ ret << "{";
+ ret << vCS() << " = (";
INLINE_LIST( ret, ilItem->children, 0, inFinish, false );
- ret << "); " << CTRL_FLOW() << "goto _again;}";
+ ret << "); ";
+
+ if ( inFinish && !noEnd )
+ EOF_CHECK( ret );
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
}
void TabCodeGen::CURS( ostream &ret, bool inFinish )
@@ -706,8 +722,14 @@ void TabCodeGen::CALL( ostream &ret, int callDest, int targState, bool inFinish
INLINE_LIST( ret, prePushExpr, 0, false, false );
}
- ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " <<
- callDest << "; " << CTRL_FLOW() << "goto _again;}";
+ ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " << callDest << ";";
+
+ if ( inFinish && !noEnd )
+ EOF_CHECK( ret );
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
if ( prePushExpr != 0 )
ret << "}";
@@ -720,9 +742,18 @@ void TabCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targState,
INLINE_LIST( ret, prePushExpr, 0, false, false );
}
- ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = (";
+ ret << "{";
+
+ ret << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = (";
INLINE_LIST( ret, ilItem->children, targState, inFinish, false );
- ret << "); " << CTRL_FLOW() << "goto _again;}";
+ ret << ");";
+
+ if ( inFinish && !noEnd )
+ EOF_CHECK( ret );
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
if ( prePushExpr != 0 )
ret << "}";
@@ -739,7 +770,12 @@ void TabCodeGen::RET( ostream &ret, bool inFinish )
ret << "}";
}
- ret << CTRL_FLOW() << "goto _again;}";
+ if ( inFinish && !noEnd )
+ EOF_CHECK( ret );
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
}
void TabCodeGen::BREAK( ostream &ret, int targState, bool csForced )
diff --git a/ragel/cstable.cpp b/ragel/cstable.cpp
index 72df0a63..13c9e738 100644
--- a/ragel/cstable.cpp
+++ b/ragel/cstable.cpp
@@ -618,15 +618,22 @@ std::ostream &CSharpTabCodeGen::TRANS_ACTIONS_WI()
void CSharpTabCodeGen::GOTO( ostream &ret, int gotoDest, bool inFinish )
{
- ret << "{" << vCS() << " = " << gotoDest << "; " <<
- CTRL_FLOW() << "goto _again;}";
+ ret << "{" << vCS() << " = " << gotoDest << ";";
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
}
void CSharpTabCodeGen::GOTO_EXPR( ostream &ret, GenInlineItem *ilItem, bool inFinish )
{
ret << "{" << vCS() << " = (";
INLINE_LIST( ret, ilItem->children, 0, inFinish );
- ret << "); " << CTRL_FLOW() << "goto _again;}";
+ ret << ");";
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
}
void CSharpTabCodeGen::CURS( ostream &ret, bool inFinish )
@@ -658,8 +665,13 @@ void CSharpTabCodeGen::CALL( ostream &ret, int callDest, int targState, bool inF
INLINE_LIST( ret, prePushExpr, 0, false );
}
- ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " <<
- callDest << "; " << CTRL_FLOW() << "goto _again;}";
+ ret << "{";
+
+ ret << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = " << callDest << ";";
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
if ( prePushExpr != 0 )
ret << "}";
@@ -672,9 +684,15 @@ void CSharpTabCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targS
INLINE_LIST( ret, prePushExpr, 0, false );
}
- ret << "{" << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = (";
+ ret << "{";
+
+ ret << STACK() << "[" << TOP() << "++] = " << vCS() << "; " << vCS() << " = (";
INLINE_LIST( ret, ilItem->children, targState, inFinish );
- ret << "); " << CTRL_FLOW() << "goto _again;}";
+ ret << ");";
+
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
if ( prePushExpr != 0 )
ret << "}";
@@ -682,8 +700,9 @@ void CSharpTabCodeGen::CALL_EXPR( ostream &ret, GenInlineItem *ilItem, int targS
void CSharpTabCodeGen::RET( ostream &ret, bool inFinish )
{
- ret << "{" << vCS() << " = " << STACK() << "[--" <<
- TOP() << "]; ";
+ ret << "{";
+
+ ret << vCS() << " = " << STACK() << "[--" << TOP() << "]; ";
if ( postPopExpr != 0 ) {
ret << "{";
@@ -691,7 +710,9 @@ void CSharpTabCodeGen::RET( ostream &ret, bool inFinish )
ret << "}";
}
- ret << CTRL_FLOW() << "goto _again;}";
+ ret << CTRL_FLOW() << "goto _again;";
+
+ ret << "}";
}
void CSharpTabCodeGen::BREAK( ostream &ret, int targState )
diff --git a/test/eofcall1.rl b/test/eofcall1.rl
new file mode 100644
index 00000000..598f8705
--- /dev/null
+++ b/test/eofcall1.rl
@@ -0,0 +1,138 @@
+/*
+ * @LANG: c
+ *
+ * Testing fcall in an EOF action.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int neg;
+int value;
+
+%%{
+ machine atoi;
+
+ action begin {
+ neg = 0;
+ value = 0;
+ }
+
+ action see_neg
+ {
+ neg = 1;
+ }
+
+ action add_digit
+ {
+ value = value * 10 + ( int ) ( fc - 48 );
+ }
+
+ action finish
+ {
+ if ( neg != 0 ) {
+ value = -1 * value;
+ }
+ }
+
+ action print
+ {
+ printf( "%d", value );
+ printf( "%s", "\n" );
+ }
+
+ atoi = (
+ ('-'@see_neg | '+')? (digit @add_digit)+
+ ) >begin %finish;
+
+ main := atoi '\n' @print %{ printf("goto extra\n"); fcall extra; };
+
+ extra := "" %{ printf("done: %d\n", (int)(p-data)); };
+
+}%%
+
+%% write data;
+int cs;
+int blen;
+char buffer[1024];
+int top, stack[1];
+
+void init()
+{
+ value = 0;
+ neg = 0;
+ %% write init;
+}
+
+void exec( char *data, int len )
+{
+ char *p = data;
+ char *pe = data + len;
+ char *eof = pe;
+ %% write exec;
+}
+
+void finish( )
+{
+ if ( cs >= atoi_first_final )
+ printf( "ACCEPT\n" );
+ else
+ printf( "FAIL\n" );
+
+}
+
+char *inp[] = {
+ "1\n",
+ "12\n",
+ "222222\n",
+ "+2123\n",
+ "213 3213\n",
+ "-12321\n",
+ "--123\n",
+ "-99\n",
+ " -3000\n",
+};
+
+int inplen = 9;
+
+int main( )
+{
+ int i;
+ for ( i = 0; i < inplen; i++ ) {
+ init();
+ exec( inp[i], strlen(inp[i]) );
+ finish();
+ }
+ return 0;
+}
+
+#ifdef ___________OUTPUT___________
+1
+goto extra
+done: 2
+ACCEPT
+12
+goto extra
+done: 3
+ACCEPT
+222222
+goto extra
+done: 7
+ACCEPT
+2123
+goto extra
+done: 6
+ACCEPT
+FAIL
+-12321
+goto extra
+done: 7
+ACCEPT
+FAIL
+-99
+goto extra
+done: 4
+ACCEPT
+FAIL
+#endif
diff --git a/test/eofcall2.rl b/test/eofcall2.rl
new file mode 100644
index 00000000..26fbf724
--- /dev/null
+++ b/test/eofcall2.rl
@@ -0,0 +1,138 @@
+/*
+ * @LANG: c
+ *
+ * Testing fcall * in an EOF action.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int neg;
+int value;
+
+%%{
+ machine atoi;
+
+ action begin {
+ neg = 0;
+ value = 0;
+ }
+
+ action see_neg
+ {
+ neg = 1;
+ }
+
+ action add_digit
+ {
+ value = value * 10 + ( int ) ( fc - 48 );
+ }
+
+ action finish
+ {
+ if ( neg != 0 ) {
+ value = -1 * value;
+ }
+ }
+
+ action print
+ {
+ printf( "%d", value );
+ printf( "%s", "\n" );
+ }
+
+ atoi = (
+ ('-'@see_neg | '+')? (digit @add_digit)+
+ ) >begin %finish;
+
+ main := atoi '\n' @print %{ printf("goto extra\n"); fcall *fentry(extra); };
+
+ extra := "" %{ printf("done: %d\n", (int)(p-data)); };
+
+}%%
+
+%% write data;
+int cs;
+int blen;
+char buffer[1024];
+int top, stack[1];
+
+void init()
+{
+ value = 0;
+ neg = 0;
+ %% write init;
+}
+
+void exec( char *data, int len )
+{
+ char *p = data;
+ char *pe = data + len;
+ char *eof = pe;
+ %% write exec;
+}
+
+void finish( )
+{
+ if ( cs >= atoi_first_final )
+ printf( "ACCEPT\n" );
+ else
+ printf( "FAIL\n" );
+
+}
+
+char *inp[] = {
+ "1\n",
+ "12\n",
+ "222222\n",
+ "+2123\n",
+ "213 3213\n",
+ "-12321\n",
+ "--123\n",
+ "-99\n",
+ " -3000\n",
+};
+
+int inplen = 9;
+
+int main( )
+{
+ int i;
+ for ( i = 0; i < inplen; i++ ) {
+ init();
+ exec( inp[i], strlen(inp[i]) );
+ finish();
+ }
+ return 0;
+}
+
+#ifdef ___________OUTPUT___________
+1
+goto extra
+done: 2
+ACCEPT
+12
+goto extra
+done: 3
+ACCEPT
+222222
+goto extra
+done: 7
+ACCEPT
+2123
+goto extra
+done: 6
+ACCEPT
+FAIL
+-12321
+goto extra
+done: 7
+ACCEPT
+FAIL
+-99
+goto extra
+done: 4
+ACCEPT
+FAIL
+#endif
diff --git a/test/eofgoto1.rl b/test/eofgoto1.rl
new file mode 100644
index 00000000..6ce530a9
--- /dev/null
+++ b/test/eofgoto1.rl
@@ -0,0 +1,137 @@
+/*
+ * @LANG: c
+ *
+ * Testing fgoto in an EOF action.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int neg;
+int value;
+
+%%{
+ machine atoi;
+
+ action begin {
+ neg = 0;
+ value = 0;
+ }
+
+ action see_neg
+ {
+ neg = 1;
+ }
+
+ action add_digit
+ {
+ value = value * 10 + ( int ) ( fc - 48 );
+ }
+
+ action finish
+ {
+ if ( neg != 0 ) {
+ value = -1 * value;
+ }
+ }
+
+ action print
+ {
+ printf( "%d", value );
+ printf( "%s", "\n" );
+ }
+
+ atoi = (
+ ('-'@see_neg | '+')? (digit @add_digit)+
+ ) >begin %finish;
+
+ extra := "" %{ printf("done: %d\n", (int)(p-data)); };
+
+ main := atoi '\n' @print %{ printf("goto extra\n"); fgoto extra; };
+
+}%%
+
+%% write data;
+int cs;
+int blen;
+char buffer[1024];
+
+void init()
+{
+ value = 0;
+ neg = 0;
+ %% write init;
+}
+
+void exec( char *data, int len )
+{
+ char *p = data;
+ char *pe = data + len;
+ char *eof = pe;
+ %% write exec;
+}
+
+void finish( )
+{
+ if ( cs >= atoi_first_final )
+ printf( "ACCEPT\n" );
+ else
+ printf( "FAIL\n" );
+
+}
+
+char *inp[] = {
+ "1\n",
+ "12\n",
+ "222222\n",
+ "+2123\n",
+ "213 3213\n",
+ "-12321\n",
+ "--123\n",
+ "-99\n",
+ " -3000\n",
+};
+
+int inplen = 9;
+
+int main( )
+{
+ int i;
+ for ( i = 0; i < inplen; i++ ) {
+ init();
+ exec( inp[i], strlen(inp[i]) );
+ finish();
+ }
+ return 0;
+}
+
+#ifdef ___________OUTPUT___________
+1
+goto extra
+done: 2
+ACCEPT
+12
+goto extra
+done: 3
+ACCEPT
+222222
+goto extra
+done: 7
+ACCEPT
+2123
+goto extra
+done: 6
+ACCEPT
+FAIL
+-12321
+goto extra
+done: 7
+ACCEPT
+FAIL
+-99
+goto extra
+done: 4
+ACCEPT
+FAIL
+#endif
diff --git a/test/eofgoto2.rl b/test/eofgoto2.rl
new file mode 100644
index 00000000..0d6096a5
--- /dev/null
+++ b/test/eofgoto2.rl
@@ -0,0 +1,138 @@
+/*
+ * @LANG: c
+ *
+ * Testing fgoto * in an EOF action.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int neg;
+int value;
+
+
+%%{
+ machine atoi;
+
+ action begin {
+ neg = 0;
+ value = 0;
+ }
+
+ action see_neg
+ {
+ neg = 1;
+ }
+
+ action add_digit
+ {
+ value = value * 10 + ( int ) ( fc - 48 );
+ }
+
+ action finish
+ {
+ if ( neg != 0 ) {
+ value = -1 * value;
+ }
+ }
+
+ action print
+ {
+ printf( "%d", value );
+ printf( "%s", "\n" );
+ }
+
+ atoi = (
+ ('-'@see_neg | '+')? (digit @add_digit)+
+ ) >begin %finish;
+
+ main := atoi '\n' @print %{ printf("goto extra\n"); fgoto *fentry(extra); };
+
+ extra := "" %{ printf("done: %d\n", (int)(p-data)); };
+
+}%%
+
+%% write data;
+int cs;
+int blen;
+char buffer[1024];
+
+void init()
+{
+ value = 0;
+ neg = 0;
+ %% write init;
+}
+
+void exec( char *data, int len )
+{
+ char *p = data;
+ char *pe = data + len;
+ char *eof = pe;
+ %% write exec;
+}
+
+void finish( )
+{
+ if ( cs >= atoi_first_final )
+ printf( "ACCEPT\n" );
+ else
+ printf( "FAIL\n" );
+
+}
+
+char *inp[] = {
+ "1\n",
+ "12\n",
+ "222222\n",
+ "+2123\n",
+ "213 3213\n",
+ "-12321\n",
+ "--123\n",
+ "-99\n",
+ " -3000\n",
+};
+
+int inplen = 9;
+
+int main( )
+{
+ int i;
+ for ( i = 0; i < inplen; i++ ) {
+ init();
+ exec( inp[i], strlen(inp[i]) );
+ finish();
+ }
+ return 0;
+}
+
+#ifdef ___________OUTPUT___________
+1
+goto extra
+done: 2
+ACCEPT
+12
+goto extra
+done: 3
+ACCEPT
+222222
+goto extra
+done: 7
+ACCEPT
+2123
+goto extra
+done: 6
+ACCEPT
+FAIL
+-12321
+goto extra
+done: 7
+ACCEPT
+FAIL
+-99
+goto extra
+done: 4
+ACCEPT
+FAIL
+#endif
diff --git a/test/eofret1.rl b/test/eofret1.rl
new file mode 100644
index 00000000..5f90263f
--- /dev/null
+++ b/test/eofret1.rl
@@ -0,0 +1,141 @@
+/*
+ * @LANG: c
+ *
+ * Testing fcall in an EOF action.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int neg;
+int value;
+
+%%{
+ machine atoi;
+
+ action begin {
+ neg = 0;
+ value = 0;
+ }
+
+ action see_neg
+ {
+ neg = 1;
+ }
+
+ action add_digit
+ {
+ value = value * 10 + ( int ) ( fc - 48 );
+ }
+
+ action finish
+ {
+ if ( neg != 0 ) {
+ value = -1 * value;
+ }
+ }
+
+ action print
+ {
+ printf( "%d", value );
+ printf( "%s", "\n" );
+ }
+
+ atoi = (
+ ('-'@see_neg | '+')? (digit @add_digit)+
+ ) >begin %finish;
+
+ main := atoi '\n' @print %{ printf("goto extra\n"); fret; };
+
+ extra := "" %{ printf("done: %d\n", (int)(p-data)); };
+
+}%%
+
+%% write data;
+int cs;
+int blen;
+char buffer[1024];
+int top, stack[1];
+
+void init()
+{
+ value = 0;
+ neg = 0;
+ %% write init;
+
+ stack[0] = atoi_en_extra;
+ top = 1;
+}
+
+void exec( char *data, int len )
+{
+ char *p = data;
+ char *pe = data + len;
+ char *eof = pe;
+ %% write exec;
+}
+
+void finish( )
+{
+ if ( cs >= atoi_first_final )
+ printf( "ACCEPT\n" );
+ else
+ printf( "FAIL\n" );
+
+}
+
+char *inp[] = {
+ "1\n",
+ "12\n",
+ "222222\n",
+ "+2123\n",
+ "213 3213\n",
+ "-12321\n",
+ "--123\n",
+ "-99\n",
+ " -3000\n",
+};
+
+int inplen = 9;
+
+int main( )
+{
+ int i;
+ for ( i = 0; i < inplen; i++ ) {
+ init();
+ exec( inp[i], strlen(inp[i]) );
+ finish();
+ }
+ return 0;
+}
+
+#ifdef ___________OUTPUT___________
+1
+goto extra
+done: 2
+ACCEPT
+12
+goto extra
+done: 3
+ACCEPT
+222222
+goto extra
+done: 7
+ACCEPT
+2123
+goto extra
+done: 6
+ACCEPT
+FAIL
+-12321
+goto extra
+done: 7
+ACCEPT
+FAIL
+-99
+goto extra
+done: 4
+ACCEPT
+FAIL
+#endif