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