tokstart => ts and tokend => te
[ragel.git] / test / cppscan4.rl
blob42a97f1bf639852ac311bbaf2e0a682e36eefb31
1 /*
2  * @LANG: d
3  */
5 module cppscan;
7 import std.c.stdio;
8 import std.string;
10 const int BUFSIZE = 2048;
12 const int TK_Dlit = 192;
13 const int TK_Slit = 193;
14 const int TK_Float = 194;
15 const int TK_Id = 195;
16 const int TK_NameSep = 197;
17 const int TK_Arrow = 211;
18 const int TK_PlusPlus = 212;
19 const int TK_MinusMinus = 213;
20 const int TK_ArrowStar = 214;
21 const int TK_DotStar = 215;
22 const int TK_ShiftLeft = 216;
23 const int TK_ShiftRight = 217;
24 const int TK_IntegerDecimal = 218;
25 const int TK_IntegerOctal = 219;
26 const int TK_IntegerHex = 220;
27 const int TK_EqualsEquals = 223;
28 const int TK_NotEquals = 224;
29 const int TK_AndAnd = 225;
30 const int TK_OrOr = 226;
31 const int TK_MultAssign = 227;
32 const int TK_DivAssign = 228;
33 const int TK_PercentAssign = 229;
34 const int TK_PlusAssign = 230;
35 const int TK_MinusAssign = 231;
36 const int TK_AmpAssign = 232;
37 const int TK_CaretAssign = 233;
38 const int TK_BarAssign = 234;
39 const int TK_DotDotDot = 240;
42 class Scanner
44         int line, col;
45         int tokStart;
46         int inlineDepth;
47         int count;
48         char[] tokBuf;
49         char[] nonTokBuf;
51         void pass(char c) { nonTokBuf ~= c; }
52         void buf(char c) { tokBuf ~= c; }
53         void token( int id )
54         {
55                 /* Leader. */
56                 if ( nonTokBuf.length > 0 ) {
57                         printf("%.*s", nonTokBuf);
58                         nonTokBuf = "";
59                 }
61                 /* Token data. */
62                 printf("<%d>%.*s", id, tokBuf);
64                 tokBuf = "";
65         }
67         int cs, stack, top;
68         
69         %%{
70                 machine Scanner;
71         
72                 action pass { pass(fc); }
73                 action buf { buf(fc); }
75                 action emit_slit { token( TK_Slit ); }
76                 action emit_dlit { token( TK_Dlit ); }
77                 action emit_id { token( TK_Id ); }
78                 action emit_integer_decimal { token( TK_IntegerDecimal ); }
79                 action emit_integer_octal { token( TK_IntegerOctal ); }
80                 action emit_integer_hex { token( TK_IntegerHex ); }
81                 action emit_float { token( TK_Float ); }
82                 action emit_symbol { token( tokBuf[0] ); }
83                 action tokst { tokStart = col; }
85                 # Single and double literals.
86                 slit = ( 'L'? ( "'" ( [^'\\\n] | /\\./ )* "'" ) $buf ) >tokst %emit_slit;
87                 dlit = ( 'L'? ( '"' ( [^"\\\n] | /\\./ )* '"' ) $buf ) >tokst %emit_dlit;
89                 # Identifiers
90                 id = ( [a-zA-Z_] [a-zA-Z0-9_]* ) >tokst $buf %emit_id;
92                 # Floating literals.
93                 fract_const = digit* '.' digit+ | digit+ '.';
94                 exponent = [eE] [+\-]? digit+;
95                 float_suffix = [flFL];
96                 float = 
97                         ( fract_const exponent? float_suffix? |
98                         digit+ exponent float_suffix? ) >tokst $buf %emit_float;
99                 
100                 # Integer decimal. Leading part buffered by float.
101                 integer_decimal = ( ( '0' | [1-9] [0-9]* ) [ulUL]{0,3} $buf ) %emit_integer_decimal;
103                 # Integer octal. Leading part buffered by float.
104                 integer_octal = ( '0' [0-9]+ [ulUL]{0,2} $buf ) %emit_integer_octal;
106                 # Integer hex. Leading 0 buffered by float.
107                 integer_hex = ( '0' ( 'x' [0-9a-fA-F]+ [ulUL]{0,2} ) $buf ) %emit_integer_hex;
109                 # Only buffer the second item, first buffered by symbol. */
110                 namesep = '::' @buf %{token( TK_NameSep );};
111                 deqs = '==' @buf %{token( TK_EqualsEquals );};
112                 neqs = '!=' @buf %{token( TK_NotEquals );};
113                 and_and = '&&' @buf %{token( TK_AndAnd );};
114                 or_or = '||' @buf %{token( TK_OrOr );};
115                 mult_assign = '*=' @buf %{token( TK_MultAssign );};
116                 percent_assign = '%=' @buf %{token( TK_PercentAssign );};
117                 plus_assign = '+=' @buf %{token( TK_PlusAssign );};
118                 minus_assign = '-=' @buf %{token( TK_MinusAssign );};
119                 amp_assign = '&=' @buf %{token( TK_AmpAssign );};
120                 caret_assign = '^=' @buf %{token( TK_CaretAssign );};
121                 bar_assign = '|=' @buf %{token( TK_BarAssign );};
122                 plus_plus = '++' @buf %{token( TK_PlusPlus );};
123                 minus_minus = '--' @buf %{token( TK_MinusMinus );};
124                 arrow = '->' @buf %{token( TK_Arrow );};
125                 arrow_star = '->*' @buf %{token( TK_ArrowStar );};
126                 dot_star = '.*' @buf %{token( TK_DotStar );};
128                 # Buffer both items. *
129                 div_assign = '/=' @{buf('/');buf(fc);} %{token( TK_DivAssign );};
131                 # Double dot is sent as two dots.
132                 dot_dot = '..' %{token('.'); buf('.'); token('.');};
134                 # Three char compounds, first item already buffered. */
135                 dot_dot_dot = '...' %{buf('.'); buf('.'); token( TK_DotDotDot );};
137                 # All compunds
138                 compound = namesep | deqs | neqs | and_and | or_or | mult_assign |
139                                 div_assign | percent_assign | plus_assign | minus_assign |
140                                 amp_assign | caret_assign | bar_assign | plus_plus | minus_minus |
141                                 arrow | arrow_star | dot_star | dot_dot | dot_dot_dot;
143                 # Single char symbols.
144                 symbol = 
145                         ( punct - [./_"'] ) >tokst $buf %emit_symbol |
146                         # Do not immediately buffer slash, may be start of comment.
147                         '/' >tokst %{ buf('/'); token( '/' ); } |
148                         # Dot covered by float.
149                         '.' %emit_symbol;
151                 # Comments and whitespace.
152                 commc = '/*' @{pass('/'); pass('*');} ( any* $0 '*/' @1 ) $pass;
153                 commcc = '//' @{pass('/'); pass('/');} ( any* $0 '\n' @1 ) $pass;
154                 whitespace = ( any - ( 0 | 33..126 ) )+ $pass;
156                 action onEOFChar { 
157                         /* On EOF char, write out the non token buffer. */
158                         printf("%.*s", nonTokBuf);
159                         nonTokBuf = "";
160                 }
162                 # Using 0 as eof. If seeingAs a result all null characters get ignored.
163                 EOF = 0 @onEOFChar;
165                 # All outside code tokens.
166                 tokens = ( 
167                         id | slit | dlit | float | integer_decimal | 
168                         integer_octal | integer_hex | compound | symbol );
169                 nontok = ( commc | commcc | whitespace | EOF );
171                 position = (
172                         '\n' @{ line += 1; col = 1; } |
173                         [^\n] @{ col += 1; } )*;
175                 main := ( ( tokens | nontok )** ) & position;
176         }%%
177         
178         %% write data noprefix;
180         void init( )
181         {
182                 /* A count of the number of characters in 
183                  * a token. Used for % sequences. */
184                 count = 0;
185                 line = 1;
186                 col = 1;
187                 %% write init;
188                 return 1;
189         }
191         int execute( char* _data, int _len )
192         {
193                 char *p = _data;
194                 char *pe = _data + _len;
195                 char *eof = null;
197                 %% write exec;
199                 if ( cs == error )
200                         return -1;
201                 if ( cs >= first_final )
202                         return 1;
203                 return 0;
204         }
206         // Indicate that there is no more data. Returns -1 if the machine finishes
207         // in the error state and does not accept, 0 if the machine finishes
208         // in any other non-accepting state and 1 if the machine finishes in an
209         // accepting state.
210         int finish( )
211         {
212                 if ( cs == error )
213                         return -1;
214                 if ( cs >= first_final )
215                         return 1;
216                 return 0;
217         }
220 void test(char[] buf)
222         Scanner scanner = new Scanner();
223         scanner.init();
224         scanner.execute( buf.ptr, buf.length );
226         /* The last token is ignored (because there is no next token). Send
227          * trailing null to force the last token into whitespace. */
228         char eof_char = 0;
229         if ( scanner.execute( &eof_char, 1 ) <= 0 ) {
230                 fprintf(stderr, "cppscan: scan failed\n");
231         }
234 int main()
236         test(
237                 "/*\n"
238                 " *  Copyright \n"
239                 " */\n"
240                 "\n"
241                 "RedTransAp *RedFsmAp::reduceTrans( TransAp *trans )\n"
242                 "{\n"
243                 "       RedAction *action = 0;\n"
244                 "       if ( trans->actionTable.length() > 0 ) {\n"
245                 "               if ( actionMap.insert( trans->actionTable, &action ) )\n"
246                 "                       action->id = nextActionId++;\n"
247                 "       }\n"
248                 "       \n"
249                 "       RedStateAp *targ = (RedStateAp*)trans->toState;\n"
250                 "       if ( action == 0 ) {\n"
251                 "               delete trans;\n"
252                 "               return 0;\n"
253                 "       }\n"
254                 "\n"
255                 "       trans->~TransAp();\n"
256                 "       inDict = new(trans) RedTransAp( targ, action, nextTransId++ );\n"
257                 "       transSet.insert( inDict );\n"
258                 "}\n"
259         );
261         test(
262                 "->*\n"
263                 ".*\n"
264                 "/*\"*/\n"
265                 "\"/*\"\n"
266                 "L'\"'\n"
267                 "L\"'\"\n"
268         );
270         return 0;
273 /+ _____OUTPUT_____
275  *  Copyright 
276  */
278 <195>RedTransAp <42>*<195>RedFsmAp<197>::<195>reduceTrans<40>( <195>TransAp <42>*<195>trans <41>)
279 <123>{
280         <195>RedAction <42>*<195>action <61>= <218>0<59>;
281         <195>if <40>( <195>trans<211>-><195>actionTable<46>.<195>length<40>(<41>) <62>> <218>0 <41>) <123>{
282                 <195>if <40>( <195>actionMap<46>.<195>insert<40>( <195>trans<211>-><195>actionTable<44>, <38>&<195>action <41>) <41>)
283                         <195>action<211>-><195>id <61>= <195>nextActionId<212>++<59>;
284         <125>}
285         
286         <195>RedStateAp <42>*<195>targ <61>= <40>(<195>RedStateAp<42>*<41>)<195>trans<211>-><195>toState<59>;
287         <195>if <40>( <195>action <223>== <218>0 <41>) <123>{
288                 <195>delete <195>trans<59>;
289                 <195>return <218>0<59>;
290         <125>}
292         <195>trans<211>-><126>~<195>TransAp<40>(<41>)<59>;
293         <195>inDict <61>= <195>new<40>(<195>trans<41>) <195>RedTransAp<40>( <195>targ<44>, <195>action<44>, <195>nextTransId<212>++ <41>)<59>;
294         <195>transSet<46>.<195>insert<40>( <195>inDict <41>)<59>;
295 <125>}
296 <214>->*
297 <215>.*
298 /*"*/
299 <192>"/*"
300 <193>L'"'
301 <192>L"'"
302 +++++++++++++++++/