2 * Copyright 2006-2007 Adrian Thurston <thurston@cs.queensu.ca>
5 /* This file is part of Ragel.
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.
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.
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
46 * The Scanner for Importing
50 machine inline_token_scan;
54 # Import scanner tokens.
59 IMP_Define IMP_Word IMP_UInt => {
60 int base = tok_ts - token_data;
64 directToParser( inclToParser, fileName, line, column, TK_Word,
65 token_strings[base+nameOff], token_lens[base+nameOff] );
66 directToParser( inclToParser, fileName, line, column, '=', 0, 0 );
67 directToParser( inclToParser, fileName, line, column, TK_UInt,
68 token_strings[base+numOff], token_lens[base+numOff] );
69 directToParser( inclToParser, fileName, line, column, ';', 0, 0 );
72 # Assignment of number.
73 IMP_Word '=' IMP_UInt => {
74 int base = tok_ts - token_data;
78 directToParser( inclToParser, fileName, line, column, TK_Word,
79 token_strings[base+nameOff], token_lens[base+nameOff] );
80 directToParser( inclToParser, fileName, line, column, '=', 0, 0 );
81 directToParser( inclToParser, fileName, line, column, TK_UInt,
82 token_strings[base+numOff], token_lens[base+numOff] );
83 directToParser( inclToParser, fileName, line, column, ';', 0, 0 );
87 IMP_Define IMP_Word IMP_Literal => {
88 int base = tok_ts - token_data;
92 directToParser( inclToParser, fileName, line, column, TK_Word,
93 token_strings[base+nameOff], token_lens[base+nameOff] );
94 directToParser( inclToParser, fileName, line, column, '=', 0, 0 );
95 directToParser( inclToParser, fileName, line, column, TK_Literal,
96 token_strings[base+litOff], token_lens[base+litOff] );
97 directToParser( inclToParser, fileName, line, column, ';', 0, 0 );
100 # Assignment of literal.
101 IMP_Word '=' IMP_Literal => {
102 int base = tok_ts - token_data;
106 directToParser( inclToParser, fileName, line, column, TK_Word,
107 token_strings[base+nameOff], token_lens[base+nameOff] );
108 directToParser( inclToParser, fileName, line, column, '=', 0, 0 );
109 directToParser( inclToParser, fileName, line, column, TK_Literal,
110 token_strings[base+litOff], token_lens[base+litOff] );
111 directToParser( inclToParser, fileName, line, column, ';', 0, 0 );
114 # Catch everything else.
121 void Scanner::flushImport()
124 int *pe = token_data + cur_token;
128 machine inline_token_scan;
136 cur_token = pe - tok_ts;
137 int ts_offset = tok_ts - token_data;
138 memmove( token_data, token_data+ts_offset, cur_token*sizeof(token_data[0]) );
139 memmove( token_strings, token_strings+ts_offset, cur_token*sizeof(token_strings[0]) );
140 memmove( token_lens, token_lens+ts_offset, cur_token*sizeof(token_lens[0]) );
144 void Scanner::directToParser( Parser *toParser, char *tokFileName, int tokLine,
145 int tokColumn, int type, char *tokdata, int toklen )
150 cerr << "scanner:" << tokLine << ":" << tokColumn <<
151 ": sending token to the parser " << Parser_lelNames[type];
152 cerr << " " << toklen;
154 cerr << " " << tokdata;
158 loc.fileName = tokFileName;
162 toParser->token( loc, type, tokdata, toklen );
165 void Scanner::importToken( int token, char *start, char *end )
167 if ( cur_token == max_tokens )
170 token_data[cur_token] = token;
172 token_strings[cur_token] = 0;
173 token_lens[cur_token] = 0;
176 int toklen = end-start;
177 token_lens[cur_token] = toklen;
178 token_strings[cur_token] = new char[toklen+1];
179 memcpy( token_strings[cur_token], start, toklen );
180 token_strings[cur_token][toklen] = 0;
185 void Scanner::pass( int token, char *start, char *end )
187 if ( importMachines )
188 importToken( token, start, end );
196 /* If no errors and we are at the bottom of the include stack (the
197 * source file listed on the command line) then write out the data. */
198 if ( includeDepth == 0 && machineSpec == 0 && machineName == 0 )
199 xmlEscapeHost( output, ts, te-ts );
203 * The scanner for processing sections, includes, imports, etc.
207 machine section_parse;
213 void Scanner::init( )
218 bool Scanner::active()
223 if ( parser == 0 && ! parserExistsError ) {
224 scan_error() << "this specification has no name, nor does any previous"
225 " specification" << endl;
226 parserExistsError = true;
235 ostream &Scanner::scan_error()
237 /* Maintain the error count. */
239 cerr << fileName << ":" << line << ":" << column << ": ";
243 bool Scanner::recursiveInclude( char *inclFileName, char *inclSectionName )
245 for ( IncludeStack::Iter si = includeStack; si.lte(); si++ ) {
246 if ( strcmp( si->fileName, inclFileName ) == 0 &&
247 strcmp( si->sectionName, inclSectionName ) == 0 )
255 void Scanner::updateCol()
260 //cerr << "adding " << te - from << " to column" << endl;
266 machine section_parse;
268 # Need the defines representing tokens.
271 action clear_words { word = lit = 0; word_len = lit_len = 0; }
272 action store_word { word = tokdata; word_len = toklen; }
273 action store_lit { lit = tokdata; lit_len = toklen; }
275 action mach_err { scan_error() << "bad machine statement" << endl; }
276 action incl_err { scan_error() << "bad include statement" << endl; }
277 action import_err { scan_error() << "bad import statement" << endl; }
278 action write_err { scan_error() << "bad write statement" << endl; }
280 action handle_machine
282 /* Assign a name to the machine. */
283 char *machine = word;
285 if ( !importMachines && inclSectionTarg == 0 ) {
286 ignoreSection = false;
288 ParserDictEl *pdEl = parserDict.find( machine );
290 pdEl = new ParserDictEl( machine );
291 pdEl->value = new Parser( fileName, machine, sectionLoc );
293 parserDict.insert( pdEl );
296 parser = pdEl->value;
298 else if ( !importMachines && strcmp( inclSectionTarg, machine ) == 0 ) {
299 /* found include target */
300 ignoreSection = false;
301 parser = inclToParser;
304 /* ignoring section */
305 ignoreSection = true;
311 ( KW_Machine TK_Word @store_word ';' ) @handle_machine
312 <>err mach_err <>eof mach_err;
314 action handle_include
317 char *inclSectionName = word;
318 char *inclFileName = 0;
320 /* Implement defaults for the input file and section name. */
321 if ( inclSectionName == 0 )
322 inclSectionName = parser->sectionName;
325 inclFileName = prepareFileName( lit, lit_len );
327 inclFileName = fileName;
329 /* Check for a recursive include structure. Add the current file/section
330 * name then check if what we are including is already in the stack. */
331 includeStack.append( IncludeStackItem( fileName, parser->sectionName ) );
333 if ( recursiveInclude( inclFileName, inclSectionName ) )
334 scan_error() << "include: this is a recursive include operation" << endl;
336 /* Open the input file for reading. */
337 ifstream *inFile = new ifstream( inclFileName );
338 if ( ! inFile->is_open() ) {
339 scan_error() << "include: could not open " <<
340 inclFileName << " for reading" << endl;
343 Scanner scanner( inclFileName, *inFile, output, parser,
344 inclSectionName, includeDepth+1, false );
349 /* Remove the last element (len-1) */
350 includeStack.remove( -1 );
355 TK_Word @store_word ( TK_Literal @store_lit )? |
356 TK_Literal @store_lit
360 ( KW_Include include_names ';' ) @handle_include
361 <>err incl_err <>eof incl_err;
366 char *importFileName = prepareFileName( lit, lit_len );
368 /* Open the input file for reading. */
369 ifstream *inFile = new ifstream( importFileName );
370 if ( ! inFile->is_open() ) {
371 scan_error() << "import: could not open " <<
372 importFileName << " for reading" << endl;
375 Scanner scanner( importFileName, *inFile, output, parser,
376 0, includeDepth+1, true );
378 scanner.importToken( 0, 0, 0 );
379 scanner.flushImport();
385 ( KW_Import TK_Literal @store_lit ';' ) @handle_import
386 <>err import_err <>eof import_err;
390 if ( active() && machineSpec == 0 && machineName == 0 ) {
392 " def_name=\"" << parser->sectionName << "\""
393 " line=\"" << line << "\""
394 " col=\"" << column << "\""
401 if ( active() && machineSpec == 0 && machineName == 0 )
402 output << "<arg>" << tokdata << "</arg>";
407 if ( active() && machineSpec == 0 && machineName == 0 )
408 output << "</write>\n";
412 ( KW_Write @write_command
413 ( TK_Word @write_arg )+ ';' @write_close )
414 <>err write_err <>eof write_err;
418 /* Send the token off to the parser. */
420 directToParser( parser, fileName, line, column, type, tokdata, toklen );
423 # Catch everything else.
425 ^( KW_Machine | KW_Include | KW_Import | KW_Write ) @handle_token;
436 void Scanner::token( int type, char c )
438 token( type, &c, &c + 1 );
441 void Scanner::token( int type )
446 void Scanner::token( int type, char *start, char *end )
452 tokdata = new char[toklen+1];
453 memcpy( tokdata, start, toklen );
457 processToken( type, tokdata, toklen );
460 void Scanner::processToken( int type, char *tokdata, int toklen )
474 machine section_parse;
480 /* Record the last token for use in controlling the scan of subsequent
485 void Scanner::startSection( )
487 parserExistsError = false;
489 if ( includeDepth == 0 ) {
490 if ( machineSpec == 0 && machineName == 0 )
491 output << "</host>\n";
494 sectionLoc.fileName = fileName;
495 sectionLoc.line = line;
499 void Scanner::endSection( )
501 /* Execute the eof actions for the section parser. */
502 processToken( -1, 0, 0 );
504 /* Close off the section with the parser. */
507 loc.fileName = fileName;
511 parser->token( loc, TK_EndSection, 0, 0 );
514 if ( includeDepth == 0 ) {
515 if ( machineSpec == 0 && machineName == 0 ) {
516 /* The end section may include a newline on the end, so
517 * we use the last line, which will count the newline. */
518 output << "<host line=\"" << line << "\">";
526 # This is sent by the driver code.
536 # Identifiers, numbers, commetns, and other common things.
537 ident = ( alpha | '_' ) ( alpha |digit |'_' )*;
539 hex_number = '0x' [0-9a-fA-F]+;
542 '/*' ( any | NL )* :>> '*/';
547 c_cpp_comment = c_comment | cpp_comment;
549 ruby_comment = '#' [^\n]* NL;
551 # These literal forms are common to host code and ragel.
552 s_literal = "'" ([^'\\] | NL | '\\' (any | NL))* "'";
553 d_literal = '"' ([^"\\] | NL | '\\' (any | NL))* '"';
554 host_re_literal = '/' ([^/\\] | NL | '\\' (any | NL))* '/';
556 whitespace = [ \t] | NL;
557 pound_comment = '#' [^\n]* NL;
559 # An inline block of code for Ruby.
560 inline_code_ruby := |*
561 # Inline expression keywords.
562 "fpc" => { token( KW_PChar ); };
563 "fc" => { token( KW_Char ); };
564 "fcurs" => { token( KW_CurState ); };
565 "ftargs" => { token( KW_TargState ); };
567 whitespaceOn = false;
571 # Inline statement keywords.
573 whitespaceOn = false;
576 "fexec" => { token( KW_Exec, 0, 0 ); };
578 whitespaceOn = false;
582 whitespaceOn = false;
586 whitespaceOn = false;
590 whitespaceOn = false;
594 whitespaceOn = false;
598 ident => { token( TK_Word, ts, te ); };
600 number => { token( TK_UInt, ts, te ); };
601 hex_number => { token( TK_Hex, ts, te ); };
603 ( s_literal | d_literal | host_re_literal )
604 => { token( IL_Literal, ts, te ); };
608 token( IL_WhiteSpace, ts, te );
611 ruby_comment => { token( IL_Comment, ts, te ); };
613 "::" => { token( TK_NameSep, ts, te ); };
615 # Some symbols need to go to the parser as with their cardinal value as
616 # the token type (as opposed to being sent as anonymous symbols)
617 # because they are part of the sequences which we interpret. The * ) ;
618 # symbols cause whitespace parsing to come back on. This gets turned
619 # off by some keywords.
623 token( *ts, ts, te );
624 if ( inlineBlockType == SemiTerminated )
630 token( *ts, ts, te );
633 [,(] => { token( *ts, ts, te ); };
636 token( IL_Symbol, ts, te );
641 if ( --curly_count == 0 && inlineBlockType == CurlyDelimited ) {
642 /* Inline code block ends. */
647 /* Either a semi terminated inline block or only the closing
648 * brace of some inner scope, not the block's closing brace. */
649 token( IL_Symbol, ts, te );
654 scan_error() << "unterminated code block" << endl;
657 # Send every other character as a symbol.
658 any => { token( IL_Symbol, ts, te ); };
662 # An inline block of code for languages other than Ruby.
664 # Inline expression keywords.
665 "fpc" => { token( KW_PChar ); };
666 "fc" => { token( KW_Char ); };
667 "fcurs" => { token( KW_CurState ); };
668 "ftargs" => { token( KW_TargState ); };
670 whitespaceOn = false;
674 # Inline statement keywords.
676 whitespaceOn = false;
679 "fexec" => { token( KW_Exec, 0, 0 ); };
681 whitespaceOn = false;
685 whitespaceOn = false;
689 whitespaceOn = false;
693 whitespaceOn = false;
697 whitespaceOn = false;
701 ident => { token( TK_Word, ts, te ); };
703 number => { token( TK_UInt, ts, te ); };
704 hex_number => { token( TK_Hex, ts, te ); };
706 ( s_literal | d_literal )
707 => { token( IL_Literal, ts, te ); };
711 token( IL_WhiteSpace, ts, te );
714 c_cpp_comment => { token( IL_Comment, ts, te ); };
716 "::" => { token( TK_NameSep, ts, te ); };
718 # Some symbols need to go to the parser as with their cardinal value as
719 # the token type (as opposed to being sent as anonymous symbols)
720 # because they are part of the sequences which we interpret. The * ) ;
721 # symbols cause whitespace parsing to come back on. This gets turned
722 # off by some keywords.
726 token( *ts, ts, te );
727 if ( inlineBlockType == SemiTerminated )
733 token( *ts, ts, te );
736 [,(] => { token( *ts, ts, te ); };
739 token( IL_Symbol, ts, te );
744 if ( --curly_count == 0 && inlineBlockType == CurlyDelimited ) {
745 /* Inline code block ends. */
750 /* Either a semi terminated inline block or only the closing
751 * brace of some inner scope, not the block's closing brace. */
752 token( IL_Symbol, ts, te );
757 scan_error() << "unterminated code block" << endl;
760 # Send every other character as a symbol.
761 any => { token( IL_Symbol, ts, te ); };
765 # Escape sequences in OR expressions.
766 '\\0' => { token( RE_Char, '\0' ); };
767 '\\a' => { token( RE_Char, '\a' ); };
768 '\\b' => { token( RE_Char, '\b' ); };
769 '\\t' => { token( RE_Char, '\t' ); };
770 '\\n' => { token( RE_Char, '\n' ); };
771 '\\v' => { token( RE_Char, '\v' ); };
772 '\\f' => { token( RE_Char, '\f' ); };
773 '\\r' => { token( RE_Char, '\r' ); };
774 '\\\n' => { updateCol(); };
775 '\\' any => { token( RE_Char, ts+1, te ); };
777 # Range dash in an OR expression.
778 '-' => { token( RE_Dash, 0, 0 ); };
780 # Terminate an OR expression.
781 ']' => { token( RE_SqClose ); fret; };
784 scan_error() << "unterminated OR literal" << endl;
787 # Characters in an OR expression.
788 [^\]] => { token( RE_Char, ts, te ); };
792 ragel_re_literal := |*
793 # Escape sequences in regular expressions.
794 '\\0' => { token( RE_Char, '\0' ); };
795 '\\a' => { token( RE_Char, '\a' ); };
796 '\\b' => { token( RE_Char, '\b' ); };
797 '\\t' => { token( RE_Char, '\t' ); };
798 '\\n' => { token( RE_Char, '\n' ); };
799 '\\v' => { token( RE_Char, '\v' ); };
800 '\\f' => { token( RE_Char, '\f' ); };
801 '\\r' => { token( RE_Char, '\r' ); };
802 '\\\n' => { updateCol(); };
803 '\\' any => { token( RE_Char, ts+1, te ); };
805 # Terminate an OR expression.
807 token( RE_Slash, ts, te );
811 # Special characters.
812 '.' => { token( RE_Dot ); };
813 '*' => { token( RE_Star ); };
815 '[' => { token( RE_SqOpen ); fcall or_literal; };
816 '[^' => { token( RE_SqOpenNeg ); fcall or_literal; };
819 scan_error() << "unterminated regular expression" << endl;
822 # Characters in an OR expression.
823 [^\/] => { token( RE_Char, ts, te ); };
826 # We need a separate token space here to avoid the ragel keywords.
827 write_statement := |*
828 ident => { token( TK_Word, ts, te ); } ;
829 [ \t\n]+ => { updateCol(); };
830 ';' => { token( ';' ); fgoto parser_def; };
833 scan_error() << "unterminated write statement" << endl;
837 # Parser definitions.
839 'machine' => { token( KW_Machine ); };
840 'include' => { token( KW_Include ); };
841 'import' => { token( KW_Import ); };
844 fgoto write_statement;
846 'action' => { token( KW_Action ); };
847 'alphtype' => { token( KW_AlphType ); };
848 'prepush' => { token( KW_PrePush ); };
849 'postpop' => { token( KW_PostPop ); };
851 # FIXME: Enable this post 5.17.
852 # 'range' => { token( KW_Range ); };
856 inlineBlockType = SemiTerminated;
857 if ( hostLang->lang == HostLang::Ruby )
858 fcall inline_code_ruby;
864 inlineBlockType = SemiTerminated;
865 if ( hostLang->lang == HostLang::Ruby )
866 fcall inline_code_ruby;
871 token( KW_Variable );
872 inlineBlockType = SemiTerminated;
873 if ( hostLang->lang == HostLang::Ruby )
874 fcall inline_code_ruby;
878 'when' => { token( KW_When ); };
879 'inwhen' => { token( KW_InWhen ); };
880 'outwhen' => { token( KW_OutWhen ); };
881 'eof' => { token( KW_Eof ); };
882 'err' => { token( KW_Err ); };
883 'lerr' => { token( KW_Lerr ); };
884 'to' => { token( KW_To ); };
885 'from' => { token( KW_From ); };
886 'export' => { token( KW_Export ); };
889 ident => { token( TK_Word, ts, te ); } ;
892 number => { token( TK_UInt, ts, te ); };
893 hex_number => { token( TK_Hex, ts, te ); };
895 # Literals, with optionals.
896 ( s_literal | d_literal ) [i]?
897 => { token( TK_Literal, ts, te ); };
899 '[' => { token( RE_SqOpen ); fcall or_literal; };
900 '[^' => { token( RE_SqOpenNeg ); fcall or_literal; };
902 '/' => { token( RE_Slash ); fgoto ragel_re_literal; };
905 pound_comment => { updateCol(); };
907 ':=' => { token( TK_ColonEquals ); };
910 ">~" => { token( TK_StartToState ); };
911 "$~" => { token( TK_AllToState ); };
912 "%~" => { token( TK_FinalToState ); };
913 "<~" => { token( TK_NotStartToState ); };
914 "@~" => { token( TK_NotFinalToState ); };
915 "<>~" => { token( TK_MiddleToState ); };
918 ">*" => { token( TK_StartFromState ); };
919 "$*" => { token( TK_AllFromState ); };
920 "%*" => { token( TK_FinalFromState ); };
921 "<*" => { token( TK_NotStartFromState ); };
922 "@*" => { token( TK_NotFinalFromState ); };
923 "<>*" => { token( TK_MiddleFromState ); };
926 ">/" => { token( TK_StartEOF ); };
927 "$/" => { token( TK_AllEOF ); };
928 "%/" => { token( TK_FinalEOF ); };
929 "</" => { token( TK_NotStartEOF ); };
930 "@/" => { token( TK_NotFinalEOF ); };
931 "<>/" => { token( TK_MiddleEOF ); };
933 # Global Error actions.
934 ">!" => { token( TK_StartGblError ); };
935 "$!" => { token( TK_AllGblError ); };
936 "%!" => { token( TK_FinalGblError ); };
937 "<!" => { token( TK_NotStartGblError ); };
938 "@!" => { token( TK_NotFinalGblError ); };
939 "<>!" => { token( TK_MiddleGblError ); };
941 # Local error actions.
942 ">^" => { token( TK_StartLocalError ); };
943 "$^" => { token( TK_AllLocalError ); };
944 "%^" => { token( TK_FinalLocalError ); };
945 "<^" => { token( TK_NotStartLocalError ); };
946 "@^" => { token( TK_NotFinalLocalError ); };
947 "<>^" => { token( TK_MiddleLocalError ); };
950 "<>" => { token( TK_Middle ); };
953 '>?' => { token( TK_StartCond ); };
954 '$?' => { token( TK_AllCond ); };
955 '%?' => { token( TK_LeavingCond ); };
957 '..' => { token( TK_DotDot ); };
958 '**' => { token( TK_StarStar ); };
959 '--' => { token( TK_DashDash ); };
960 '->' => { token( TK_Arrow ); };
961 '=>' => { token( TK_DoubleArrow ); };
963 ":>" => { token( TK_ColonGt ); };
964 ":>>" => { token( TK_ColonGtGt ); };
965 "<:" => { token( TK_LtColon ); };
967 # Opening of longest match.
968 "|*" => { token( TK_BarStar ); };
970 # Separater for name references.
971 "::" => { token( TK_NameSep, ts, te ); };
979 [ \t\r]+ => { updateCol(); };
981 # If we are in a single line machine then newline may end the spec.
984 if ( singleLineSpec ) {
991 if ( lastToken == KW_Export || lastToken == KW_Entry )
996 inlineBlockType = CurlyDelimited;
997 if ( hostLang->lang == HostLang::Ruby )
998 fcall inline_code_ruby;
1005 scan_error() << "unterminated ragel section" << endl;
1008 any => { token( *ts ); } ;
1011 # Outside code scanner. These tokens get passed through.
1013 ident => { pass( IMP_Word, ts, te ); };
1014 number => { pass( IMP_UInt, ts, te ); };
1015 ruby_comment => { pass(); };
1016 ( s_literal | d_literal | host_re_literal )
1017 => { pass( IMP_Literal, ts, te ); };
1021 singleLineSpec = false;
1027 singleLineSpec = true;
1031 whitespace+ => { pass(); };
1033 any => { pass( *ts, 0, 0 ); };
1036 # Outside code scanner. These tokens get passed through.
1038 'define' => { pass( IMP_Define, 0, 0 ); };
1039 ident => { pass( IMP_Word, ts, te ); };
1040 number => { pass( IMP_UInt, ts, te ); };
1041 c_cpp_comment => { pass(); };
1042 ( s_literal | d_literal ) => { pass( IMP_Literal, ts, te ); };
1046 singleLineSpec = false;
1052 singleLineSpec = true;
1056 whitespace+ => { pass(); };
1058 any => { pass( *ts, 0, 0 ); };
1064 void Scanner::do_scan()
1067 char *buf = new char[bufsize];
1068 int cs, act, have = 0;
1071 /* The stack is two deep, one level for going into ragel defs from the main
1072 * machines which process outside code, and another for going into or literals
1073 * from either a ragel spec, or a regular expression. */
1075 int curly_count = 0;
1076 bool execute = true;
1077 bool singleLineSpec = false;
1078 InlineBlockType inlineBlockType = CurlyDelimited;
1080 /* Init the section parser and the character scanner. */
1084 /* Set up the start state. FIXME: After 5.20 is released the nocs write
1085 * init option should be used, the main machine eliminated and this statement moved
1086 * above the write init. */
1087 if ( hostLang->lang == HostLang::Ruby )
1088 cs = rlscan_en_main_ruby;
1090 cs = rlscan_en_main;
1093 char *p = buf + have;
1094 int space = bufsize - have;
1097 /* We filled up the buffer trying to scan a token. Grow it. */
1098 bufsize = bufsize * 2;
1099 char *newbuf = new char[bufsize];
1101 /* Recompute p and space. */
1103 space = bufsize - have;
1105 /* Patch up pointers possibly in use. */
1107 ts = newbuf + ( ts - buf );
1108 te = newbuf + ( te - buf );
1110 /* Copy the new buffer in. */
1111 memcpy( newbuf, buf, have );
1116 input.read( p, space );
1117 int len = input.gcount();
1120 /* If we see eof then append the eof var. */
1129 /* Check if we failed. */
1130 if ( cs == rlscan_error ) {
1131 /* Machine failed before finding a token. I'm not yet sure if this
1133 scan_error() << "scanner error" << endl;
1137 /* Decide if we need to preserve anything. */
1138 char *preserve = ts;
1140 /* Now set up the prefix. */
1141 if ( preserve == 0 )
1144 /* There is data that needs to be shifted over. */
1145 have = pe - preserve;
1146 memmove( buf, preserve, have );
1147 unsigned int shiftback = preserve - buf;