First cut of a test-suite transformation for Ruby. Some of the tests work.
[external/ragel.git] / test / cppscan1.rl
1 /*
2  * @LANG: c++
3  * @ALLOW_GENFLAGS: -T0 -T1 -F0 -F1 -G0 -G1 -G2 -P
4  */
5
6 #include "cppscan1.h"
7
8 %%{
9         machine Scanner;
10         access fsm->;
11
12         action pass { fsm->pass(fc); }
13         action buf { fsm->buf(fc); }
14
15         action emit_slit { fsm->token( TK_Slit ); }
16         action emit_dlit { fsm->token( TK_Dlit ); }
17         action emit_id { fsm->token( TK_Id ); }
18         action emit_integer_decimal { fsm->token( TK_IntegerDecimal ); }
19         action emit_integer_octal { fsm->token( TK_IntegerOctal ); }
20         action emit_integer_hex { fsm->token( TK_IntegerHex ); }
21         action emit_float { fsm->token( TK_Float ); }
22         action emit_symbol { fsm->token( fsm->tokBuf.data[0] ); }
23         action tokst { fsm->tokStart = fsm->col; }
24
25         # Single and double literals.
26         slit = ( 'L'? ( "'" ( [^'\\\n] | /\\./ )* "'" ) $buf ) >tokst %emit_slit;
27         dlit = ( 'L'? ( '"' ( [^"\\\n] | /\\./ )* '"' ) $buf ) >tokst %emit_dlit;
28
29         # Identifiers
30         id = ( [a-zA-Z_] [a-zA-Z0-9_]* ) >tokst $buf %emit_id;
31
32         # Floating literals.
33         fract_const = digit* '.' digit+ | digit+ '.';
34         exponent = [eE] [+\-]? digit+;
35         float_suffix = [flFL];
36         float = 
37                 ( fract_const exponent? float_suffix? |
38                 digit+ exponent float_suffix? ) >tokst $buf %emit_float;
39         
40         # Integer decimal. Leading part buffered by float.
41         integer_decimal = ( ( '0' | [1-9] [0-9]* ) [ulUL]{0,3} $buf ) %emit_integer_decimal;
42
43         # Integer octal. Leading part buffered by float.
44         integer_octal = ( '0' [0-9]+ [ulUL]{0,2} $buf ) %emit_integer_octal;
45
46         # Integer hex. Leading 0 buffered by float.
47         integer_hex = ( '0' ( 'x' [0-9a-fA-F]+ [ulUL]{0,2} ) $buf ) %emit_integer_hex;
48
49         # Only buffer the second item, first buffered by symbol. */
50         namesep = '::' @buf %{fsm->token( TK_NameSep );};
51         deqs = '==' @buf %{fsm->token( TK_EqualsEquals );};
52         neqs = '!=' @buf %{fsm->token( TK_NotEquals );};
53         and_and = '&&' @buf %{fsm->token( TK_AndAnd );};
54         or_or = '||' @buf %{fsm->token( TK_OrOr );};
55         mult_assign = '*=' @buf %{fsm->token( TK_MultAssign );};
56         percent_assign = '%=' @buf %{fsm->token( TK_PercentAssign );};
57         plus_assign = '+=' @buf %{fsm->token( TK_PlusAssign );};
58         minus_assign = '-=' @buf %{fsm->token( TK_MinusAssign );};
59         amp_assign = '&=' @buf %{fsm->token( TK_AmpAssign );};
60         caret_assign = '^=' @buf %{fsm->token( TK_CaretAssign );};
61         bar_assign = '|=' @buf %{fsm->token( TK_BarAssign );};
62         plus_plus = '++' @buf %{fsm->token( TK_PlusPlus );};
63         minus_minus = '--' @buf %{fsm->token( TK_MinusMinus );};
64         arrow = '->' @buf %{fsm->token( TK_Arrow );};
65         arrow_star = '->*' @buf %{fsm->token( TK_ArrowStar );};
66         dot_star = '.*' @buf %{fsm->token( TK_DotStar );};
67
68         # Buffer both items. *
69         div_assign = '/=' @{fsm->buf('/');fsm->buf(fc);} %{fsm->token( TK_DivAssign );};
70
71         # Double dot is sent as two dots.
72         dot_dot = '..' %{fsm->token('.'); fsm->buf('.'); fsm->token('.');};
73
74         # Three char compounds, first item already buffered. */
75         dot_dot_dot = '...' %{fsm->buf('.'); fsm->buf('.'); fsm->token( TK_DotDotDot );};
76
77         # All compunds
78         compound = namesep | deqs | neqs | and_and | or_or | mult_assign |
79                         div_assign | percent_assign | plus_assign | minus_assign |
80                         amp_assign | caret_assign | bar_assign | plus_plus | minus_minus |
81                         arrow | arrow_star | dot_star | dot_dot | dot_dot_dot;
82
83         # Single char symbols.
84         symbol = 
85                 ( punct - [./_"'] ) >tokst $buf %emit_symbol |
86                 # Do not immediately buffer slash, may be start of comment.
87                 '/' >tokst %{ fsm->buf('/'); fsm->token( '/' ); } |
88                 # Dot covered by float.
89                 '.' %emit_symbol;
90
91         # Comments and whitespace.
92         commc = '/*' @{fsm->pass('/'); fsm->pass('*');} ( any* $0 '*/' @1 ) $pass;
93         commcc = '//' @{fsm->pass('/'); fsm->pass('/');} ( any* $0 '\n' @1 ) $pass;
94         whitespace = ( any - ( 0 | 33..126 ) )+ $pass;
95
96         action onEOFChar { 
97                 /* On EOF char, write out the non token buffer. */
98                 fsm->nonTokBuf.append(0);
99                 cout << fsm->nonTokBuf.data;
100                 fsm->nonTokBuf.clear();
101         }
102
103         # Using 0 as eof. If seeingAs a result all null characters get ignored.
104         EOF = 0 @onEOFChar;
105
106         # All outside code tokens.
107         tokens = ( 
108                 id | slit | dlit | float | integer_decimal | 
109                 integer_octal | integer_hex | compound | symbol );
110         nontok = ( commc | commcc | whitespace | EOF );
111
112         position = (
113                 '\n' @{ fsm->line += 1; fsm->col = 1; } |
114                 [^\n] @{ fsm->col += 1; } )*;
115
116         main := ( ( tokens | nontok )** ) & position;
117 }%%
118
119 %% write data;
120
121 void Scanner::init( )
122 {
123         Scanner *fsm = this;
124         /* A count of the number of characters in 
125          * a token. Used for % sequences. */
126         count = 0;
127         line = 1;
128         col = 1;
129
130         %% write init;
131 }
132
133 int Scanner::execute( char *data, int len )
134 {
135         Scanner *fsm = this;
136         char *p = data;
137         char *pe = data + len;
138
139         %% write exec;
140         if ( cs == Scanner_error )
141                 return -1;
142         if ( cs >= Scanner_first_final )
143                 return 1;
144         return 0;
145 }
146
147 int Scanner::finish( )
148 {
149         %% write eof;
150         if ( cs == Scanner_error )
151                 return -1;
152         if ( cs >= Scanner_first_final )
153                 return 1;
154         return 0;
155 }
156
157 void Scanner::token( int id )
158 {
159         /* Leader. */
160         if ( nonTokBuf.length > 0 ) {
161                 nonTokBuf.append(0);
162                 cout << nonTokBuf.data;
163                 nonTokBuf.clear();
164         }
165
166         /* Token data. */
167         tokBuf.append(0);
168         cout << '<' << id << '>' << tokBuf.data;
169         tokBuf.clear();
170 }
171
172 void Buffer::empty()
173 {
174         if ( data != 0 ) {
175                 free( data );
176
177                 data = 0;
178                 length = 0;
179                 allocated = 0;
180         }
181 }
182
183 void Buffer::upAllocate( int len )
184 {
185         if ( data == 0 )
186                 data = (char*) malloc( len );
187         else
188                 data = (char*) realloc( data, len );
189         allocated = len;
190 }
191
192 void test( char *buf )
193 {
194         Scanner scanner(cout);
195         scanner.init();
196         scanner.execute( buf, strlen(buf) );
197
198         /* The last token is ignored (because there is no next token). Send
199          * trailing null to force the last token into whitespace. */
200         char eof = 0;
201         if ( scanner.execute( &eof, 1 ) <= 0 ) {
202                 cerr << "cppscan: scan failed" << endl;
203                 return;
204         }
205         cout.flush();
206 }
207
208 int main()
209 {
210         test( 
211                 "/*\n"
212                 " *  Copyright \n"
213                 " */\n"
214                 "\n"
215                 "/* Construct an fsmmachine from a graph. */\n"
216                 "RedFsmAp::RedFsmAp( FsmAp *graph, bool complete )\n"
217                 ":\n"
218                 "       graph(graph),\n"
219                 "{\n"
220                 "       assert( sizeof(RedTransAp) <= sizeof(TransAp) );\n"
221                 "\n"
222                 "       reduceMachine();\n"
223                 "}\n"
224                 "\n"
225                 "{\n"
226                 "       /* Get the transition that we want to extend. */\n"
227                 "       RedTransAp *extendTrans = list[pos].value;\n"
228                 "\n"
229                 "       /* Look ahead in the transition list. */\n"
230                 "       for ( int next = pos + 1; next < list.length(); pos++, next++ ) {\n"
231                 "               if ( ! keyOps->eq( list[pos].highKey, nextKey ) )\n"
232                 "                       break;\n"
233                 "       }\n"
234                 "       return false;\n"
235                 "}\n"
236                 "\n" );
237
238         test( 
239                 "->*\n"
240                 ".*\n"
241                 "/*\"*/\n"
242                 "\"/*\"\n"
243                 "L'\"'\n"
244                 "L\"'\"\n" );
245         
246         return 0;
247 }
248
249 #ifdef _____OUTPUT_____
250 /*
251  *  Copyright 
252  */
253
254 /* Construct an fsmmachine from a graph. */
255 <195>RedFsmAp<197>::<195>RedFsmAp<40>( <195>FsmAp <42>*<195>graph<44>, <195>bool <195>complete <41>)
256 <58>:
257         <195>graph<40>(<195>graph<41>)<44>,
258 <123>{
259         <195>assert<40>( <195>sizeof<40>(<195>RedTransAp<41>) <60><<61>= <195>sizeof<40>(<195>TransAp<41>) <41>)<59>;
260
261         <195>reduceMachine<40>(<41>)<59>;
262 <125>}
263
264 <123>{
265         /* Get the transition that we want to extend. */
266         <195>RedTransAp <42>*<195>extendTrans <61>= <195>list<91>[<195>pos<93>]<46>.<195>value<59>;
267
268         /* Look ahead in the transition list. */
269         <195>for <40>( <195>int <195>next <61>= <195>pos <43>+ <218>1<59>; <195>next <60>< <195>list<46>.<195>length<40>(<41>)<59>; <195>pos<212>++<44>, <195>next<212>++ <41>) <123>{
270                 <195>if <40>( <33>! <195>keyOps<211>-><195>eq<40>( <195>list<91>[<195>pos<93>]<46>.<195>highKey<44>, <195>nextKey <41>) <41>)
271                         <195>break<59>;
272         <125>}
273         <195>return <195>false<59>;
274 <125>}
275
276 <214>->*
277 <215>.*
278 /*"*/
279 <192>"/*"
280 <193>L'"'
281 <192>L"'"
282 #endif