]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/engine/scan.cpp
2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
4 * This file is part of Jam - see jam.c for Copyright information.
8 * scan.c - the jam yacc scanner
16 #include "constants.h"
17 #include "jamgram.hpp"
26 #include "jamgramtab.h"
30 typedef struct include include
;
33 include
* next
; /* next serial include file */
34 char * string
; /* pointer into current line */
35 char * * strings
; /* for yyfparse() -- text to parse */
36 LISTITER pos
; /* for yysparse() -- text to parse */
37 LIST
* list
; /* for yysparse() -- text to parse */
38 FILE * file
; /* for yyfparse() -- file being read */
39 OBJECT
* fname
; /* for yyfparse() -- file name */
40 int line
; /* line counter for error messages */
41 char buf
[ 512 ]; /* for yyfparse() -- line buffer */
44 static include
* incp
= 0; /* current file; head of chain */
46 static int scanmode
= SCAN_NORMAL
;
47 static int anyerrors
= 0;
50 static char * symdump( YYSTYPE
* );
52 #define BIGGEST_TOKEN 10240 /* no single token can be larger */
56 * Set parser mode: normal, string, or keyword.
61 int result
= scanmode
;
67 void yyerror( char const * s
)
69 /* We use yylval instead of incp to access the error location information as
70 * the incp pointer will already be reset to 0 in case the error occurred at
73 * The two may differ only if ran into an unexpected EOF or we get an error
74 * while reading a lexical token spanning multiple lines, e.g. a multi-line
75 * string literal or action body, in which case yylval location information
76 * will hold the information about where the token started while incp will
77 * hold the information about where reading it broke.
79 out_printf( "%s:%d: %s at %s\n", object_str( yylval
.file
), yylval
.line
, s
,
87 return anyerrors
!= 0;
91 void yyfparse( OBJECT
* s
)
93 include
* i
= (include
*)BJAM_MALLOC( sizeof( *i
) );
95 /* Push this onto the incp chain. */
96 i
->string
= (char*)"";
99 i
->fname
= object_copy( s
);
106 void yysparse( OBJECT
* name
, const char * * lines
)
109 incp
->strings
= (char * *)lines
;
114 * yyfdone() - cleanup after we're done parsing a file.
118 include
* const i
= incp
;
121 /* Close file, free name. */
122 if(i
->file
&& (i
->file
!= stdin
))
124 object_free(i
->fname
);
125 BJAM_FREE((char *)i
);
130 * yyline() - read new line and return first character.
132 * Fabricates a continuous stream of characters across include files, returning
133 * EOF at the bitter end.
138 include
* const i
= incp
;
143 /* Once we start reading from the input stream, we reset the include
144 * insertion point so that the next include file becomes the head of the
148 /* If there is more data in this line, return it. */
152 /* If we are reading from an internal string list, go to the next string. */
158 i
->string
= *(i
->strings
++);
164 /* If necessary, open the file. */
168 if ( strcmp( object_str( i
->fname
), "-" ) && !( f
= fopen( object_str( i
->fname
), "r" ) ) )
169 perror( object_str( i
->fname
) );
173 /* If there is another line in this file, start it. */
174 if ( i
->file
&& fgets( i
->buf
, sizeof( i
->buf
), i
->file
) )
182 /* This include is done. Return EOF so yyparse() returns to
189 /* This allows us to get an extra character of lookahead.
190 * There are a few places where we need to look ahead two
191 * characters and yyprev only guarantees a single character
198 return *incp
->string
;
200 else if ( incp
->strings
)
202 if ( *incp
->strings
)
203 return **incp
->strings
;
205 else if ( incp
->file
)
207 /* Don't bother opening the file. yypeek is
208 * only used in special cases and never at the
209 * beginning of a file.
211 int ch
= fgetc( incp
->file
);
213 ungetc( ch
, incp
->file
);
220 * yylex() - set yylval to current token; return its type.
222 * Macros to move things along:
224 * yychar() - return and advance character; invalid after EOF.
225 * yyprev() - back up one character; invalid before yychar().
227 * yychar() returns a continuous stream of characters, until it hits the EOF of
228 * the current include file.
231 #define yychar() ( *incp->string ? *incp->string++ : yyline() )
232 #define yyprev() ( incp->string-- )
234 static int use_new_scanner
= 0;
236 #define yystartkeyword() if(use_new_scanner) break; else token_warning()
237 #define yyendkeyword() if(use_new_scanner) break; else if ( 1 ) { expect_whitespace = 1; continue; } else (void)0
239 void do_token_warning()
241 out_printf( "%s:%d: %s %s\n", object_str( yylval
.file
), yylval
.line
, "Unescaped special character in",
242 symdump( &yylval
) );
245 #define token_warning() has_token_warning = 1
250 char buf
[ BIGGEST_TOKEN
];
256 /* Get first character (whitespace or of token). */
259 if ( scanmode
== SCAN_STRING
)
261 /* If scanning for a string (action's {}'s), look for the closing brace.
262 * We handle matching braces, if they match.
267 while ( ( c
!= EOF
) && ( b
< buf
+ sizeof( buf
) ) )
272 if ( ( c
== '}' ) && !--nest
)
279 /* Turn trailing "\r\n" sequences into plain "\n" for Cygwin. */
280 if ( ( c
== '\n' ) && ( b
[ -1 ] == '\r' ) )
284 /* We ate the ending brace -- regurgitate it. */
288 /* Check for obvious errors. */
289 if ( b
== buf
+ sizeof( buf
) )
291 yyerror( "action block too big" );
297 yyerror( "unmatched {} in action block" );
302 yylval
.type
= STRING
;
303 yylval
.string
= object_new( buf
);
304 yylval
.file
= incp
->fname
;
305 yylval
.line
= incp
->line
;
317 int expect_whitespace
= 0;
318 int has_token_warning
= 0;
320 /* Eat white space. */
323 /* Skip past white space. */
324 while ( ( c
!= EOF
) && isspace( c
) )
332 if ( ( c
!= EOF
) && c
== '|' )
334 /* Swallow up block comment. */
337 while ( ! ( c0
== '|' && c1
== '#' ) && ( c0
!= EOF
&& c1
!= EOF
) )
346 /* Swallow up comment line. */
347 while ( ( c
!= EOF
) && ( c
!= '\n' ) ) c
= yychar();
351 /* c now points to the first character of a token. */
355 yylval
.file
= incp
->fname
;
356 yylval
.line
= incp
->line
;
358 /* While scanning the word, disqualify it for (expensive) keyword lookup
359 * when we can: $anything, "anything", \anything
361 notkeyword
= c
== '$';
363 /* Look for white space to delimit word. "'s get stripped but preserve
364 * white space. \ protects next character.
369 ( b
< buf
+ sizeof( buf
) ) &&
370 ( inquote
|| invarexpand
|| !isspace( c
) )
373 if ( expect_whitespace
|| ( isspace( c
) && ! inquote
) )
376 expect_whitespace
= 0;
378 if ( !inquote
&& !invarexpand
)
380 if ( scanmode
== SCAN_COND
|| scanmode
== SCAN_CONDB
)
382 if ( hastoken
&& ( c
== '=' || c
== '<' || c
== '>' || c
== '!' || c
== '(' || c
== ')' || c
== '&' || c
== '|' ) )
384 /* Don't treat > as special if we started with a grist. */
385 if ( ! ( scanmode
== SCAN_CONDB
&& ingrist
== 1 && c
== '>' ) )
390 else if ( c
== '=' || c
== '(' || c
== ')' )
396 else if ( c
== '!' || ( scanmode
== SCAN_COND
&& ( c
== '<' || c
== '>' ) ) )
399 if ( ( c
= yychar() ) == '=' )
406 else if ( c
== '&' || c
== '|' )
417 else if ( scanmode
== SCAN_PARAMS
)
419 if ( c
== '*' || c
== '+' || c
== '?' || c
== '(' || c
== ')' )
433 else if ( scanmode
== SCAN_XASSIGN
&& ! hastoken
)
441 else if ( c
== '+' || c
== '?' )
443 if ( yypeek() == '=' )
452 else if ( scanmode
== SCAN_NORMAL
|| scanmode
== SCAN_ASSIGN
)
467 else if ( c
== '+' || c
== '?' )
469 if ( yypeek() == '=' )
485 if ( scanmode
!= SCAN_CASE
&& ( c
== ';' || c
== '{' || c
== '}' ||
486 ( scanmode
!= SCAN_PARAMS
&& ( c
== '[' || c
== ']' ) ) ) )
510 /* Special rules for ':' do not apply after we quote anything. */
513 else if ( ingrist
== 0 )
517 int is_conditional
= 0;
520 if( yypeek() == '\\' )
525 else if ( next
== '/' )
532 /* Accept windows paths iff they are at the start or immediately follow a grist. */
533 if ( b
> buf
&& isalpha( b
[ -1 ] ) && ( b
== buf
+ 1 || b
[ -2 ] == '>' ) )
544 /* Accept conditionals only for tokens that start with "<" or "!<" */
545 if ( ( (b
> buf
) && (buf
[ 0 ] == '<') ) ||
546 ( (b
> (buf
+ 1)) && (buf
[ 0 ] == '!') && (buf
[ 1 ] == '<') ))
551 if ( !is_conditional
&& !is_win_path
)
566 else if ( c
!= '\\' )
568 if ( !invarexpand
&& c
== '<' )
570 if ( ingrist
== 0 ) ingrist
= 1;
573 else if ( !invarexpand
&& c
== '>' )
575 if ( ingrist
== 1 ) ingrist
= 0;
580 if ( ( c
= yychar() ) == EOF
)
587 /* inside $(), we only care about quotes */
600 if ( ( c
= yychar() ) == EOF
)
607 /* inside @(), we only care about quotes */
618 else if ( invarexpand
&& c
== '(' )
622 else if ( invarexpand
&& c
== ')' )
629 else if ( ( c
= yychar() ) != EOF
)
650 /* Automatically switch modes after reading the token. */
651 if ( scanmode
== SCAN_CONDB
)
652 scanmode
= SCAN_COND
;
654 /* Check obvious errors. */
655 if ( b
== buf
+ sizeof( buf
) )
657 yyerror( "string too big" );
663 yyerror( "unmatched \" in string" );
667 /* We looked ahead a character - back up. */
671 /* Scan token table. Do not scan if it is obviously not a keyword or if
672 * it is an alphabetic when were looking for punctuation.
678 if ( !notkeyword
&& !( isalpha( *buf
) && ( scanmode
== SCAN_PUNCT
|| scanmode
== SCAN_PARAMS
|| scanmode
== SCAN_ASSIGN
) ) )
679 for ( k
= keywords
; k
->word
; ++k
)
680 if ( ( *buf
== *k
->word
) && !strcmp( k
->word
, buf
) )
682 yylval
.type
= k
->type
;
683 yylval
.keyword
= k
->word
; /* used by symdump */
687 if ( yylval
.type
== ARG
)
688 yylval
.string
= object_new( buf
);
690 if ( scanmode
== SCAN_NORMAL
&& yylval
.type
== ARG
)
691 scanmode
= SCAN_XASSIGN
;
693 if ( has_token_warning
)
698 out_printf( "scan %s\n", symdump( &yylval
) );
703 /* We do not reset yylval.file & yylval.line here so unexpected EOF error
704 * messages would include correct error location information.
711 static char * symdump( YYSTYPE
* s
)
713 static char buf
[ BIGGEST_TOKEN
+ 20 ];
716 case EOF
: sprintf( buf
, "EOF" ); break;
717 case 0 : sprintf( buf
, "unknown symbol %s", object_str( s
->string
) ); break;
718 case ARG
: sprintf( buf
, "argument %s" , object_str( s
->string
) ); break;
719 case STRING
: sprintf( buf
, "string \"%s\"" , object_str( s
->string
) ); break;
720 default : sprintf( buf
, "keyword %s" , s
->keyword
); break;
727 * Get information about the current file and line, for those epsilon
728 * transitions that produce a parse.
731 void yyinput_last_read_token( OBJECT
* * name
, int * line
)
733 /* TODO: Consider whether and when we might want to report where the last
734 * read token ended, e.g. EOF errors inside string literals.