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
10 * 12/26/93 (seiwald) - bump buf in yylex to 10240 - yuk.
11 * 09/16/94 (seiwald) - check for overflows, unmatched {}'s, etc.
12 * Also handle tokens abutting EOF by remembering
13 * to return EOF now matter how many times yylex()
15 * 02/11/95 (seiwald) - honor only punctuation keywords if SCAN_PUNCT.
16 * 07/27/95 (seiwald) - Include jamgram.h after scan.h, so that YYSTYPE is
17 * defined before Linux's yacc tries to redefine it.
18 * 01/10/01 (seiwald) - \ can now escape any whitespace char
19 * 11/04/02 (seiwald) - const-ing for string literals
34 # include "jamgramtab.h"
39 struct include
*next
; /* next serial include file */
40 const char *string
; /* pointer into current line */
41 char **strings
; /* for yyfparse() -- text to parse */
42 FILE *file
; /* for yyfparse() -- file being read */
43 const char *fname
; /* for yyfparse() -- file name */
44 int line
; /* line counter for error messages */
45 char buf
[ 512 ]; /* for yyfparse() -- line buffer */
48 static struct include
*incp
= 0; /* current file; head of chain */
50 static int scanmode
= SCAN_NORMAL
;
51 static int anyerrors
= 0;
52 static char *symdump( YYSTYPE
*s
);
54 # define BIGGEST_TOKEN 10240 /* no single token can be larger */
57 * Set parser mode: normal, string, or keyword
67 yyerror( const char *s
)
70 printf( "%s: line %d: ", incp
->fname
, incp
->line
);
72 printf( "%s at %s\n", s
, symdump( &yylval
) );
80 return anyerrors
!= 0;
84 yyfparse( const char *s
)
86 struct include
*i
= (struct include
*)malloc( sizeof( *i
) );
88 /* Push this onto the incp chain. */
93 i
->fname
= copystr( s
);
98 /* If the filename is "+", it means use the internal jambase. */
100 if( !strcmp( s
, "+" ) )
101 i
->strings
= jambase
;
105 * yyline() - read new line and return first character
107 * Fabricates a continuous stream of characters across include files,
108 * returning EOF at the bitter end.
114 struct include
*i
= incp
;
119 /* Once we start reading from the input stream, we reset the */
120 /* include insertion point so that the next include file becomes */
121 /* the head of the list. */
123 /* If there is more data in this line, return it. */
128 /* If we're reading from an internal string list, go to the */
137 i
->string
= *(i
->strings
++);
141 /* If necessary, open the file */
147 if( strcmp( i
->fname
, "-" ) && !( f
= fopen( i
->fname
, "r" ) ) )
153 /* If there's another line in this file, start it. */
155 if( i
->file
&& fgets( i
->buf
, sizeof( i
->buf
), i
->file
) )
163 /* This include is done. */
164 /* Free it up and return EOF so yyparse() returns to parse_file(). */
168 /* Close file, free name */
170 if( i
->file
&& i
->file
!= stdin
)
179 * yylex() - set yylval to current token; return its type
181 * Macros to move things along:
183 * yychar() - return and advance character; invalid after EOF
184 * yyprev() - back up one character; invalid before yychar()
186 * yychar() returns a continuous stream of characters, until it hits
187 * the EOF of the current include file.
190 # define yychar() ( *incp->string ? *incp->string++ : yyline() )
191 # define yyprev() ( incp->string-- )
197 char buf
[BIGGEST_TOKEN
];
203 /* Get first character (whitespace or of token) */
207 if( scanmode
== SCAN_STRING
)
209 /* If scanning for a string (action's {}'s), look for the */
210 /* closing brace. We handle matching braces, if they match! */
214 while( c
!= EOF
&& b
< buf
+ sizeof( buf
) )
219 if( c
== '}' && !--nest
)
227 /* We ate the ending brace -- regurgitate it. */
232 /* Check obvious errors. */
234 if( b
== buf
+ sizeof( buf
) )
236 yyerror( "action block too big" );
242 yyerror( "unmatched {} in action block" );
247 yylval
.type
= STRING
;
248 yylval
.string
= newstr( buf
);
258 /* Eat white space */
262 /* Skip past white space */
264 while( c
!= EOF
&& isspace( c
) )
267 /* Not a comment? Swallow up comment line. */
271 while( ( c
= yychar() ) != EOF
&& c
!= '\n' )
275 /* c now points to the first character of a token. */
280 /* While scanning the word, disqualify it for (expensive) */
281 /* keyword lookup when we can: $anything, "anything", \anything */
283 notkeyword
= c
== '$';
285 /* look for white space to delimit word */
286 /* "'s get stripped but preserve white space */
287 /* \ protects next character */
291 b
< buf
+ sizeof( buf
) &&
292 ( inquote
|| !isspace( c
) ) )
305 else if( ( c
= yychar()) != EOF
)
320 /* Check obvious errors. */
322 if( b
== buf
+ sizeof( buf
) )
324 yyerror( "string too big" );
330 yyerror( "unmatched \" in string" );
334 /* We looked ahead a character - back up. */
339 /* scan token table */
340 /* don't scan if it's obviously not a keyword or if its */
341 /* an alphabetic when were looking for punctuation */
346 if( !notkeyword
&& !( isalpha( *buf
) && scanmode
== SCAN_PUNCT
) )
348 for( k
= keywords
; k
->word
; k
++ )
349 if( *buf
== *k
->word
&& !strcmp( k
->word
, buf
) )
351 yylval
.type
= k
->type
;
352 yylval
.string
= k
->word
; /* used by symdump */
357 if( yylval
.type
== ARG
)
358 yylval
.string
= newstr( buf
);
362 printf( "scan %s\n", symdump( &yylval
) );
372 symdump( YYSTYPE
*s
)
374 static char buf
[ BIGGEST_TOKEN
+ 20 ];
379 sprintf( buf
, "EOF" );
382 sprintf( buf
, "unknown symbol %s", s
->string
);
385 sprintf( buf
, "argument %s", s
->string
);
388 sprintf( buf
, "string \"%s\"", s
->string
);
391 sprintf( buf
, "keyword %s", s
->string
);