5c979ebe6eca0f7b10b2e743c9604a2f2dcd51a0
[external/ragel.git] / examples / cppscan / cppscan.rl
1 /*
2  * A C++ scanner. Uses the longest match construction.
3  * << <= <<= >> >= >>= are left out since angle brackets are used in templates.
4  */
5
6 #include <string.h>
7 #include <stdlib.h>
8 #include <iostream>
9
10 #define TK_Dlit 256
11 #define TK_Slit 257
12 #define TK_Float 258
13 #define TK_Id 259
14 #define TK_NameSep 260
15 #define TK_Arrow 261
16 #define TK_PlusPlus 262
17 #define TK_MinusMinus 263
18 #define TK_ArrowStar 264
19 #define TK_DotStar 265
20 #define TK_ShiftLeft 266
21 #define TK_ShiftRight 267
22 #define TK_IntegerDecimal 268
23 #define TK_IntegerOctal 269
24 #define TK_IntegerHex 270
25 #define TK_EqualsEquals 271
26 #define TK_NotEquals 272
27 #define TK_AndAnd 273
28 #define TK_OrOr 274
29 #define TK_MultAssign 275
30 #define TK_DivAssign 276
31 #define TK_PercentAssign 277
32 #define TK_PlusAssign 278
33 #define TK_MinusAssign 279
34 #define TK_AmpAssign 280
35 #define TK_CaretAssign 281
36 #define TK_BarAssign 282
37 #define TK_DotDotDot 283
38 #define TK_Whitespace 284
39 #define TK_Comment 285
40
41 #define BUFSIZE 16384
42
43 /* EOF char used to flush out that last token. This should be a whitespace
44  * token. */
45
46 #define LAST_CHAR 0
47
48 using std::cerr;
49 using std::cout;
50 using std::cin;
51 using std::endl;
52
53 static char buf[BUFSIZE];
54 static int line = 1, col = 1;
55 static char *tokstart, *tokend;
56 static int act, have = 0;
57 static int cs;
58
59 %%{
60         machine Scanner; 
61         write data nofinal;
62
63         # Floating literals.
64         fract_const = digit* '.' digit+ | digit+ '.';
65         exponent = [eE] [+\-]? digit+;
66         float_suffix = [flFL];
67
68         c_comment := 
69                 any* :>> '*/'
70                 @{ fgoto main; };
71
72         main := |*
73
74         # Single and double literals.
75         ( 'L'? "'" ( [^'\\\n] | /\\./ )* "'" ) 
76                 {token( TK_Slit );};
77         ( 'L'? '"' ( [^"\\\n] | /\\./ )* '"' ) 
78                 {token( TK_Dlit );};
79
80         # Identifiers
81         ( [a-zA-Z_] [a-zA-Z0-9_]* ) 
82                 {token( TK_Id );};
83
84         # Floating literals.
85         ( fract_const exponent? float_suffix? | digit+ exponent float_suffix? ) 
86                 {token( TK_Float );};
87         
88         # Integer decimal. Leading part buffered by float.
89         ( ( '0' | [1-9] [0-9]* ) [ulUL]{0,3} ) 
90                 {token( TK_IntegerDecimal );};
91
92         # Integer octal. Leading part buffered by float.
93         ( '0' [0-9]+ [ulUL]{0,2} ) 
94                 {token( TK_IntegerOctal );};
95
96         # Integer hex. Leading 0 buffered by float.
97         ( '0' ( 'x' [0-9a-fA-F]+ [ulUL]{0,2} ) ) 
98                 {token( TK_IntegerHex );};
99
100         # Only buffer the second item, first buffered by symbol. */
101         '::' {token( TK_NameSep );};
102         '==' {token( TK_EqualsEquals );};
103         '!=' {token( TK_NotEquals );};
104         '&&' {token( TK_AndAnd );};
105         '||' {token( TK_OrOr );};
106         '*=' {token( TK_MultAssign );};
107         '/=' {token( TK_DivAssign );};
108         '%=' {token( TK_PercentAssign );};
109         '+=' {token( TK_PlusAssign );};
110         '-=' {token( TK_MinusAssign );};
111         '&=' {token( TK_AmpAssign );};
112         '^=' {token( TK_CaretAssign );};
113         '|=' {token( TK_BarAssign );};
114         '++' {token( TK_PlusPlus );};
115         '--' {token( TK_MinusMinus );};
116         '->' {token( TK_Arrow );};
117         '->*' {token( TK_ArrowStar );};
118         '.*' {token( TK_DotStar );};
119
120         # Three char compounds, first item already buffered. */
121         '...' {token( TK_DotDotDot );};
122
123         # Single char symbols.
124         ( punct - [_"'] ) {token( tokstart[0] );};
125
126         # Comments and whitespace.
127         '/*' { fgoto c_comment; };
128         '//' [^\n]* '\n';
129         ( any - 33..126 )+;
130
131         *|;
132 }%%
133
134 void token( int tok )
135 {
136         char *data = tokstart;
137         int len = tokend - tokstart;
138
139         cout << '<' << tok << "> ";
140         cout.write( data, len );
141         cout << '\n';
142         
143         /* Count newlines and columns. This code is here mainly for having some
144          * code in the token routine when commenting out the above output during
145          * performance testing. */
146         for ( int i = 0; i < len; i ++ ) {
147                 if ( data[i] == '\n' ) {
148                         line += 1;
149                         col = 1;
150                 }
151                 else {
152                         col += 1;
153                 }
154         }
155 }
156
157 int main()
158 {
159         std::ios::sync_with_stdio(false);
160
161         %% write init;
162
163         /* Do the first read. */
164         bool done = false;
165         while ( !done ) {
166                 char *p = buf + have;
167                 int space = BUFSIZE - have;
168
169                 if ( space == 0 ) {
170                         /* We filled up the buffer trying to scan a token. */
171                         cerr << "OUT OF BUFFER SPACE" << endl;
172                         exit(1);
173                 }
174
175                 cin.read( p, space );
176                 int len = cin.gcount();
177
178                 /* If we see eof then append the EOF char. */
179                 if ( len == 0 ) {
180                         p[0] = LAST_CHAR, len++;
181                         done = true;
182                 }
183
184                 char *pe = p + len;
185                 %% write exec;
186
187                 /* Check if we failed. */
188                 if ( cs == Scanner_error ) {
189                         /* Machine failed before finding a token. */
190                         cerr << "PARSE ERROR" << endl;
191                         exit(1);
192                 }
193
194                 /* Now set up the prefix. */
195                 if ( tokstart == 0 )
196                         have = 0;
197                 else {
198                         /* There is data that needs to be shifted over. */
199                         have = pe - tokstart;
200                         memmove( buf, tokstart, have );
201                         tokend -= (tokstart-buf);
202                         tokstart = buf;
203                 }
204         }
205
206         return 0;
207 }