fix bug in astnode_clone() that caused crash when expanding a macro containing forwar...
[xorcyst.git] / scanner.l
blobad3b8dba5805d248f4dd941bdf0b200377c4e72c
1 %{
2 /*
3  * $Id: scanner.l,v 1.15 2007/11/11 22:35:46 khansen Exp $
4  * $Log: scanner.l,v $
5  * Revision 1.15  2007/11/11 22:35:46  khansen
6  * compile on mac
7  *
8  * Revision 1.14  2007/08/19 11:19:47  khansen
9  * --case-insensitive option
10  *
11  * Revision 1.13  2007/08/12 18:58:49  khansen
12  * ability to generate pure 6502 binary
13  *
14  * Revision 1.12  2007/08/11 01:25:39  khansen
15  * includepaths support (-I option)
16  *
17  * Revision 1.11  2007/08/10 20:21:36  khansen
18  * *** empty log message ***
19  *
20  * Revision 1.10  2007/07/22 13:34:16  khansen
21  * convert tabs to whitespaces
22  *
23  * Revision 1.9  2005/01/09 11:20:31  kenth
24  * xorcyst 1.4.5
25  * BLT, BGE
26  *
27  * Revision 1.8  2004/12/19 19:59:08  kenth
28  * xorcyst 1.4.0
29  *
30  * Revision 1.7  2004/12/16 13:22:08  kenth
31  * added DEFINE parsing
32  *
33  * Revision 1.6  2004/12/14 01:50:33  kenth
34  * xorcyst 1.3.0
35  *
36  * Revision 1.5  2004/12/11 02:12:32  kenth
37  * xorcyst 1.2.0
38  *
39  * Revision 1.4  2004/12/10 22:43:53  kenth
40  * removed FILE_PATH recognition: ".db <a, >b" is erronously parsed otherwise
41  *
42  * Revision 1.3  2004/12/09 11:15:28  kenth
43  * bugfix: close file handle
44  * added: "WARNING", "ERROR" recognition
45  *
46  * Revision 1.2  2004/12/06 05:06:29  kenth
47  * xorcyst 1.1.0
48  *
49  * Revision 1.1  2004/06/30 07:56:59  kenth
50  * Initial revision
51  *
52  */
53 int yyparswap;
54 int yyignorecase;
55 void yyerror(const char *);   /* See below */
56 char *strip_label();    /* See below */
57 const char *maybe_ignorecase(char *);
58 #include "loc.h"
59 #include "astnode.h"
60 #include "parser.h"
61 #include "xasm.h"
62 #include <string.h>
63 #include <ctype.h>
64 #include <assert.h>
65 /* Each time we match a string, move the end cursor to its end. */
66 #define YY_USER_ACTION  yylloc.last_column += yyleng;
68 whitespace      [ \t]+
69 comment         ";"[^\n]*
70 string_literal      \"[^\n"]*\"
71 binary_literal      [0-1]+
72 octal_literal       0[0-7]*
73 decimal_literal     [1-9][0-9]*
74 hex_literal     [0-9A-F]+
75 hex_literal2        [0-9][0-9A-F]*
76 hex_literal3        0[A-F][0-9A-F]*
77 identifier      [A-Z_][A-Z0-9_]{0,254}
78 local_id        [0-9A-Z_]{1,255}
79 pragma_prefix       "."?
80 label_prefix        ^[ \t]*
83 /* At each yylex invocation, mark the current position as the
84     start of the next token.  */
85 LOCATION_STEP (yylloc);
87 {whitespace}        { LOCATION_STEP (yylloc); }
88 {comment}       { LOCATION_STEP (yylloc); }
89 "%"{binary_literal} { yylval.integer = strtol(&yytext[1], NULL, 2); return(INTEGER_LITERAL); }
90 {binary_literal}"B" { yylval.integer = strtol(yytext, NULL, 2); return(INTEGER_LITERAL); }
91 {octal_literal}     { yylval.integer = strtol(yytext, NULL, 8); return(INTEGER_LITERAL); }
92 {decimal_literal}   { yylval.integer = strtol(yytext, NULL, 10); return(INTEGER_LITERAL); }
93 "0X"{hex_literal}   { yylval.integer = strtol(&yytext[2], NULL, 16); return(INTEGER_LITERAL); }
94 "$"{hex_literal}    { yylval.integer = strtol(&yytext[1], NULL, 16); return(INTEGER_LITERAL); }
95 {hex_literal3}"H"   { yylval.integer = strtol(yytext, NULL, 16); return(INTEGER_LITERAL); }
96 {hex_literal2}"H"   { yylval.integer = strtol(yytext, NULL, 16); return(INTEGER_LITERAL); }
97 "'"."'"         { yylval.integer = yytext[1]; return(INTEGER_LITERAL); }
98 "ADC"           { yylval.mnemonic = ADC_MNEMONIC; return(MNEMONIC); }
99 "AND"           { yylval.mnemonic = AND_MNEMONIC; return(MNEMONIC); }
100 "ASL"           { yylval.mnemonic = ASL_MNEMONIC; return(MNEMONIC); }
101 "BCC"           { yylval.mnemonic = BCC_MNEMONIC; return(MNEMONIC); }
102 "BCS"           { yylval.mnemonic = BCS_MNEMONIC; return(MNEMONIC); }
103 "BLT"           { yylval.mnemonic = BCC_MNEMONIC; return(MNEMONIC); }
104 "BGE"           { yylval.mnemonic = BCS_MNEMONIC; return(MNEMONIC); }
105 "BEQ"           { yylval.mnemonic = BEQ_MNEMONIC; return(MNEMONIC); }
106 "BIT"           { yylval.mnemonic = BIT_MNEMONIC; return(MNEMONIC); }
107 "BMI"           { yylval.mnemonic = BMI_MNEMONIC; return(MNEMONIC); }
108 "BNE"           { yylval.mnemonic = BNE_MNEMONIC; return(MNEMONIC); }
109 "BPL"           { yylval.mnemonic = BPL_MNEMONIC; return(MNEMONIC); }
110 "BRK"           { yylval.mnemonic = BRK_MNEMONIC; return(MNEMONIC); }
111 "BVC"           { yylval.mnemonic = BVC_MNEMONIC; return(MNEMONIC); }
112 "BVS"           { yylval.mnemonic = BVS_MNEMONIC; return(MNEMONIC); }
113 "CLC"           { yylval.mnemonic = CLC_MNEMONIC; return(MNEMONIC); }
114 "CLD"           { yylval.mnemonic = CLD_MNEMONIC; return(MNEMONIC); }
115 "CLI"           { yylval.mnemonic = CLI_MNEMONIC; return(MNEMONIC); }
116 "CLV"           { yylval.mnemonic = CLV_MNEMONIC; return(MNEMONIC); }
117 "CMP"           { yylval.mnemonic = CMP_MNEMONIC; return(MNEMONIC); }
118 "CPX"           { yylval.mnemonic = CPX_MNEMONIC; return(MNEMONIC); }
119 "CPY"           { yylval.mnemonic = CPY_MNEMONIC; return(MNEMONIC); }
120 "DEC"           { yylval.mnemonic = DEC_MNEMONIC; return(MNEMONIC); }
121 "DEX"           { yylval.mnemonic = DEX_MNEMONIC; return(MNEMONIC); }
122 "DEY"           { yylval.mnemonic = DEY_MNEMONIC; return(MNEMONIC); }
123 "EOR"           { yylval.mnemonic = EOR_MNEMONIC; return(MNEMONIC); }
124 "INC"           { yylval.mnemonic = INC_MNEMONIC; return(MNEMONIC); }
125 "INX"           { yylval.mnemonic = INX_MNEMONIC; return(MNEMONIC); }
126 "INY"           { yylval.mnemonic = INY_MNEMONIC; return(MNEMONIC); }
127 "JMP"           { yylval.mnemonic = JMP_MNEMONIC; return(MNEMONIC); }
128 "JSR"           { yylval.mnemonic = JSR_MNEMONIC; return(MNEMONIC); }
129 "LDA"           { yylval.mnemonic = LDA_MNEMONIC; return(MNEMONIC); }
130 "LDX"           { yylval.mnemonic = LDX_MNEMONIC; return(MNEMONIC); }
131 "LDY"           { yylval.mnemonic = LDY_MNEMONIC; return(MNEMONIC); }
132 "LSR"           { yylval.mnemonic = LSR_MNEMONIC; return(MNEMONIC); }
133 "NOP"           { yylval.mnemonic = NOP_MNEMONIC; return(MNEMONIC); }
134 "ORA"           { yylval.mnemonic = ORA_MNEMONIC; return(MNEMONIC); }
135 "PHA"           { yylval.mnemonic = PHA_MNEMONIC; return(MNEMONIC); }
136 "PHP"           { yylval.mnemonic = PHP_MNEMONIC; return(MNEMONIC); }
137 "PLA"           { yylval.mnemonic = PLA_MNEMONIC; return(MNEMONIC); }
138 "PLP"           { yylval.mnemonic = PLP_MNEMONIC; return(MNEMONIC); }
139 "ROL"           { yylval.mnemonic = ROL_MNEMONIC; return(MNEMONIC); }
140 "ROR"           { yylval.mnemonic = ROR_MNEMONIC; return(MNEMONIC); }
141 "RTI"           { yylval.mnemonic = RTI_MNEMONIC; return(MNEMONIC); }
142 "RTS"           { yylval.mnemonic = RTS_MNEMONIC; return(MNEMONIC); }
143 "SBC"           { yylval.mnemonic = SBC_MNEMONIC; return(MNEMONIC); }
144 "SEC"           { yylval.mnemonic = SEC_MNEMONIC; return(MNEMONIC); }
145 "SED"           { yylval.mnemonic = SED_MNEMONIC; return(MNEMONIC); }
146 "SEI"           { yylval.mnemonic = SEI_MNEMONIC; return(MNEMONIC); }
147 "STA"           { yylval.mnemonic = STA_MNEMONIC; return(MNEMONIC); }
148 "STX"           { yylval.mnemonic = STX_MNEMONIC; return(MNEMONIC); }
149 "STY"           { yylval.mnemonic = STY_MNEMONIC; return(MNEMONIC); }
150 "TAX"           { yylval.mnemonic = TAX_MNEMONIC; return(MNEMONIC); }
151 "TAY"           { yylval.mnemonic = TAY_MNEMONIC; return(MNEMONIC); }
152 "TSX"           { yylval.mnemonic = TSX_MNEMONIC; return(MNEMONIC); }
153 "TXA"           { yylval.mnemonic = TXA_MNEMONIC; return(MNEMONIC); }
154 "TXS"           { yylval.mnemonic = TXS_MNEMONIC; return(MNEMONIC); }
155 "TYA"           { yylval.mnemonic = TYA_MNEMONIC; return(MNEMONIC); }
156 "X"         { return('X'); }
157 "Y"         { return('Y'); }
158 "A"         { return('A'); }
159 "MASK"          { return(MASK); }
160 "SIZEOF"        { return(SIZEOF); }
161 {pragma_prefix}"DATA"   { return(DATASEG); }
162 {pragma_prefix}"CODE"   { return(CODESEG); }
163 {pragma_prefix}"DATASEG" { return(DATASEG); }
164 {pragma_prefix}"CODESEG" { return(CODESEG); }
165 {pragma_prefix}"IF" { return(IF); }
166 {pragma_prefix}"IFDEF"  { return(IFDEF); }
167 {pragma_prefix}"IFNDEF" { return(IFNDEF); }
168 {pragma_prefix}"ELSE"   { return(ELSE); }
169 {pragma_prefix}"ELIF"   { return(ELIF); }
170 {pragma_prefix}"ENDIF"  { return(ENDIF); }
171 {pragma_prefix}"MACRO"  { return(MACRO); }
172 {pragma_prefix}"END"    { return(END); }
173 {pragma_prefix}"ENDE"   { return(ENDE); }
174 {pragma_prefix}"ENDM"   { return(ENDM); }
175 {pragma_prefix}"ENDP"   { return(ENDP); }
176 {pragma_prefix}"ENDS"   { return(ENDS); }
177 {pragma_prefix}"EQU"    { return(EQU); }
178 {pragma_prefix}"DEFINE" { return(DEFINE); }
179 {pragma_prefix}"INCLUDE" { return(INCSRC); }
180 {pragma_prefix}"INCSRC" { return(INCSRC); }
181 {pragma_prefix}"INCBIN" { return(INCBIN); }
182 {pragma_prefix}"ALIGN"  { return(ALIGN); }
183 {pragma_prefix}"PUBLIC" { return(PUBLIC); }
184 {pragma_prefix}"EXTRN"  { return(EXTRN); }
185 {pragma_prefix}"ZEROPAGE" { return(ZEROPAGE); }
186 {pragma_prefix}"CHARMAP" { return(CHARMAP); }
187 {pragma_prefix}"STRUC"  { return(STRUC); }
188 {pragma_prefix}"UNION"  { return(UNION); }
189 {pragma_prefix}"RECORD" { return(RECORD); }
190 {pragma_prefix}"ENUM"   { return(ENUM); }
191 {pragma_prefix}"PROC"   { return(PROC); }
192 {pragma_prefix}"REPT"   { return(REPT); }
193 {pragma_prefix}"TAG"    { return(TAG); }
194 {pragma_prefix}"TYPE"   { return(TAG); }
195 {pragma_prefix}"LABEL"  { return(_LABEL_); }
196 {pragma_prefix}"MESSAGE" { return(MESSAGE); }
197 {pragma_prefix}"WARNING" { return(WARNING); }
198 {pragma_prefix}"ERROR"  { return(ERROR); }
199 {pragma_prefix}"WHILE"  { return(WHILE); }
200 {pragma_prefix}"PAD"    { return(DSB); }
201 {pragma_prefix}"DB" { return(BYTE); }
202 {pragma_prefix}"BYTE"   { return(BYTE); }
203 {pragma_prefix}"CHAR"   { return(CHAR); }
204 {pragma_prefix}"ASC"    { return(CHAR); }
205 {pragma_prefix}"DW" { return(WORD); }
206 {pragma_prefix}"WORD"   { return(WORD); }
207 {pragma_prefix}"DD" { return(DWORD); }
208 {pragma_prefix}"DWORD"  { return(DWORD); }
209 {pragma_prefix}"DSB"    { return(DSB); }
210 {pragma_prefix}"DSW"    { return(DSW); }
211 {pragma_prefix}"DSD"    { return(DSD); }
212 {pragma_prefix}"ORG"    { return(ORG); }
213 {label_prefix}{identifier}":" { yylval.label = maybe_ignorecase(strip_label()); return(LABEL); }
214 {label_prefix}"@@"{local_id}":" { yylval.label = maybe_ignorecase(strip_label()); return(LOCAL_LABEL); }
215 "@@"{local_id}      { yylval.ident = maybe_ignorecase(yytext); return(LOCAL_ID); }
216 {identifier}        { yylval.ident = maybe_ignorecase(yytext); return(IDENTIFIER); }
217 {string_literal}    { yytext[yyleng-1] = '\0'; yylval.string = &yytext[1]; return(STRING_LITERAL); }
218 "+"{2,8}        { yylval.ident = yytext; return(FORWARD_BRANCH); }
219 "-"{2,8}        { yylval.ident = yytext; return(BACKWARD_BRANCH); }
220 "::"            { return(SCOPE_OP); }
221 "."         { return('.'); }
222 \n          { LOCATION_LINES (yylloc, yyleng); LOCATION_STEP (yylloc); return('\n'); }
223 ","         { return(','); }
224 ":"         { return(':'); }
225 "#"         { return('#'); }
226 "="         { return('='); }
227 "("         { return( yyparswap ? '[' : '(' ); }
228 ")"         { return( yyparswap ? ']' : ')' ); }
229 "["         { return( yyparswap ? '(' : '[' ); }
230 "]"         { return( yyparswap ? ')' : ']'); }
231 "{"         { return('{'); }
232 "}"         { return('}'); }
233 "&"         { return('&'); }
234 "!"         { return('!'); }
235 "~"         { return('~'); }
236 "-"         { return('-'); }
237 "+"         { return('+'); }
238 "*"         { return('*'); }
239 "/"         { return('/'); }
240 "%"         { return('%'); }
241 "<"         { return('<'); }
242 ">"         { return('>'); }
243 "^"         { return('^'); }
244 "|"         { return('|'); }
245 ">>"                    { return(SHR_OP); }
246 "<<"                    { return(SHL_OP); }
247 "<="                    { return(LE_OP); }
248 ">="                    { return(GE_OP); }
249 "=="                    { return(EQ_OP); }
250 "!="                    { return(NE_OP); }
251 "$"         { return('$'); }
252 "@"         { return('@'); }
253 .           { yyerror("Skipping invalid character(s)"); LOCATION_STEP (yylloc); }
256  * Describes a file stack record.
257  * It holds name, location and buffer state for it.
258  */
259 typedef struct tag_file_stack_rec {
260     const char *name; /* Name of the file */
261     char *path; /* Absolute path */
262     YY_BUFFER_STATE buf;    /* flex input buffer */
263     YYLTYPE loc;    /* Current position in file */
264     FILE *fp;   /* File handle */
265 } file_stack_rec;
267 /* Max. nesting depth */
268 #define FILE_STACK_SIZE 32
270 /* Stack of files */
271 static file_stack_rec file_stack[FILE_STACK_SIZE];
273 /* File stack pointer */
274 static int file_stack_ptr;
276 /* Macro to access top of file stack */
277 #define FTOS() file_stack[file_stack_ptr]
280  * Resets the location described by yylloc.
281  */
282 void yyresetloc(void)
284     LOCATION_RESET(yylloc);
288  * Helper function used to handle INCSRC and INCBIN
289  * statements during parsing.
290  */
291 FILE *open_included_file(const char *filename, int quoted_form, char **path_out)
293     FILE *fp = 0;
294     char *path = 0;
295     if (filename[0] == '/') {
296         /* Absolute path */
297         fp = fopen(filename, "rt");
298         if (fp) {
299             char *lastslash = strrchr(filename, '/');
300             int len = lastslash - filename;
301             assert(len > 0);
302             path = (char *)malloc(len + 1);
303             strncpy(path, filename, len);
304             path[len] = '\0';
305         }
306     } else {
307         /* Not absolute path */
308         int i;
309         if (quoted_form) {
310             /* Try parent includes */
311             for (i = file_stack_ptr; i >= 0; --i) {
312                 const char *include_path = file_stack[i].path;
313                 char *tmp = (char *)malloc(
314                     strlen(include_path) + strlen("/") + strlen(filename) + 1);
315                 strcpy(tmp, include_path);
316                 strcat(tmp, "/");
317                 strcat(tmp, filename);
318                 fp = fopen(tmp, "rt");
319                 if (fp) {
320                     char *lastslash = strrchr(tmp, '/');
321                     int len = lastslash - tmp;
322                     assert(len > 0);
323                     path = (char *)malloc(len + 1);
324                     strncpy(path, tmp, len);
325                     path[len] = '\0';
326                     free(tmp);
327                     break;
328                 }
329                 free(tmp);
330                 /* We only search the current dir for now. */
331                 break;
332             }
333         }
334         if (!fp) {
335             /* Try search paths */
336             for (i = 0; i < xasm_args.include_path_count; ++i) {
337                 const char *include_path = xasm_args.include_paths[i];
338                 char *tmp = (char *)malloc(
339                     strlen(include_path) + strlen("/") + strlen(filename) + 1);
340                 strcpy(tmp, include_path);
341                 strcat(tmp, "/");
342                 strcat(tmp, filename);
343                 fp = fopen(tmp, "rt");
344                 if (fp) {
345                     char *lastslash = strrchr(tmp, '/');
346                     int len = lastslash - tmp;
347                     assert(len > 0);
348                     path = (char *)malloc(len + 1);
349                     strncpy(path, tmp, len);
350                     path[len] = '\0';
351                     free(tmp);
352                     break;
353                 }
354                 free(tmp);
355              }
356         }
357     }
358     if (path_out)
359         *path_out = path;
360     return fp;
364  * Function called by lexer upon EOF(yyin).
365  */
366 int yywrap()
368     /* Discard of buffer that has been scanned */
369     yy_delete_buffer(YY_CURRENT_BUFFER);
370     /* Close current file */
371     fclose(FTOS().fp);
372     free(FTOS().path);
373     /* Resume scanning of previous buffer, if any */
374     if (file_stack_ptr > 0) {
375         /* Pop stack */
376         file_stack_ptr--;
377         /* Restore location */
378         yylloc = FTOS().loc;
379         /* Resume scanning from this buffer */
380         yy_switch_to_buffer(FTOS().buf);
381         /* Not end of all input. */
382         return(0);
383     }
384     else {
385         /* We have reached end of all input. */
386         return(1);
387     }
391  * Opens a file and resumes scanning from there.
392  * The current file's status is pushed on stack.
393  * @param filename Name of new file to start scanning
394  * @return error code (0, 1 or 2)
395  */
396 int yypushandrestart(const char *filename, int quoted_form)
398     FILE *fp = 0;
399     char *path = 0;
400     /* Check for stack overflow */
401     if (file_stack_ptr == FILE_STACK_SIZE-1) {
402         /* Error, stack overflow */
403         return 2;
404     }
405     fp = open_included_file(filename, quoted_form, &path);
406     if (fp) {
407         /* Save position in current file */
408         FTOS().loc = yylloc;
409         /* Push the new file */
410         file_stack_ptr++;
411         FTOS().name = filename;
412         FTOS().path = path;
413         FTOS().buf = yy_create_buffer(fp, YY_BUF_SIZE);
414         FTOS().fp = fp;
415         /* Reset file location */
416         yyresetloc();
417         /* Resume scanning from the new buffer */
418         yy_switch_to_buffer(FTOS().buf);
419         /* Success */
420         return 0;
421     } else {
422         /* Error, couldn't open file */
423         return 1;
424     }
428  * Initializes the lexer, tells it to start tokenizing from the given file.
429  * @param filename Name of file where scanning is initiated
430  * @param swap_parens Use ( ) for indirection if 1, [ ] otherwise
431  * @return 1 if success, 0 otherwise
432  */
433 int yybegin(const char *filename, int swap_parens, int ignore_case)
435     FILE *fp;
436     yyparswap = swap_parens;
437     yyignorecase = ignore_case;
438     /* Attempt to open the given file */
439     fp = fopen(filename, "rt");
440     if (fp) {
441         /* Figure out path */
442         char *path;
443         char *lastslash = strrchr(filename, '/');
444         if (filename[0] != '/') {
445             /* Not absolute */
446             if (lastslash) {
447                 int len = lastslash - filename;
448                 assert(len > 0);
449                 path = (char *)malloc(strlen(xasm_path) + 1 + len + 1);
450                 strcpy(path, xasm_path);
451                 strcat(path, "/");
452                 strncat(path, filename, len);
453             } else {
454                 path = (char *)malloc(strlen(xasm_path) + 1);
455                 strcpy(path, xasm_path);
456             }
457         } else {
458             /* Absolute */
459             int len = lastslash - filename;
460             assert(len > 0);
461             path = (char *)malloc(len + 1);
462             strncpy(path, filename, len);
463             path[len] = '\0';
464         }
465         /* Init stack */
466         file_stack_ptr = 0;
467         FTOS().name = filename;
468         FTOS().path = path;
469         FTOS().buf = yy_create_buffer(fp, YY_BUF_SIZE);
470         FTOS().fp = fp;
471         /* Reset file location */
472         yyresetloc();
473         /* Use the new buffer */
474         yy_switch_to_buffer(FTOS().buf);
475         /* Success */
476         return 1;
477     } else {
478         /* Couldn't open file */
479         return 0;
480     }
484  * Gets the name of the file that is currently being tokenized.
485  */
486 const char *yy_current_filename()
488     return FTOS().name;
492  * Called by the parser to report an error during parsing.
493  * @param s Error message
494  */
495 void yyerror(const char *s) {
496     int i;
497     /* Print line of form: file:pos:message */
498     fprintf(stderr, "%s:", yy_current_filename());
499     LOCATION_PRINT(stderr, yylloc);
500     fprintf(stderr, ": %s\n", s);
501     /* Print include-trace */
502     for (i=file_stack_ptr-1; i>=0; i--) {
503         fprintf(stderr, "(%s:", file_stack[i].name);
504         LOCATION_PRINT(stderr, file_stack[i].loc);
505         fprintf(stderr, ")\n");
506     }
510  * Call when yytext is a label to remove whitespace and punctuation.
511  */
512 char *strip_label()
514     int start;
515     /* Kill the ':' at the end */
516     yytext[strlen(yytext)-1] = 0;
517     /* Skip the whitespace, if any */
518     start = 0;
519     while ((yytext[start] == ' ') || (yytext[start] == '\t')) start++;
520     return &yytext[start];
523 static char *__strupr(char *str)
525     char *p = str;
526     while (*p) {
527         *p = toupper(*p);
528         ++p;
529     }
530     return str;
533 const char *maybe_ignorecase(char *str)
535     if (yyignorecase)
536         __strupr(str);
537     return str;
540 char *scan_include(int terminator)
542     static char buf[1024];
543     int i = 0;
544     while (1) {
545         int c = input();
546         if (c == terminator)
547             break;
548         else if (c == '\n') {
549             yyerror("unterminated include filename");
550             unput(c);
551             break;
552         } else if (i == 1023) {
553             yyerror("include filename is too long");
554             break;
555         } else {
556             buf[i++] = (char)c;
557         }
558     }
559     buf[i] = '\0';
560     LOCATION_STEP (yylloc); 
561     return buf;