]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/engine/scan.c
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"
27 #include "jamgramtab.h"
31 typedef struct include include
;
34 include
* next
; /* next serial include file */
35 char * string
; /* pointer into current line */
36 char * * strings
; /* for yyfparse() -- text to parse */
37 LISTITER pos
; /* for yysparse() -- text to parse */
38 LIST
* list
; /* for yysparse() -- text to parse */
39 FILE * file
; /* for yyfparse() -- file being read */
40 OBJECT
* fname
; /* for yyfparse() -- file name */
41 int line
; /* line counter for error messages */
42 char buf
[ 512 ]; /* for yyfparse() -- line buffer */
45 static include
* incp
= 0; /* current file; head of chain */
47 static int scanmode
= SCAN_NORMAL
;
48 static int anyerrors
= 0;
51 static char * symdump( YYSTYPE
* );
53 #define BIGGEST_TOKEN 10240 /* no single token can be larger */
57 * Set parser mode: normal, string, or keyword.
62 int result
= scanmode
;
68 void yyerror( char const * s
)
70 /* We use yylval instead of incp to access the error location information as
71 * the incp pointer will already be reset to 0 in case the error occurred at
74 * The two may differ only if ran into an unexpected EOF or we get an error
75 * while reading a lexical token spanning multiple lines, e.g. a multi-line
76 * string literal or action body, in which case yylval location information
77 * will hold the information about where the token started while incp will
78 * hold the information about where reading it broke.
80 out_printf( "%s:%d: %s at %s\n", object_str( yylval
.file
), yylval
.line
, s
,
88 return anyerrors
!= 0;
92 void yyfparse( OBJECT
* s
)
94 include
* i
= (include
*)BJAM_MALLOC( sizeof( *i
) );
96 /* Push this onto the incp chain. */
100 i
->fname
= object_copy( s
);
105 /* If the filename is "+", it means use the internal jambase. */
106 if ( !strcmp( object_str( s
), "+" ) )
107 i
->strings
= jambase
;
111 void yysparse( OBJECT
* name
, const char * * lines
)
114 incp
->strings
= (char * *)lines
;
119 * yyfdone() - cleanup after we're done parsing a file.
123 include
* const i
= incp
;
126 /* Close file, free name. */
127 if(i
->file
&& (i
->file
!= stdin
))
129 object_free(i
->fname
);
130 BJAM_FREE((char *)i
);
135 * yyline() - read new line and return first character.
137 * Fabricates a continuous stream of characters across include files, returning
138 * EOF at the bitter end.
143 include
* const i
= incp
;
148 /* Once we start reading from the input stream, we reset the include
149 * insertion point so that the next include file becomes the head of the
153 /* If there is more data in this line, return it. */
157 /* If we are reading from an internal string list, go to the next string. */
163 i
->string
= *(i
->strings
++);
169 /* If necessary, open the file. */
173 if ( strcmp( object_str( i
->fname
), "-" ) && !( f
= fopen( object_str( i
->fname
), "r" ) ) )
174 perror( object_str( i
->fname
) );
178 /* If there is another line in this file, start it. */
179 if ( i
->file
&& fgets( i
->buf
, sizeof( i
->buf
), i
->file
) )
187 /* This include is done. Return EOF so yyparse() returns to
194 /* This allows us to get an extra character of lookahead.
195 * There are a few places where we need to look ahead two
196 * characters and yyprev only guarantees a single character
203 return *incp
->string
;
205 else if ( incp
->strings
)
207 if ( *incp
->strings
)
208 return **incp
->strings
;
210 else if ( incp
->file
)
212 /* Don't bother opening the file. yypeek is
213 * only used in special cases and never at the
214 * beginning of a file.
216 int ch
= fgetc( incp
->file
);
218 ungetc( ch
, incp
->file
);
225 * yylex() - set yylval to current token; return its type.
227 * Macros to move things along:
229 * yychar() - return and advance character; invalid after EOF.
230 * yyprev() - back up one character; invalid before yychar().
232 * yychar() returns a continuous stream of characters, until it hits the EOF of
233 * the current include file.
236 #define yychar() ( *incp->string ? *incp->string++ : yyline() )
237 #define yyprev() ( incp->string-- )
239 static int use_new_scanner
= 0;
240 static int expect_whitespace
;
242 #define yystartkeyword() if(use_new_scanner) break; else token_warning()
243 #define yyendkeyword() if(use_new_scanner) break; else if ( 1 ) { expect_whitespace = 1; continue; } else (void)0
245 void do_token_warning()
247 out_printf( "%s:%d: %s %s\n", object_str( yylval
.file
), yylval
.line
, "Unescaped special character in",
248 symdump( &yylval
) );
251 #define token_warning() has_token_warning = 1
256 char buf
[ BIGGEST_TOKEN
];
262 /* Get first character (whitespace or of token). */
265 if ( scanmode
== SCAN_STRING
)
267 /* If scanning for a string (action's {}'s), look for the closing brace.
268 * We handle matching braces, if they match.
273 while ( ( c
!= EOF
) && ( b
< buf
+ sizeof( buf
) ) )
278 if ( ( c
== '}' ) && !--nest
)
285 /* Turn trailing "\r\n" sequences into plain "\n" for Cygwin. */
286 if ( ( c
== '\n' ) && ( b
[ -1 ] == '\r' ) )
290 /* We ate the ending brace -- regurgitate it. */
294 /* Check for obvious errors. */
295 if ( b
== buf
+ sizeof( buf
) )
297 yyerror( "action block too big" );
303 yyerror( "unmatched {} in action block" );
308 yylval
.type
= STRING
;
309 yylval
.string
= object_new( buf
);
310 yylval
.file
= incp
->fname
;
311 yylval
.line
= incp
->line
;
323 int expect_whitespace
= 0;
324 int has_token_warning
= 0;
326 /* Eat white space. */
329 /* Skip past white space. */
330 while ( ( c
!= EOF
) && isspace( c
) )
338 if ( ( c
!= EOF
) && c
== '|' )
340 /* Swallow up block comment. */
343 while ( ! ( c0
== '|' && c1
== '#' ) && ( c0
!= EOF
&& c1
!= EOF
) )
352 /* Swallow up comment line. */
353 while ( ( c
!= EOF
) && ( c
!= '\n' ) ) c
= yychar();
357 /* c now points to the first character of a token. */
361 yylval
.file
= incp
->fname
;
362 yylval
.line
= incp
->line
;
364 /* While scanning the word, disqualify it for (expensive) keyword lookup
365 * when we can: $anything, "anything", \anything
367 notkeyword
= c
== '$';
369 /* Look for white space to delimit word. "'s get stripped but preserve
370 * white space. \ protects next character.
375 ( b
< buf
+ sizeof( buf
) ) &&
376 ( inquote
|| invarexpand
|| !isspace( c
) )
379 if ( expect_whitespace
|| ( isspace( c
) && ! inquote
) )
382 expect_whitespace
= 0;
384 if ( !inquote
&& !invarexpand
)
386 if ( scanmode
== SCAN_COND
|| scanmode
== SCAN_CONDB
)
388 if ( hastoken
&& ( c
== '=' || c
== '<' || c
== '>' || c
== '!' || c
== '(' || c
== ')' || c
== '&' || c
== '|' ) )
390 /* Don't treat > as special if we started with a grist. */
391 if ( ! ( scanmode
== SCAN_CONDB
&& ingrist
== 1 && c
== '>' ) )
396 else if ( c
== '=' || c
== '(' || c
== ')' )
402 else if ( c
== '!' || ( scanmode
== SCAN_COND
&& ( c
== '<' || c
== '>' ) ) )
405 if ( ( c
= yychar() ) == '=' )
412 else if ( c
== '&' || c
== '|' )
423 else if ( scanmode
== SCAN_PARAMS
)
425 if ( c
== '*' || c
== '+' || c
== '?' || c
== '(' || c
== ')' )
439 else if ( scanmode
== SCAN_XASSIGN
&& ! hastoken
)
447 else if ( c
== '+' || c
== '?' )
449 if ( yypeek() == '=' )
458 else if ( scanmode
== SCAN_NORMAL
|| scanmode
== SCAN_ASSIGN
)
473 else if ( c
== '+' || c
== '?' )
475 if ( yypeek() == '=' )
491 if ( scanmode
!= SCAN_CASE
&& ( c
== ';' || c
== '{' || c
== '}' ||
492 ( scanmode
!= SCAN_PARAMS
&& ( c
== '[' || c
== ']' ) ) ) )
516 /* Special rules for ':' do not apply after we quote anything. */
519 else if ( ingrist
== 0 )
523 int is_conditional
= 0;
526 if( yypeek() == '\\' )
531 else if ( next
== '/' )
538 /* Accept windows paths iff they are at the start or immediately follow a grist. */
539 if ( b
> buf
&& isalpha( b
[ -1 ] ) && ( b
== buf
+ 1 || b
[ -2 ] == '>' ) )
550 /* Accept conditionals only for tokens that start with "<" or "!<" */
551 if ( b
> buf
&& buf
[ 0 ] == '<' ||
552 ( b
> buf
+ 1 && buf
[ 0 ] == '!' && buf
[ 1 ] == '<' ))
557 if ( !is_conditional
&& !is_win_path
)
572 else if ( c
!= '\\' )
574 if ( !invarexpand
&& c
== '<' )
576 if ( ingrist
== 0 ) ingrist
= 1;
579 else if ( !invarexpand
&& c
== '>' )
581 if ( ingrist
== 1 ) ingrist
= 0;
586 if ( ( c
= yychar() ) == EOF
)
593 /* inside $(), we only care about quotes */
606 if ( ( c
= yychar() ) == EOF
)
613 /* inside @(), we only care about quotes */
624 else if ( invarexpand
&& c
== '(' )
628 else if ( invarexpand
&& c
== ')' )
635 else if ( ( c
= yychar() ) != EOF
)
656 /* Automatically switch modes after reading the token. */
657 if ( scanmode
== SCAN_CONDB
)
658 scanmode
= SCAN_COND
;
660 /* Check obvious errors. */
661 if ( b
== buf
+ sizeof( buf
) )
663 yyerror( "string too big" );
669 yyerror( "unmatched \" in string" );
673 /* We looked ahead a character - back up. */
677 /* Scan token table. Do not scan if it is obviously not a keyword or if
678 * it is an alphabetic when were looking for punctuation.
684 if ( !notkeyword
&& !( isalpha( *buf
) && ( scanmode
== SCAN_PUNCT
|| scanmode
== SCAN_PARAMS
|| scanmode
== SCAN_ASSIGN
) ) )
685 for ( k
= keywords
; k
->word
; ++k
)
686 if ( ( *buf
== *k
->word
) && !strcmp( k
->word
, buf
) )
688 yylval
.type
= k
->type
;
689 yylval
.keyword
= k
->word
; /* used by symdump */
693 if ( yylval
.type
== ARG
)
694 yylval
.string
= object_new( buf
);
696 if ( scanmode
== SCAN_NORMAL
&& yylval
.type
== ARG
)
697 scanmode
= SCAN_XASSIGN
;
699 if ( has_token_warning
)
704 out_printf( "scan %s\n", symdump( &yylval
) );
709 /* We do not reset yylval.file & yylval.line here so unexpected EOF error
710 * messages would include correct error location information.
717 static char * symdump( YYSTYPE
* s
)
719 static char buf
[ BIGGEST_TOKEN
+ 20 ];
722 case EOF
: sprintf( buf
, "EOF" ); break;
723 case 0 : sprintf( buf
, "unknown symbol %s", object_str( s
->string
) ); break;
724 case ARG
: sprintf( buf
, "argument %s" , object_str( s
->string
) ); break;
725 case STRING
: sprintf( buf
, "string \"%s\"" , object_str( s
->string
) ); break;
726 default : sprintf( buf
, "keyword %s" , s
->keyword
); break;
733 * Get information about the current file and line, for those epsilon
734 * transitions that produce a parse.
737 void yyinput_last_read_token( OBJECT
* * name
, int * line
)
739 /* TODO: Consider whether and when we might want to report where the last
740 * read token ended, e.g. EOF errors inside string literals.