78efe206bb28b3097ecfb67d2421f934d8702d64
[external/ragel.git] / test / cppscan2.rl
1 /*
2  * @LANG: c++
3  */
4
5 #include <iostream>
6 using namespace std;
7
8 #define TK_Dlit 192
9 #define TK_Slit 193
10 #define TK_Float 194
11 #define TK_Id 195
12 #define TK_NameSep 197
13 #define TK_Arrow 211
14 #define TK_PlusPlus 212
15 #define TK_MinusMinus 213
16 #define TK_ArrowStar 214
17 #define TK_DotStar 215
18 #define TK_ShiftLeft 216
19 #define TK_ShiftRight 217
20 #define TK_IntegerDecimal 218
21 #define TK_IntegerOctal 219
22 #define TK_IntegerHex 220
23 #define TK_EqualsEquals 223
24 #define TK_NotEquals 224
25 #define TK_AndAnd 225
26 #define TK_OrOr 226
27 #define TK_MultAssign 227
28 #define TK_DivAssign 228
29 #define TK_PercentAssign 229
30 #define TK_PlusAssign 230
31 #define TK_MinusAssign 231
32 #define TK_AmpAssign 232
33 #define TK_CaretAssign 233
34 #define TK_BarAssign 234
35 #define TK_DotDotDot 240
36 #define TK_Whitespace 241
37 #define TK_Comment 242
38
39 #define BUFSIZE 4096
40
41 int tok;
42 char buf[BUFSIZE], *tokstart, *tokend;
43 void token( char *data, int len );
44 bool discard = false;
45
46 struct Scanner
47 {
48         int cs;
49
50         // Initialize the machine. Invokes any init statement blocks. Returns 0
51         // if the machine begins in a non-accepting state and 1 if the machine
52         // begins in an accepting state.
53         int init( );
54
55         // Execute the machine on a block of data. Returns -1 if after processing
56         // the data, the machine is in the error state and can never accept, 0 if
57         // the machine is in a non-accepting state and 1 if the machine is in an
58         // accepting state.
59         int execute( char *data, int len );
60
61         // Indicate that there is no more data. Returns -1 if the machine finishes
62         // in the error state and does not accept, 0 if the machine finishes
63         // in any other non-accepting state and 1 if the machine finishes in an
64         // accepting state.
65         int finish( );
66 };
67
68 %%{
69         machine Scanner;
70
71         # Single and double literals.
72         slit = ( 'L'? "'" ( [^'\\\n] | /\\./ )* "'" ) @{tok = TK_Slit;};
73         dlit = ( 'L'? '"' ( [^"\\\n] | /\\./ )* '"' ) @{tok = TK_Dlit;};
74
75         # Identifiers
76         id = ( [a-zA-Z_] [a-zA-Z0-9_]* ) @{tok = TK_Id;};
77
78         # Floating literals.
79         fract_const = digit* '.' digit+ | digit+ '.';
80         exponent = [eE] [+\-]? digit+;
81         float_suffix = [flFL];
82         float = 
83                 ( fract_const exponent? float_suffix? |
84                 digit+ exponent float_suffix? ) @{tok = TK_Float;};
85         
86         # Integer decimal. Leading part buffered by float.
87         integer_decimal = ( ( '0' | [1-9] [0-9]* ) [ulUL]{0,3} ) @{tok = TK_IntegerDecimal;};
88
89         # Integer octal. Leading part buffered by float.
90         integer_octal = ( '0' [0-9]+ [ulUL]{0,2} ) @{tok = TK_IntegerOctal;};
91
92         # Integer hex. Leading 0 buffered by float.
93         integer_hex = ( '0' ( 'x' [0-9a-fA-F]+ [ulUL]{0,2} ) ) @{tok = TK_IntegerHex;};
94
95         # Only buffer the second item, first buffered by symbol. */
96         namesep = '::' @{tok = TK_NameSep;};
97         deqs = '==' @{tok = TK_EqualsEquals;};
98         neqs = '!=' @{tok = TK_NotEquals;};
99         and_and = '&&' @{tok = TK_AndAnd;};
100         or_or = '||' @{tok = TK_OrOr;};
101         mult_assign = '*=' @{tok = TK_MultAssign;};
102         div_assign = '/=' @{tok = TK_DivAssign;};
103         percent_assign = '%=' @{tok = TK_PercentAssign;};
104         plus_assign = '+=' @{tok = TK_PlusAssign;};
105         minus_assign = '-=' @{tok = TK_MinusAssign;};
106         amp_assign = '&=' @{tok = TK_AmpAssign;};
107         caret_assign = '^=' @{tok = TK_CaretAssign;};
108         bar_assign = '|=' @{tok = TK_BarAssign;};
109         plus_plus = '++' @{tok = TK_PlusPlus;};
110         minus_minus = '--' @{tok = TK_MinusMinus;};
111         arrow = '->' @{tok = TK_Arrow;};
112         arrow_star = '->*' @{tok = TK_ArrowStar;};
113         dot_star = '.*' @{tok = TK_DotStar;};
114
115         # Three char compounds, first item already buffered. */
116         dot_dot_dot = '...' @{tok = TK_DotDotDot;};
117
118         # All compunds
119         compound = namesep | deqs | neqs | and_and | or_or | mult_assign |
120                         div_assign | percent_assign | plus_assign | minus_assign |
121                         amp_assign | caret_assign | bar_assign | plus_plus | minus_minus |
122                         arrow | arrow_star | dot_star | dot_dot_dot;
123
124         # Single char symbols.
125         symbol = ( punct - [_"'] ) @{tok = fc;};
126
127         action discard {
128                 discard = true;
129         }
130
131         # Comments and whitespace.
132         commc = '/*' @discard ( any* $0 '*/' @1 ) @{tok = TK_Comment;};
133         commcc = '//' @discard ( any* $0 '\n' @1 ) @{tok = TK_Comment;};
134         whitespace = ( any - 33..126 )+ >discard @{tok = TK_Whitespace;};
135
136         # All outside code tokens.
137         tokens = ( 
138                 id | slit | dlit | float | integer_decimal | 
139                 integer_octal | integer_hex | compound | symbol |
140                 commc | commcc | whitespace );
141
142         action onError {
143                 if ( tok != 0 ) {
144                         char *rst_data;
145
146                         if ( tok == TK_Comment || tok == TK_Whitespace ) {
147                                 /* Reset comment status, don't send. */
148                                 discard = false;
149
150                                 /* Restart right at the error point if consuming whitespace or
151                                  * a comment. Consume may have spanned multiple buffers. */
152                                 rst_data = fpc;
153                         }
154                         else {
155                                 /* Send the token. */
156                                 token( tokstart, tokend - tokstart + 1 );
157
158                                 /* Restart right after the token. */
159                                 rst_data = tokend+1;
160                         }
161
162                         tokstart = 0;
163                         fexec rst_data;
164                         fgoto main;
165                 }
166         }
167
168         main := tokens >{tokstart=fpc;} @{tokend=fpc;} $!onError;
169 }%%
170
171 %% write data;
172
173 int Scanner::init( )
174 {
175         tok = 0;
176         tokstart = 0;
177         tokend = 0;
178
179         %% write init;
180         return 1;
181 }
182
183 int Scanner::execute( char *data, int len )
184 {
185         char *p = data;
186         char *pe = data + len;
187         char *eof = pe;
188
189         %% write exec;
190
191         if ( cs == Scanner_error )
192                 return -1;
193         if ( cs >= Scanner_first_final )
194                 return 1;
195         return 0;
196 }
197
198 int Scanner::finish( )
199 {
200         if ( cs == Scanner_error )
201                 return -1;
202         if ( cs >= Scanner_first_final )
203                 return 1;
204         return 0;
205 }
206
207
208 void token( char *data, int len )
209 {
210         cout << "<" << tok << "> ";
211         for ( int i = 0; i < len; i++ )
212                 cout << data[i];
213         cout << '\n';
214 }
215
216 void test( char * data )
217 {
218         Scanner scanner;
219         scanner.init();
220         scanner.execute( data, strlen(data) );
221         scanner.finish();
222         if ( tok != 0 && tok != TK_Comment && tok != TK_Whitespace )
223                 token( tokstart, tokend - tokstart + 1 );
224 }
225
226 int main()
227 {
228         test(
229                 "/*\n"
230                 " *  Copyright \n"
231                 " */\n"
232                 "\n"
233                 "\n"
234                 "/* Move ranges to the singles list. */\n"
235                 "void RedFsmAp::move( RedStateAp *state )\n"
236                 "{\n"
237                 "       RedTranst &range = state->outRange;\n"
238                 "       for ( int rpos = 0; rpos < range.length(); ) {\n"
239                 "               if ( can( range, rpos ) ) {\n"
240                 "                       while ( range[rpos].value != range[rpos+1].value ) {\n"
241                 "                               single.append( range[rpos+1] );\n"
242                 "                       }\n"
243                 "                       \n"
244                 "                       range[rpos].highKey = range[rpos+1].highKey;\n"
245                 "               }\n"
246                 "               else if ( keyOps->span( range[rpos].lowKey, range[rpos].highKey ) == 1 ) {\n"
247                 "                       single.append( range[rpos] );\n"
248                 "               }\n"
249                 "       }\n"
250                 "}\n"
251                 "\n" );
252
253         test( 
254                 "->*\n"
255                 ".*\n"
256                 "/*\"*/\n"
257                 "\"/*\"\n"
258                 "L'\"'\n"
259                 "L\"'\"\n"
260                 "...\n" );
261 }
262
263 #ifdef _____OUTPUT_____
264 <195> void
265 <195> RedFsmAp
266 <197> ::
267 <195> move
268 <40> (
269 <195> RedStateAp
270 <42> *
271 <195> state
272 <41> )
273 <123> {
274 <195> RedTranst
275 <38> &
276 <195> range
277 <61> =
278 <195> state
279 <211> ->
280 <195> outRange
281 <59> ;
282 <195> for
283 <40> (
284 <195> int
285 <195> rpos
286 <61> =
287 <218> 0
288 <59> ;
289 <195> rpos
290 <60> <
291 <195> range
292 <46> .
293 <195> length
294 <40> (
295 <41> )
296 <59> ;
297 <41> )
298 <123> {
299 <195> if
300 <40> (
301 <195> can
302 <40> (
303 <195> range
304 <44> ,
305 <195> rpos
306 <41> )
307 <41> )
308 <123> {
309 <195> while
310 <40> (
311 <195> range
312 <91> [
313 <195> rpos
314 <93> ]
315 <46> .
316 <195> value
317 <224> !=
318 <195> range
319 <91> [
320 <195> rpos
321 <43> +
322 <218> 1
323 <93> ]
324 <46> .
325 <195> value
326 <41> )
327 <123> {
328 <195> single
329 <46> .
330 <195> append
331 <40> (
332 <195> range
333 <91> [
334 <195> rpos
335 <43> +
336 <218> 1
337 <93> ]
338 <41> )
339 <59> ;
340 <125> }
341 <195> range
342 <91> [
343 <195> rpos
344 <93> ]
345 <46> .
346 <195> highKey
347 <61> =
348 <195> range
349 <91> [
350 <195> rpos
351 <43> +
352 <218> 1
353 <93> ]
354 <46> .
355 <195> highKey
356 <59> ;
357 <125> }
358 <195> else
359 <195> if
360 <40> (
361 <195> keyOps
362 <211> ->
363 <195> span
364 <40> (
365 <195> range
366 <91> [
367 <195> rpos
368 <93> ]
369 <46> .
370 <195> lowKey
371 <44> ,
372 <195> range
373 <91> [
374 <195> rpos
375 <93> ]
376 <46> .
377 <195> highKey
378 <41> )
379 <223> ==
380 <218> 1
381 <41> )
382 <123> {
383 <195> single
384 <46> .
385 <195> append
386 <40> (
387 <195> range
388 <91> [
389 <195> rpos
390 <93> ]
391 <41> )
392 <59> ;
393 <125> }
394 <125> }
395 <125> }
396 <214> ->*
397 <215> .*
398 <192> "/*"
399 <193> L'"'
400 <192> L"'"
401 <240> ...
402 #endif