Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/tools/jam/src/scan.c @ 29

Last change on this file since 29 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

File size: 8.3 KB
Line 
1/*
2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
3 *
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6
7# include "jam.h"
8# include "lists.h"
9# include "parse.h"
10# include "scan.h"
11# include "jamgram.h"
12# include "jambase.h"
13# include "newstr.h"
14# include "debug.h"
15
16/*
17 * scan.c - the jam yacc scanner
18 *
19 * 12/26/93 (seiwald) - bump buf in yylex to 10240 - yuk.
20 * 09/16/94 (seiwald) - check for overflows, unmatched {}'s, etc.
21 *                      Also handle tokens abutting EOF by remembering
22 *                      to return EOF now matter how many times yylex()
23 *                      reinvokes yyline().
24 * 02/11/95 (seiwald) - honor only punctuation keywords if SCAN_PUNCT.
25 * 07/27/95 (seiwald) - Include jamgram.h after scan.h, so that YYSTYPE is
26 *                      defined before Linux's yacc tries to redefine it.
27 */
28
29struct keyword {
30        char *word;
31        int type;
32} keywords[] = {
33# include "jamgramtab.h"
34        { 0, 0 }
35} ;
36
37struct include {
38        struct include *next;   /* next serial include file */
39        char    *string;        /* pointer into current line */
40        char    **strings;      /* for yyfparse() -- text to parse */
41        FILE    *file;          /* for yyfparse() -- file being read */
42        char    *fname;         /* for yyfparse() -- file name */
43        int     line;           /* line counter for error messages */
44        char    buf[ 512 ];     /* for yyfparse() -- line buffer */
45} ;
46
47static struct include *incp = 0; /* current file; head of chain */
48
49static int scanmode = SCAN_NORMAL;
50static int anyerrors = 0;
51static char *symdump( YYSTYPE *s );
52
53# define BIGGEST_TOKEN 10240    /* no single token can be larger */
54
55/*
56 * Set parser mode: normal, string, or keyword
57 */
58
59void
60yymode( int n )
61{
62        scanmode = n;
63}
64
65void
66yyerror( char *s )
67{
68        if( incp )
69            printf( "%s:%d: ", incp->fname, incp->line );
70
71        printf( "%s at %s\n", s, symdump( &yylval ) );
72
73        ++anyerrors;
74}
75
76int
77yyanyerrors()
78{
79        return anyerrors != 0;
80}
81
82void
83yyfparse( char *s )
84{
85        struct include *i = (struct include *)malloc( sizeof( *i ) );
86    if ( DEBUG_PROFILE )
87        profile_memory( sizeof( *i ) );
88
89        /* Push this onto the incp chain. */
90
91        i->string = "";
92        i->strings = 0;
93        i->file = 0;
94        i->fname = copystr( s );
95        i->line = 0;
96        i->next = incp;
97        incp = i;
98
99        /* If the filename is "+", it means use the internal jambase. */
100
101        if( !strcmp( s, "+" ) )
102            i->strings = jambase;
103}
104
105/*
106 * yyline() - read new line and return first character
107 *
108 * Fabricates a continuous stream of characters across include files,
109 * returning EOF at the bitter end.
110 */
111
112int
113yyline()
114{
115        struct include *i = incp;
116
117        if( !incp )
118            return EOF;
119
120        /* Once we start reading from the input stream, we reset the */
121        /* include insertion point so that the next include file becomes */
122        /* the head of the list. */
123
124        /* If there is more data in this line, return it. */
125
126        if( *i->string )
127            return *i->string++;
128
129        /* If we're reading from an internal string list, go to the */
130        /* next string. */
131
132        if( i->strings )
133        {
134            if( !*i->strings )
135                goto next;
136
137            i->line++;
138            i->string = *(i->strings++);
139            return *i->string++;
140        }
141
142        /* If necessary, open the file */
143
144        if( !i->file )
145        {
146            FILE *f = stdin;
147
148            if( strcmp( i->fname, "-" ) && !( f = fopen( i->fname, "r" ) ) )
149                perror( i->fname );
150
151            i->file = f;
152        }
153
154        /* If there's another line in this file, start it. */
155
156        if( i->file && fgets( i->buf, sizeof( i->buf ), i->file ) )
157        {
158            i->line++;
159            i->string = i->buf;
160            return *i->string++;
161        }
162
163    next:
164        /* This include is done.  */
165        /* Free it up and return EOF so yyparse() returns to parse_file(). */
166
167        incp = i->next;
168
169        /* Close file, free name */
170
171        if( i->file && i->file != stdin )
172            fclose( i->file );
173        freestr( i->fname );
174        free( (char *)i );
175
176        return EOF;
177}
178
179/*
180 * yylex() - set yylval to current token; return its type
181 *
182 * Macros to move things along:
183 *
184 *      yychar() - return and advance character; invalid after EOF
185 *      yyprev() - back up one character; invalid before yychar()
186 *
187 * yychar() returns a continuous stream of characters, until it hits
188 * the EOF of the current include file.
189 */
190
191# define yychar() ( *incp->string ? *incp->string++ : yyline() )
192# define yyprev() ( incp->string-- )
193
194int
195yylex()
196{
197        int c;
198        char buf[BIGGEST_TOKEN];
199        char *b = buf;
200
201        if( !incp )
202            goto eof;
203
204        /* Get first character (whitespace or of token) */
205
206        c = yychar();
207
208        if( scanmode == SCAN_STRING )
209        {
210            /* If scanning for a string (action's {}'s), look for the */
211            /* closing brace.  We handle matching braces, if they match! */
212
213            int nest = 1;
214
215            while( c != EOF && b < buf + sizeof( buf ) )
216            {
217                    if( c == '{' )
218                        nest++;
219
220                    if( c == '}' && !--nest )
221                        break;
222
223                    *b++ = c;
224
225                    c = yychar();
226
227                    /* turn trailing "\r\n" sequences into plain "\n"
228                     * for Cygwin
229                     */
230                    if (c == '\n' && b[-1] == '\r')
231                        --b;
232            }
233
234            /* We ate the ending brace -- regurgitate it. */
235
236            if( c != EOF )
237                yyprev();
238
239            /* Check obvious errors. */
240
241            if( b == buf + sizeof( buf ) )
242            {
243                yyerror( "action block too big" );
244                goto eof;
245            }
246
247            if( nest )
248            {
249                yyerror( "unmatched {} in action block" );
250                goto eof;
251            }
252
253            *b = 0;
254            yylval.type = STRING;
255            yylval.string = newstr( buf );
256        yylval.file = incp->fname;
257        yylval.line = incp->line;
258       
259        }
260        else
261        {
262            char *b = buf;
263            struct keyword *k;
264            int inquote = 0;
265            int notkeyword;
266               
267            /* Eat white space */
268
269            for( ;; )
270            {
271            /* Skip past white space */
272
273            while( c != EOF && isspace( c ) )
274                c = yychar();
275
276            /* Not a comment?  Swallow up comment line. */
277
278            if( c != '#' )
279                break;
280            while( ( c = yychar() ) != EOF && c != '\n' )
281                ;
282            }
283
284            /* c now points to the first character of a token. */
285
286            if( c == EOF )
287                goto eof;
288
289        yylval.file = incp->fname;
290        yylval.line = incp->line;
291       
292            /* While scanning the word, disqualify it for (expensive) */
293            /* keyword lookup when we can: $anything, "anything", \anything */
294
295            notkeyword = c == '$';
296
297            /* look for white space to delimit word */
298            /* "'s get stripped but preserve white space */
299            /* \ protects next character */
300
301            while( 
302                c != EOF &&
303                b < buf + sizeof( buf ) &&
304                ( inquote || !isspace( c ) ) )
305            {
306                if( c == '"' )
307                {
308                    /* begin or end " */
309                    inquote = !inquote;
310                    notkeyword = 1;
311                }
312                else if( c != '\\' )
313                {
314                    /* normal char */
315                    *b++ = c;
316                }
317                else if( ( c = yychar()) != EOF )
318            {
319                    /* \c */
320                    *b++ = c;
321                    notkeyword = 1;
322                }
323                else
324                {
325                    /* \EOF */
326                    break;
327                }
328
329                c = yychar();
330            }
331
332            /* Check obvious errors. */
333
334            if( b == buf + sizeof( buf ) )
335            {
336                yyerror( "string too big" );
337                goto eof;
338            }
339
340            if( inquote )
341            {
342                yyerror( "unmatched \" in string" );
343                goto eof;
344            }
345
346            /* We looked ahead a character - back up. */
347
348            if( c != EOF )
349                yyprev();
350
351            /* scan token table */
352            /* don't scan if it's obviously not a keyword or if its */
353            /* an alphabetic when were looking for punctuation */
354
355            *b = 0;
356            yylval.type = ARG;
357
358            if( !notkeyword && !( isalpha( *buf ) && scanmode == SCAN_PUNCT ) )
359            {
360                for( k = keywords; k->word; k++ )
361                    if( *buf == *k->word && !strcmp( k->word, buf ) )
362                {
363                    yylval.type = k->type;
364                    yylval.string = k->word;    /* used by symdump */
365                    break;
366                }
367            }
368
369            if( yylval.type == ARG )
370                yylval.string = newstr( buf );
371        }
372
373        if( DEBUG_SCAN )
374                printf( "scan %s\n", symdump( &yylval ) );
375
376        return yylval.type;
377
378eof:
379    yylval.file = "end-of-input"; /* just in case */
380    yylval.line = 0;
381       
382        yylval.type = EOF;
383        return yylval.type;
384}
385
386static char *
387symdump( YYSTYPE *s )
388{
389        static char buf[ BIGGEST_TOKEN + 20 ];
390
391        switch( s->type )
392        {
393        case EOF:
394                sprintf( buf, "EOF" );
395                break;
396        case 0:
397                sprintf( buf, "unknown symbol %s", s->string );
398                break;
399        case ARG:
400                sprintf( buf, "argument %s", s->string );
401                break;
402        case STRING:
403                sprintf( buf, "string \"%s\"", s->string );
404                break;
405        default:
406                sprintf( buf, "keyword %s", s->string );
407                break;
408        }
409        return buf;
410}
411
412/*  Get information about the current file and line, for those epsilon
413 *  transitions that produce a parse
414 */
415void yyinput_stream( char** name, int* line )
416{
417    if (incp)
418    {
419        *name = incp->fname;
420        *line = incp->line;
421    }
422    else
423    {
424        *name = "(builtin)";
425        *line = -1;
426    }
427}
Note: See TracBrowser for help on using the repository browser.