Use a single function for both the active flag (now called ignoreSection) and
[external/ragel.git] / ragel / rlscan.rl
1 /*
2  *  Copyright 2006-2007 Adrian Thurston <thurston@cs.queensu.ca>
3  */
4
5 /*  This file is part of Ragel.
6  *
7  *  Ragel is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  * 
12  *  Ragel is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  * 
17  *  You should have received a copy of the GNU General Public License
18  *  along with Ragel; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
20  */
21
22 #include <iostream>
23 #include <fstream>
24 #include <string.h>
25
26 #include "ragel.h"
27 #include "rlparse.h"
28 #include "parsedata.h"
29 #include "avltree.h"
30 #include "vector.h"
31
32 using std::ifstream;
33 using std::istream;
34 using std::ostream;
35 using std::cout;
36 using std::cerr;
37 using std::endl;
38
39 extern char *Parser_lelNames[];
40
41 /* This is used for tracking the current stack of include file/machine pairs. It is
42  * is used to detect and recursive include structure. */
43 struct IncludeStackItem
44 {
45         IncludeStackItem( char *fileName, char *sectionName )
46                 : fileName(fileName), sectionName(sectionName) {}
47
48         char *fileName;
49         char *sectionName;
50 };
51
52 typedef Vector<IncludeStackItem> IncludeStack;
53
54 enum InlineBlockType
55 {
56         CurlyDelimited,
57         SemiTerminated
58 };
59
60 struct Scanner
61 {
62         Scanner( char *fileName, istream &input, ostream &output,
63                         Parser *inclToParser, char *inclSectionTarg,
64                         int includeDepth )
65         : 
66                 fileName(fileName), input(input), output(output),
67                 inclToParser(inclToParser),
68                 inclSectionTarg(inclSectionTarg),
69                 includeDepth(includeDepth),
70                 line(1), column(1), lastnl(0), 
71                 parser(0), ignoreSection(false), 
72                 parserExistsError(false),
73                 whitespaceOn(true)
74                 {}
75
76         bool recursiveInclude( char *inclFileName, char *inclSectionName );
77
78         char *prepareFileName( char *fileName, int len )
79         {
80                 bool caseInsensitive;
81                 Token tokenFnStr, tokenRes;
82                 tokenFnStr.data = fileName;
83                 tokenFnStr.length = len;
84                 tokenFnStr.prepareLitString( tokenRes, caseInsensitive );
85                 return tokenRes.data;
86         }
87
88         void init();
89         void token( int type, char *start, char *end );
90         void token( int type, char c );
91         void token( int type );
92         void updateCol();
93         void startSection();
94         void endSection();
95         void do_scan();
96         bool active();
97         ostream &scan_error();
98
99         char *fileName;
100         istream &input;
101         ostream &output;
102         Parser *inclToParser;
103         char *inclSectionTarg;
104         int includeDepth;
105
106         int cs;
107         int line;
108         char *word, *lit;
109         int word_len, lit_len;
110         InputLoc sectionLoc;
111         char *tokstart, *tokend;
112         int column;
113         char *lastnl;
114
115         /* Set by machine statements, these persist from section to section
116          * allowing for unnamed sections. */
117         Parser *parser;
118         bool ignoreSection;
119         IncludeStack includeStack;
120
121         /* This is set if ragel has already emitted an error stating that
122          * no section name has been seen and thus no parser exists. */
123         bool parserExistsError;
124
125         /* This is for inline code. By default it is on. It goes off for
126          * statements and values in inline blocks which are parsed. */
127         bool whitespaceOn;
128 };
129
130 %%{
131         machine section_parse;
132         alphtype int;
133         write data;
134 }%%
135
136 void Scanner::init( )
137 {
138         %% write init;
139 }
140
141 bool Scanner::active()
142 {
143         if ( ignoreSection )
144                 return false;
145
146         if ( parser == 0 && ! parserExistsError ) {
147                 scan_error() << "there is no previous specification name" << endl;
148                 parserExistsError = true;
149         }
150
151         if ( parser == 0 )
152                 return false;
153
154         return true;
155 }
156
157 ostream &Scanner::scan_error()
158 {
159         /* Maintain the error count. */
160         gblErrorCount += 1;
161         cerr << fileName << ":" << line << ":" << column << ": ";
162         return cerr;
163 }
164
165 bool Scanner::recursiveInclude( char *inclFileName, char *inclSectionName )
166 {
167         for ( IncludeStack::Iter si = includeStack; si.lte(); si++ ) {
168                 if ( strcmp( si->fileName, inclFileName ) == 0 &&
169                                 strcmp( si->sectionName, inclSectionName ) == 0 )
170                 {
171                         return true;
172                 }
173         }
174         return false;   
175 }
176
177 void Scanner::updateCol()
178 {
179         char *from = lastnl;
180         if ( from == 0 )
181                 from = tokstart;
182         //cerr << "adding " << tokend - from << " to column" << endl;
183         column += tokend - from;
184         lastnl = 0;
185 }
186
187 void Scanner::token( int type, char c )
188 {
189         token( type, &c, &c + 1 );
190 }
191
192 void Scanner::token( int type )
193 {
194         token( type, 0, 0 );
195 }
196
197 %%{
198         machine section_parse;
199
200         # This relies on the the kelbt implementation and the order
201         # that tokens are declared.
202         KW_Machine = 128;
203         KW_Include = 129;
204         KW_Write = 130;
205         TK_Word = 131;
206         TK_Literal = 132;
207
208         action clear_words { word = lit = 0; word_len = lit_len = 0; }
209         action store_word { word = tokdata; word_len = toklen; }
210         action store_lit { lit = tokdata; lit_len = toklen; }
211
212         action mach_err { scan_error() << "bad machine statement" << endl; }
213         action incl_err { scan_error() << "bad include statement" << endl; }
214         action write_err { scan_error() << "bad write statement" << endl; }
215
216         action handle_machine
217         {
218                 /* Assign a name to the machine. */
219                 char *machine = word;
220
221                 if ( inclSectionTarg == 0 ) {
222                         ignoreSection = false;
223
224                         ParserDictEl *pdEl = parserDict.find( machine );
225                         if ( pdEl == 0 ) {
226                                 pdEl = new ParserDictEl( machine );
227                                 pdEl->value = new Parser( fileName, machine, sectionLoc );
228                                 pdEl->value->init();
229                                 parserDict.insert( pdEl );
230                         }
231
232                         parser = pdEl->value;
233                 }
234                 else if ( strcmp( inclSectionTarg, machine ) == 0 ) {
235                         /* found include target */
236                         ignoreSection = false;
237                         parser = inclToParser;
238                 }
239                 else {
240                         /* ignoring section */
241                         ignoreSection = true;
242                         parser = 0;
243                 }
244         }
245
246         machine_stmt =
247                 ( KW_Machine TK_Word @store_word ';' ) @handle_machine
248                 <>err mach_err <>eof mach_err;
249
250         action handle_include
251         {
252                 if ( active() ) {
253                         char *inclSectionName = word;
254                         char *inclFileName = 0;
255
256                         /* Implement defaults for the input file and section name. */
257                         if ( inclSectionName == 0 )
258                                 inclSectionName = parser->sectionName;
259
260                         if ( lit != 0 ) 
261                                 inclFileName = prepareFileName( lit, lit_len );
262                         else
263                                 inclFileName = fileName;
264
265                         /* Check for a recursive include structure. Add the current file/section
266                          * name then check if what we are including is already in the stack. */
267                         includeStack.append( IncludeStackItem( fileName, parser->sectionName ) );
268
269                         if ( recursiveInclude( inclFileName, inclSectionName ) )
270                                 scan_error() << "include: this is a recursive include operation" << endl;
271                         else {
272                                 /* Open the input file for reading. */
273                                 ifstream *inFile = new ifstream( inclFileName );
274                                 if ( ! inFile->is_open() ) {
275                                         scan_error() << "include: could not open " << 
276                                                         inclFileName << " for reading" << endl;
277                                 }
278
279                                 Scanner scanner( inclFileName, *inFile, output, parser,
280                                                 inclSectionName, includeDepth+1 );
281                                 scanner.init();
282                                 scanner.do_scan( );
283                                 delete inFile;
284                         }
285
286                         /* Remove the last element (len-1) */
287                         includeStack.remove( -1 );
288                 }
289         }
290
291         include_names = (
292                 TK_Word @store_word ( TK_Literal @store_lit )? |
293                 TK_Literal @store_lit
294         ) >clear_words;
295
296         include_stmt =
297                 ( KW_Include include_names ';' ) @handle_include
298                 <>err incl_err <>eof incl_err;
299
300         action write_command
301         {
302                 if ( active() && machineSpec == 0 && machineName == 0 ) {
303                         output << "<write"
304                                         " def_name=\"" << parser->sectionName << "\""
305                                         " line=\"" << line << "\""
306                                         " col=\"" << column << "\""
307                                         ">";
308                 }
309         }
310
311         action write_arg
312         {
313                 if ( active() && machineSpec == 0 && machineName == 0 )
314                         output << "<arg>" << tokdata << "</arg>";
315         }
316
317         action write_close
318         {
319                 if ( active() && machineSpec == 0 && machineName == 0 )
320                         output << "</write>\n";
321         }
322
323         write_stmt =
324                 ( KW_Write @write_command 
325                 ( TK_Word @write_arg )+ ';' @write_close )
326                 <>err write_err <>eof write_err;
327
328         action handle_token
329         {
330                 /* Send the token off to the parser. */
331                 if ( active() ) {
332                         InputLoc loc;
333
334                         #if 0
335                         cerr << "scanner:" << line << ":" << column << 
336                                         ": sending token to the parser " << Parser_lelNames[*p];
337                         cerr << " " << toklen;
338                         if ( tokdata != 0 )
339                                 cerr << " " << tokdata;
340                         cerr << endl;
341                         #endif
342
343                         loc.fileName = fileName;
344                         loc.line = line;
345                         loc.col = column;
346
347                         parser->token( loc, type, tokdata, toklen );
348                 }
349         }
350
351         # Catch everything else.
352         everything_else = ^( KW_Machine | KW_Include | KW_Write ) @handle_token;
353
354         main := ( 
355                 machine_stmt |
356                 include_stmt |
357                 write_stmt |
358                 everything_else
359         )*;
360 }%%
361
362 void Scanner::token( int type, char *start, char *end )
363 {
364         char *tokdata = 0;
365         int toklen = 0;
366         int *p = &type;
367         int *pe = &type + 1;
368
369         if ( start != 0 ) {
370                 toklen = end-start;
371                 tokdata = new char[toklen+1];
372                 memcpy( tokdata, start, toklen );
373                 tokdata[toklen] = 0;
374         }
375
376         %%{
377                 machine section_parse;
378                 write exec;
379         }%%
380
381         updateCol();
382 }
383
384 void Scanner::startSection( )
385 {
386         parserExistsError = false;
387
388         if ( includeDepth == 0 ) {
389                 if ( machineSpec == 0 && machineName == 0 )
390                         output << "</host>\n";
391         }
392
393         sectionLoc.fileName = fileName;
394         sectionLoc.line = line;
395         sectionLoc.col = 0;
396 }
397
398 void Scanner::endSection( )
399 {
400         /* Execute the eof actions for the section parser. */
401         %%{
402                 machine section_parse;
403                 write eof;
404         }%%
405
406         /* Close off the section with the parser. */
407         if ( active() ) {
408                 InputLoc loc;
409                 loc.fileName = fileName;
410                 loc.line = line;
411                 loc.col = 0;
412
413                 parser->token( loc, TK_EndSection, 0, 0 );
414         }
415
416         if ( includeDepth == 0 ) {
417                 if ( machineSpec == 0 && machineName == 0 ) {
418                         /* The end section may include a newline on the end, so
419                          * we use the last line, which will count the newline. */
420                         output << "<host line=\"" << line << "\">";
421                 }
422         }
423 }
424
425 %%{
426         machine rlscan;
427
428         # This is sent by the driver code.
429         EOF = 0;
430         
431         action inc_nl { 
432                 lastnl = p; 
433                 column = 0;
434                 line++;
435         }
436         NL = '\n' @inc_nl;
437
438         # Identifiers, numbers, commetns, and other common things.
439         ident = ( alpha | '_' ) ( alpha |digit |'_' )*;
440         number = digit+;
441         hex_number = '0x' [0-9a-fA-F]+;
442
443         c_comment = 
444                 '/*' ( any | NL )* :>> '*/';
445
446         cpp_comment =
447                 '//' [^\n]* NL;
448
449         c_cpp_comment = c_comment | cpp_comment;
450
451         # These literal forms are common to C-like host code and ragel.
452         s_literal = "'" ([^'\\] | NL | '\\' (any | NL))* "'";
453         d_literal = '"' ([^"\\] | NL | '\\' (any | NL))* '"';
454
455         whitespace = [ \t] | NL;
456         pound_comment = '#' [^\n]* NL;
457
458         # An inline block of code. This is specified as a scanned, but is sent to
459         # the parser as one long block. The inline_block pointer is used to handle
460         # the preservation of the data.
461         inline_code := |*
462                 # Inline expression keywords.
463                 "fpc" => { token( KW_PChar ); };
464                 "fc" => { token( KW_Char ); };
465                 "fcurs" => { token( KW_CurState ); };
466                 "ftargs" => { token( KW_TargState ); };
467                 "fentry" => { 
468                         whitespaceOn = false; 
469                         token( KW_Entry );
470                 };
471
472                 # Inline statement keywords.
473                 "fhold" => { 
474                         whitespaceOn = false; 
475                         token( KW_Hold );
476                 };
477                 "fexec" => { token( KW_Exec, 0, 0 ); };
478                 "fgoto" => { 
479                         whitespaceOn = false; 
480                         token( KW_Goto );
481                 };
482                 "fnext" => { 
483                         whitespaceOn = false; 
484                         token( KW_Next );
485                 };
486                 "fcall" => { 
487                         whitespaceOn = false; 
488                         token( KW_Call );
489                 };
490                 "fret" => { 
491                         whitespaceOn = false; 
492                         token( KW_Ret );
493                 };
494                 "fbreak" => { 
495                         whitespaceOn = false; 
496                         token( KW_Break );
497                 };
498
499                 ident => { token( TK_Word, tokstart, tokend ); };
500
501                 number => { token( TK_UInt, tokstart, tokend ); };
502                 hex_number => { token( TK_Hex, tokstart, tokend ); };
503
504                 ( s_literal | d_literal ) 
505                         => { token( IL_Literal, tokstart, tokend ); };
506
507                 whitespace+ => { 
508                         if ( whitespaceOn ) 
509                                 token( IL_WhiteSpace, tokstart, tokend );
510                 };
511                 c_cpp_comment => { token( IL_Comment, tokstart, tokend ); };
512
513                 "::" => { token( TK_NameSep, tokstart, tokend ); };
514
515                 # Some symbols need to go to the parser as with their cardinal value as
516                 # the token type (as opposed to being sent as anonymous symbols)
517                 # because they are part of the sequences which we interpret. The * ) ;
518                 # symbols cause whitespace parsing to come back on. This gets turned
519                 # off by some keywords.
520
521                 ";" => {
522                         whitespaceOn = true;
523                         token( *tokstart, tokstart, tokend );
524                         if ( inlineBlockType == SemiTerminated )
525                                 fgoto parser_def;
526                 };
527
528                 [*)] => { 
529                         whitespaceOn = true;
530                         token( *tokstart, tokstart, tokend );
531                 };
532
533                 [,(] => { token( *tokstart, tokstart, tokend ); };
534
535                 '{' => { 
536                         token( IL_Symbol, tokstart, tokend );
537                         curly_count += 1; 
538                 };
539
540                 '}' => { 
541                         if ( --curly_count == 0 && inlineBlockType == CurlyDelimited ) {
542                                 /* Inline code block ends. */
543                                 token( '}' );
544                                 fgoto parser_def;
545                         }
546                         else {
547                                 /* Either a semi terminated inline block or only the closing
548                                  * brace of some inner scope, not the block's closing brace. */
549                                 token( IL_Symbol, tokstart, tokend );
550                         }
551                 };
552
553                 EOF => {
554                         scan_error() << "unterminated code block" << endl;
555                 };
556
557                 # Send every other character as a symbol.
558                 any => { token( IL_Symbol, tokstart, tokend ); };
559         *|;
560
561         or_literal := |*
562                 # Escape sequences in OR expressions.
563                 '\\0' => { token( RE_Char, '\0' ); };
564                 '\\a' => { token( RE_Char, '\a' ); };
565                 '\\b' => { token( RE_Char, '\b' ); };
566                 '\\t' => { token( RE_Char, '\t' ); };
567                 '\\n' => { token( RE_Char, '\n' ); };
568                 '\\v' => { token( RE_Char, '\v' ); };
569                 '\\f' => { token( RE_Char, '\f' ); };
570                 '\\r' => { token( RE_Char, '\r' ); };
571                 '\\\n' => { updateCol(); };
572                 '\\' any => { token( RE_Char, tokstart+1, tokend ); };
573
574                 # Range dash in an OR expression.
575                 '-' => { token( RE_Dash, 0, 0 ); };
576
577                 # Terminate an OR expression.
578                 ']'     => { token( RE_SqClose ); fret; };
579
580                 EOF => {
581                         scan_error() << "unterminated OR literal" << endl;
582                 };
583
584                 # Characters in an OR expression.
585                 [^\]] => { token( RE_Char, tokstart, tokend ); };
586
587         *|;
588
589         re_literal := |*
590                 # Escape sequences in regular expressions.
591                 '\\0' => { token( RE_Char, '\0' ); };
592                 '\\a' => { token( RE_Char, '\a' ); };
593                 '\\b' => { token( RE_Char, '\b' ); };
594                 '\\t' => { token( RE_Char, '\t' ); };
595                 '\\n' => { token( RE_Char, '\n' ); };
596                 '\\v' => { token( RE_Char, '\v' ); };
597                 '\\f' => { token( RE_Char, '\f' ); };
598                 '\\r' => { token( RE_Char, '\r' ); };
599                 '\\\n' => { updateCol(); };
600                 '\\' any => { token( RE_Char, tokstart+1, tokend ); };
601
602                 # Terminate an OR expression.
603                 '/' [i]? => { 
604                         token( RE_Slash, tokstart, tokend ); 
605                         fgoto parser_def;
606                 };
607
608                 # Special characters.
609                 '.' => { token( RE_Dot ); };
610                 '*' => { token( RE_Star ); };
611
612                 '[' => { token( RE_SqOpen ); fcall or_literal; };
613                 '[^' => { token( RE_SqOpenNeg ); fcall or_literal; };
614
615                 EOF => {
616                         scan_error() << "unterminated regular expression" << endl;
617                 };
618
619                 # Characters in an OR expression.
620                 [^\/] => { token( RE_Char, tokstart, tokend ); };
621         *|;
622
623         # We need a separate token space here to avoid the ragel keywords.
624         write_statement := |*
625                 ident => { token( TK_Word, tokstart, tokend ); } ;
626                 [ \t\n]+ => { updateCol(); };
627                 ';' => { token( ';' ); fgoto parser_def; };
628
629                 EOF => {
630                         scan_error() << "unterminated write statement" << endl;
631                 };
632         *|;
633
634         # Parser definitions. 
635         parser_def := |*
636                 'machine' => { token( KW_Machine ); };
637                 'include' => { token( KW_Include ); };
638                 'write' => { 
639                         token( KW_Write );
640                         fgoto write_statement;
641                 };
642                 'action' => { token( KW_Action ); };
643                 'alphtype' => { token( KW_AlphType ); };
644
645                 # FIXME: Enable this post 5.17.
646                 # 'range' => { token( KW_Range ); };
647
648                 'getkey' => { 
649                         token( KW_GetKey );
650                         inlineBlockType = SemiTerminated;
651                         fgoto inline_code;
652                 };
653                 'access' => { 
654                         token( KW_Access );
655                         inlineBlockType = SemiTerminated;
656                         fgoto inline_code;
657                 };
658                 'variable' => { 
659                         token( KW_Variable );
660                         inlineBlockType = SemiTerminated;
661                         fgoto inline_code;
662                 };
663                 'when' => { token( KW_When ); };
664                 'eof' => { token( KW_Eof ); };
665                 'err' => { token( KW_Err ); };
666                 'lerr' => { token( KW_Lerr ); };
667                 'to' => { token( KW_To ); };
668                 'from' => { token( KW_From ); };
669
670                 # Identifiers.
671                 ident => { token( TK_Word, tokstart, tokend ); } ;
672
673                 # Numbers
674                 number => { token( TK_UInt, tokstart, tokend ); };
675                 hex_number => { token( TK_Hex, tokstart, tokend ); };
676
677                 # Literals, with optionals.
678                 ( s_literal | d_literal ) [i]? 
679                         => { token( TK_Literal, tokstart, tokend ); };
680
681                 '[' => { token( RE_SqOpen ); fcall or_literal; };
682                 '[^' => { token( RE_SqOpenNeg ); fcall or_literal; };
683
684                 '/' => { token( RE_Slash ); fgoto re_literal; };
685
686                 # Ignore.
687                 pound_comment => { updateCol(); };
688
689                 ':=' => { token( TK_ColonEquals ); };
690
691                 # To State Actions.
692                 ">~" => { token( TK_StartToState ); };
693                 "$~" => { token( TK_AllToState ); };
694                 "%~" => { token( TK_FinalToState ); };
695                 "<~" => { token( TK_NotStartToState ); };
696                 "@~" => { token( TK_NotFinalToState ); };
697                 "<>~" => { token( TK_MiddleToState ); };
698
699                 # From State actions
700                 ">*" => { token( TK_StartFromState ); };
701                 "$*" => { token( TK_AllFromState ); };
702                 "%*" => { token( TK_FinalFromState ); };
703                 "<*" => { token( TK_NotStartFromState ); };
704                 "@*" => { token( TK_NotFinalFromState ); };
705                 "<>*" => { token( TK_MiddleFromState ); };
706
707                 # EOF Actions.
708                 ">/" => { token( TK_StartEOF ); };
709                 "$/" => { token( TK_AllEOF ); };
710                 "%/" => { token( TK_FinalEOF ); };
711                 "</" => { token( TK_NotStartEOF ); };
712                 "@/" => { token( TK_NotFinalEOF ); };
713                 "<>/" => { token( TK_MiddleEOF ); };
714
715                 # Global Error actions.
716                 ">!" => { token( TK_StartGblError ); };
717                 "$!" => { token( TK_AllGblError ); };
718                 "%!" => { token( TK_FinalGblError ); };
719                 "<!" => { token( TK_NotStartGblError ); };
720                 "@!" => { token( TK_NotFinalGblError ); };
721                 "<>!" => { token( TK_MiddleGblError ); };
722
723                 # Local error actions.
724                 ">^" => { token( TK_StartLocalError ); };
725                 "$^" => { token( TK_AllLocalError ); };
726                 "%^" => { token( TK_FinalLocalError ); };
727                 "<^" => { token( TK_NotStartLocalError ); };
728                 "@^" => { token( TK_NotFinalLocalError ); };
729                 "<>^" => { token( TK_MiddleLocalError ); };
730
731                 # Middle.
732                 "<>" => { token( TK_Middle ); };
733
734                 # Conditions. 
735                 '>?' => { token( TK_StartCond ); };
736                 '$?' => { token( TK_AllCond ); };
737                 '%?' => { token( TK_LeavingCond ); };
738
739                 '..' => { token( TK_DotDot ); };
740                 '**' => { token( TK_StarStar ); };
741                 '--' => { token( TK_DashDash ); };
742                 '->' => { token( TK_Arrow ); };
743                 '=>' => { token( TK_DoubleArrow ); };
744
745                 ":>"  => { token( TK_ColonGt ); };
746                 ":>>" => { token( TK_ColonGtGt ); };
747                 "<:"  => { token( TK_LtColon ); };
748
749                 # Opening of longest match.
750                 "|*" => { token( TK_BarStar ); };
751
752                 '}%%' => { 
753                         updateCol();
754                         endSection();
755                         fgoto main;
756                 };
757
758                 [ \t\r]+ => { updateCol(); };
759
760                 # If we are in a single line machine then newline may end the spec.
761                 NL => {
762                         updateCol();
763                         if ( singleLineSpec ) {
764                                 endSection();
765                                 fgoto main;
766                         }
767                 };
768
769                 '{' => { 
770                         token( '{' );
771                         curly_count = 1; 
772                         inlineBlockType = CurlyDelimited;
773                         fgoto inline_code;
774                 };
775
776                 EOF => {
777                         scan_error() << "unterminated ragel section" << endl;
778                 };
779
780                 any => { token( *tokstart ); } ;
781         *|;
782
783         action pass {
784                 updateCol();
785
786                 /* If no errors and we are at the bottom of the include stack (the
787                  * source file listed on the command line) then write out the data. */
788                 if ( includeDepth == 0 && machineSpec == 0 && machineName == 0 )
789                         xmlEscapeHost( output, tokstart, tokend-tokstart );
790         }
791
792         # Outside code scanner. These tokens get passed through.
793         main := |*
794                 ident => pass;
795                 number => pass;
796                 c_cpp_comment => pass;
797                 s_literal | d_literal => pass;
798                 '%%{' => { 
799                         updateCol();
800                         singleLineSpec = false;
801                         startSection();
802                         fgoto parser_def;
803                 };
804                 '%%' => { 
805                         updateCol();
806                         singleLineSpec = true;
807                         startSection();
808                         fgoto parser_def;
809                 };
810                 whitespace+ => pass;
811                 EOF;
812                 any => pass;
813         *|;
814
815 }%%
816
817 %% write data;
818
819 void Scanner::do_scan()
820 {
821         int bufsize = 8;
822         char *buf = new char[bufsize];
823         const char last_char = 0;
824         int cs, act, have = 0;
825         int top, stack[1];
826         int curly_count = 0;
827         bool execute = true;
828         bool singleLineSpec = false;
829         InlineBlockType inlineBlockType;
830
831         %% write init;
832
833         while ( execute ) {
834                 char *p = buf + have;
835                 int space = bufsize - have;
836
837                 if ( space == 0 ) {
838                         /* We filled up the buffer trying to scan a token. Grow it. */
839                         bufsize = bufsize * 2;
840                         char *newbuf = new char[bufsize];
841
842                         /* Recompute p and space. */
843                         p = newbuf + have;
844                         space = bufsize - have;
845
846                         /* Patch up pointers possibly in use. */
847                         if ( tokstart != 0 )
848                                 tokstart = newbuf + ( tokstart - buf );
849                         tokend = newbuf + ( tokend - buf );
850
851                         /* Copy the new buffer in. */
852                         memcpy( newbuf, buf, have );
853                         delete[] buf;
854                         buf = newbuf;
855                 }
856
857                 input.read( p, space );
858                 int len = input.gcount();
859
860                 /* If we see eof then append the EOF char. */
861                 if ( len == 0 ) {
862                         p[0] = last_char, len = 1;
863                         execute = false;
864                 }
865
866                 char *pe = p + len;
867                 %% write exec;
868
869                 /* Check if we failed. */
870                 if ( cs == rlscan_error ) {
871                         /* Machine failed before finding a token. I'm not yet sure if this
872                          * is reachable. */
873                         scan_error() << "scanner error" << endl;
874                         exit(1);
875                 }
876
877                 /* Decide if we need to preserve anything. */
878                 char *preserve = tokstart;
879
880                 /* Now set up the prefix. */
881                 if ( preserve == 0 )
882                         have = 0;
883                 else {
884                         /* There is data that needs to be shifted over. */
885                         have = pe - preserve;
886                         memmove( buf, preserve, have );
887                         unsigned int shiftback = preserve - buf;
888                         if ( tokstart != 0 )
889                                 tokstart -= shiftback;
890                         tokend -= shiftback;
891
892                         preserve = buf;
893                 }
894         }
895
896         delete[] buf;
897 }
898
899 void scan( char *fileName, istream &input, ostream &output )
900 {
901         Scanner scanner( fileName, input, output, 0, 0, 0 );
902         scanner.init();
903         scanner.do_scan();
904
905         InputLoc eofLoc;
906         eofLoc.fileName = fileName;
907         eofLoc.col = 1;
908         eofLoc.line = scanner.line;
909 }