- An extern statement finishes with the first closing '}' or the first
[wine] / tools / wrc / parser.l
1 /* -*-C-*-
2  *
3  * Copyright 1994 Martin von Loewis
4  * Copyright 1998 Bertho A. Stultiens (BS)
5  *
6  * 20-Jun-1998 BS       - Changed the filename conversion. Filenames are
7  *                        case-sensitive inder *nix, but not under dos.
8  *                        default behaviour is to convert to lower case.
9  *                      - All backslashes are converted to forward and
10  *                        both single and double slash is recognized as
11  *                        MS/Borland does.
12  *                      - Fixed a bug in 'yywf' case that prevented
13  *                        double quoted names to be scanned propperly.
14  *
15  * 19-May-1998 BS       - Started to build a preprocessor.
16  *                      - Changed keyword processing completely to
17  *                        table-lookups.
18  *
19  * 20-Apr-1998 BS       - Added ';' comment stripping
20  *
21  * 17-Apr-1998 BS       - Made the win32 keywords optional when compiling in
22  *                        16bit mode
23  *
24  * 15-Apr-1998 BS       - Changed string handling to include escapes
25  *                      - Added unicode string handling (no codepage
26  *                        translation though).
27  *                      - 'Borrowed' the main idea of string scanning from
28  *                        the flex manual pages.
29  *                      - Added conditional handling of scanning depending
30  *                        on the state of the parser. This was mainly required
31  *                        to distinguish a file to load or raw data that
32  *                        follows. MS's definition of filenames is rather
33  *                        complex... It can be unquoted or double quoted. If
34  *                        double quoted, then the '\\' char is not automatically
35  *                        escaped according to Borland's rc compiler, but it
36  *                        accepts both "\\path\\file.rc" and "\path\file.rc".
37  *                        This makes life very hard! I go for the escaped
38  *                        version, as this seems to be the documented way...
39  *                      - Single quoted strings are now parsed and converted
40  *                        here.
41  *                      - Added comment stripping. The implementation is
42  *                        'borrowed' from the flex manpages.
43  *                      - Rebuild string processing so that it may contain
44  *                        escaped '\0'.
45  */
46
47 /* Exclusive rules when looking for a filename */
48 %x yywf
49 %x yywf_s
50 /* Exclusive string handling */
51 %x yystr
52 /* Exclusive unicode string handling */
53 %x yylstr
54 /* Exclusive rcdata single quoted data handling */
55 %x yyrcd
56 /* Exclusive comment eating... */
57 %x comment
58 /* Preprocessor exclusives */
59 %x pp_incl
60 %x pp_def
61 %x pp_undef
62 %x pp_if
63 %x pp_ifdef
64 %x pp_ifndef
65 %x pp_elif
66 %x pp_else
67 %x pp_endif
68 %x pp_error
69 /* Set when accumulating #define's expansion text */
70 %x pp_def_s
71 /* Set when processing function type defines */
72 %x pp_ignore
73 /* Set when need to strip to eol */
74 %x pp_ignore_eol
75 /* Set when handling a false #if case */
76 %x pp_false
77 /* Set when stripping c-junk */
78 %x pp_stripe
79 %x pp_strips
80 %x pp_stripp
81 %x pp_stripp_final
82
83 /*%option stack*/
84 %option never-interactive
85 /*%option noyywrap */
86 /* Some shortcut definitions */
87 ws      [ \f\t\r]
88 cident  [a-zA-Z_][0-9a-zA-Z_]*
89
90 %{
91
92 #if !defined(YY_FLEX_MAJOR_VERSION) || (1000 * YY_FLEX_MAJOR_VERSION + YY_FLEX_MINOR_VERSION < 2005)
93 #error Must use flex version 2.5.1 or higher (yy_scan_* routines are required).
94 #endif
95
96 /*#define LEX_DEBUG*/
97
98 #include "config.h"
99
100 #include <stdio.h>
101 #include <stdlib.h>
102 #include <string.h>
103 #include <ctype.h>
104
105 #include "wrc.h"
106 #include "utils.h"
107 #include "preproc.h"
108 #include "parser.h"
109 #include "newstruc.h"
110
111 #include "y.tab.h"
112
113 #define YY_USE_PROTOS
114 #define YY_NO_UNPUT
115
116 /* Always update the current character position within a line */
117 #define YY_USER_ACTION  char_number+=yyleng;
118
119 raw_data_t *new_raw_data(void);
120
121 void addcchar(char c);
122 void addwchar(short s);
123 string_t *get_buffered_cstring(void);
124 string_t *get_buffered_wstring(void);
125 string_t *make_string(char *s);
126 string_t *make_filename(char *s, int len);
127
128 int line_number = 1;            /* The current line */
129 int char_number = 1;            /* The current char pos within the line */
130 static char *cbuffer;           /* Buffers for string collection */
131 static int cbufidx;
132 static int cbufalloc = 0;
133 static short *wbuffer;
134 static int wbufidx;
135 static int wbufalloc = 0;
136 static int want_nl = 0;         /* Set when newline needs to go to parser */
137 static int want_ident = 0;      /* Set is #ifdef, #ifndef or defined is seen */
138 static int stripslevel = 0;     /* Count {} during pp_strips/pp_stripe mode */
139 static int stripplevel = 0;     /* Count () during pp_strips mode */
140 static char *substtext = NULL;  /* Holds the substition text while getting a define */
141 static int cjunk_tagline;       /* Where did we start stripping (helps error tracking) */
142
143 #ifdef YY_USE_STACK
144 void push_to(int start) { yy_push_state(start); }
145 void pop_start(void)    { yy_pop_state(start); }
146 #else
147 #define MAXSTARTSTACK   32
148 static int startstack[MAXSTARTSTACK];
149 static int startstackidx = 0;
150
151 void push_to(int start)
152 {
153         if(yydebug)
154                 printf("push_to(%d): %d -> %d\n", line_number, YY_START, start);
155         if(startstackidx >= MAXSTARTSTACK-1)
156                 internal_error(__FILE__, __LINE__, "Start condition stack overflow");
157         startstack[startstackidx++] = YY_START;
158         BEGIN(start);
159 }
160
161 void pop_start(void)
162 {
163         if(yydebug)
164                 printf("pop_start(%d): %d <- %d\n", line_number, startstack[startstackidx-1], YY_START);
165         if(startstackidx <= 0)
166                 internal_error(__FILE__, __LINE__, "Start condition stack underflow");
167         --startstackidx;
168         BEGIN(startstack[startstackidx]);
169 }
170 #endif
171
172
173 struct bufferstackentry {
174         YY_BUFFER_STATE bufferstate;    /* Buffer to switch back to */
175         struct pp_entry *define;        /* Points to expanding define
176                                            or NULL if handling includes
177                                          */
178         int line_number;                /* Line that we were handling */
179         int char_number;                /* The current position */
180         char *filename;                 /* Filename that we were handling */
181 };
182
183 #define MAXBUFFERSTACK 128
184 static struct bufferstackentry bufferstack[MAXBUFFERSTACK];
185 static int bufferstackidx = 0;
186
187 void push_buffer(YY_BUFFER_STATE buf, struct pp_entry *ppp, char *filename)
188 {
189         if(yydebug)
190                 printf("push_buffer: %p %p %p\n", buf, ppp, filename);
191         if(bufferstackidx >= MAXBUFFERSTACK-1)
192                 internal_error(__FILE__, __LINE__, "Buffer stack overflow");
193         memset(&bufferstack[bufferstackidx], 0, sizeof(bufferstack[0]));
194         bufferstack[bufferstackidx].bufferstate = buf;
195         bufferstack[bufferstackidx].define = ppp;
196         if(ppp)
197                 ppp->expanding = 1;
198         else if(filename)
199         {
200                 /* These will track the yyerror to the correct file and line */
201                 bufferstack[bufferstackidx].line_number = line_number;
202                 bufferstack[bufferstackidx].char_number = char_number;
203                 line_number = 1;
204                 char_number = 1;
205                 bufferstack[bufferstackidx].filename = input_name;
206                 input_name = filename;
207         }
208         else
209                 internal_error(__FILE__, __LINE__, "Pushing buffer without knowing where to go to");
210         bufferstackidx++;
211 }
212
213 YY_BUFFER_STATE pop_buffer(void)
214 {
215         if(bufferstackidx <= 0)
216                 return (YY_BUFFER_STATE)0;
217         bufferstackidx--;
218         if(bufferstack[bufferstackidx].define)
219                 bufferstack[bufferstackidx].define->expanding = 0;
220         else
221         {
222                 line_number = bufferstack[bufferstackidx].line_number;
223                 char_number = bufferstack[bufferstackidx].char_number;
224                 input_name = bufferstack[bufferstackidx].filename;
225                 fclose(yyin);
226         }
227         if(yydebug)
228                 printf("pop_buffer: %p %p (%d, %d) %p\n",
229                         bufferstack[bufferstackidx].bufferstate,
230                         bufferstack[bufferstackidx].define,
231                         bufferstack[bufferstackidx].line_number,
232                         bufferstack[bufferstackidx].char_number,
233                         bufferstack[bufferstackidx].filename);
234         yy_switch_to_buffer(bufferstack[bufferstackidx].bufferstate);
235         return bufferstack[bufferstackidx].bufferstate;
236 }
237
238 void do_include(char *name, int namelen)
239 {
240         char *cpy = (char *)xmalloc(namelen);
241         strcpy(cpy, name+1);    /* strip leading " or < */
242         cpy[namelen-2] = '\0';  /* strip trailing " or > */
243         if((yyin = open_include(cpy, name[0] == '"')) == NULL)
244                 yyerror("Unable to open include file %s", cpy);
245         push_buffer(YY_CURRENT_BUFFER, NULL, cpy);
246         yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
247 }
248
249
250 struct keyword {
251         char    *keyword;
252         int     token;
253         int     isextension;
254         int     needcase;
255         int     alwayskeyword;
256 };
257
258 static struct keyword keywords[] = {
259         { "ACCELERATORS", ACCELERATORS, 0, 0, 0},
260         { "ALT", ALT, 0, 0, 0},
261         { "ASCII", ASCII, 0, 0, 0},
262         { "AUTO3STATE", AUTO3STATE, 1, 0, 0},
263         { "AUTOCHECKBOX", AUTOCHECKBOX, 1, 0, 0},
264         { "AUTORADIOBUTTON", AUTORADIOBUTTON, 1, 0, 0},
265         { "BEGIN", tBEGIN, 0, 0, 1},
266         { "BITMAP", tBITMAP, 0, 0, 0},
267         { "BLOCK", BLOCK, 0, 0, 1},
268         { "BUTTON", BUTTON, 1, 0, 0},
269         { "CAPTION", CAPTION, 0, 0, 0},
270         { "CHARACTERISTICS", CHARACTERISTICS, 1, 0, 0},
271         { "CHECKBOX", CHECKBOX, 0, 0, 0},
272         { "CHECKED", CHECKED, 0, 0, 0},
273         { "CLASS", CLASS, 0, 0, 0},
274         { "COMBOBOX", COMBOBOX, 0, 0, 0},
275         { "CONTROL", CONTROL, 0, 0, 0},
276         { "CTEXT", CTEXT, 0, 0, 0},
277         { "CURSOR", CURSOR, 0, 0, 0},
278         { "defined", tDEFINED, 0, 1, 1},
279         { "DEFPUSHBUTTON", DEFPUSHBUTTON, 0, 0, 1},
280         { "DIALOG", DIALOG, 0, 0, 0},
281         { "DIALOGEX", DIALOGEX, 1, 0, 0},
282         { "DISCARDABLE", DISCARDABLE, 0, 0, 0},
283         { "DLGINIT", DLGINIT, 0, 0, 0},
284         { "EDITTEXT", EDITTEXT, 0, 0, 0},
285         { "END", tEND, 0, 0, 1},
286         { "EXSTYLE", EXSTYLE, 0, 0, 0},
287         { "extern", tEXTERN, 0, 1, 1},
288         { "FILEFLAGS", FILEFLAGS, 0, 0, 0},
289         { "FILEFLAGSMASK", FILEFLAGSMASK, 0, 0, 0},
290         { "FILEOS", FILEOS, 0, 0, 0},
291         { "FILESUBTYPE", FILESUBTYPE, 0, 0, 0},
292         { "FILETYPE", FILETYPE, 0, 0, 0},
293         { "FILEVERSION", FILEVERSION, 0, 0, 0},
294         { "FIXED", tFIXED, 0, 0, 0},
295         { "FONT", FONT, 0, 0, 0},
296         { "GRAYED", GRAYED, 0, 0, 0},
297         { "GROUPBOX", GROUPBOX, 0, 0, 0},
298         { "HELP", HELP, 0, 0, 0},
299         { "ICON", ICON, 0, 0, 0},
300         { "IMPURE", IMPURE, 0, 0, 0},
301         { "INACTIVE", INACTIVE, 0, 0, 0},
302         { "LANGUAGE", LANGUAGE, 1, 0, 1},
303         { "LISTBOX", LISTBOX, 0, 0, 0},
304         { "LOADONCALL", LOADONCALL, 0, 0, 0},
305         { "LTEXT", LTEXT, 0, 0, 0},
306         { "MENU", MENU, 0, 0, 0},
307         { "MENUBARBREAK", MENUBARBREAK, 0, 0, 0},
308         { "MENUBREAK", MENUBREAK, 0, 0, 0},
309         { "MENUEX", MENUEX, 1, 0, 0},
310         { "MENUITEM", MENUITEM, 0, 0, 0},
311         { "MESSAGETABLE", MESSAGETABLE, 1, 0, 0},
312         { "MOVEABLE", MOVEABLE, 0, 0, 0},
313         { "NOINVERT", NOINVERT, 0, 0, 0},
314         { "NOT", NOT, 0, 0, 0},
315         { "POPUP", POPUP, 0, 0, 0},
316         { "PRELOAD", PRELOAD, 0, 0, 0},
317         { "PRODUCTVERSION", PRODUCTVERSION, 0, 0, 0},
318         { "PURE", tPURE, 0, 0, 0},
319         { "PUSHBUTTON", PUSHBUTTON, 0, 0, 0},
320         { "RADIOBUTTON", RADIOBUTTON, 0, 0, 0},
321         { "RCDATA", RCDATA, 0, 0, 0},
322         { "RTEXT", RTEXT, 0, 0, 0},
323         { "SCROLLBAR", SCROLLBAR, 0, 0, 0},
324         { "SEPARATOR", SEPARATOR, 0, 0, 0},
325         { "SHIFT", SHIFT, 0, 0, 0},
326         { "STATE3", STATE3, 1, 0, 0},
327         { "STRING", tSTRING, 0, 0, 0},
328         { "STRINGTABLE", STRINGTABLE, 0, 0, 1},
329         { "STYLE", STYLE, 0, 0, 0},
330         { "TOOLBAR", TOOLBAR, 1, 0, 0},
331         { "typedef", tTYPEDEF, 0, 1, 1},
332         { "VALUE", VALUE, 0, 0, 0},
333         { "VERSION", VERSION, 1, 0, 0},
334         { "VERSIONINFO", VERSIONINFO, 0, 0, 0},
335         { "VIRTKEY", VIRTKEY, 0, 0, 0}
336 };
337
338 #define NKEYWORDS       (sizeof(keywords)/sizeof(keywords[0]))
339 #define KWP(p)          ((struct keyword *)(p))
340 int kw_cmp_func(const void *s1, const void *s2)
341 {
342         int ret;
343         ret = strcasecmp(KWP(s1)->keyword, KWP(s2)->keyword);
344         if(!ret && (KWP(s1)->needcase || KWP(s2)->needcase))
345                 return strcmp(KWP(s1)->keyword, KWP(s2)->keyword);
346         else
347                 return ret;
348 }
349
350 #define KW_BSEARCH
351 #define DO_SORT
352 struct keyword *iskeyword(char *kw)
353 {
354         struct keyword *kwp;
355         struct keyword key;
356         key.keyword = kw;
357         key.needcase = 0;
358 #ifdef DO_SORT
359         {
360                 /* Make sure that it is sorted for bsearsh */
361                 static int sorted = 0;
362                 if(!sorted)
363                 {
364                         qsort(keywords, NKEYWORDS, sizeof(keywords[0]), kw_cmp_func);
365                         sorted = 1;
366                 }
367         }
368 #endif
369 #ifdef KW_BSEARCH
370         kwp = bsearch(&key, keywords, NKEYWORDS, sizeof(keywords[0]), kw_cmp_func);
371 #else
372         {
373                 int i;
374                 for(i = 0; i < NKEYWORDS; i++)
375                 {
376                         if(!kw_cmp_func(&key, &keywords[i]))
377                                 break;
378                 }
379                 if(i < NKEYWORDS)
380                         kwp = &keywords[i];
381                 else
382                         kwp = NULL;
383         }
384 #endif
385
386 #ifdef LEX_DEBUG
387         if(kwp && !strcmp(kwp->keyword, "LANGUAGE"))
388                 printf("Got Language\n");
389 #endif
390         if(kwp == NULL || (kwp->isextension && !extensions))
391                 return NULL;
392         else
393                 return kwp;
394 }
395
396 void add_to_substtext(char *text, int len)
397 {
398         if(!substtext)
399         {
400                 substtext = xstrdup(text);
401         }
402         else
403         {
404                 substtext = (char *)xrealloc(substtext, strlen(substtext)+len+1);
405                 strcat(substtext, text);
406         }
407 }
408
409 %}
410
411 %%
412         /* #include handling */
413 ^{ws}*#{ws}*include{ws}*        push_to(pp_incl);
414 <pp_incl>\<[^\n\>]+\>           do_include(yytext, yyleng); pop_start();
415 <pp_incl>\"[^\n\>]+\"           do_include(yytext, yyleng); pop_start();
416 <pp_incl>.              yyerror("Malformed #include");
417
418         /* #define handling */
419 ^{ws}*#{ws}*define{ws}* push_to(pp_def);
420 <pp_def>{cident}        {
421                                 set_define(yytext);
422                                 push_to(pp_def_s);
423                         }
424 <pp_def>{cident}\(      push_to(pp_ignore); /* Ignore function-like defines for now*/
425 <pp_def>.               yyerror("Malformed #define");
426
427 <pp_ignore,pp_def_s>[^\/\\\n]*  {
428                         if(YY_START == pp_def_s)
429                                 add_to_substtext(yytext, yyleng);
430                 }
431 <pp_ignore,pp_def_s>\/[^\/\*][^\/\\\n]* { /* Comment is handled in normal handling */
432                         if(YY_START == pp_def_s)
433                                 add_to_substtext(yytext, yyleng);
434                 }
435 <pp_ignore,pp_def_s>\\{ws}*\n   line_number++;  char_number = 1; /* Line continuation */
436 <pp_ignore,pp_def_s>\n          {
437                         if(YY_START == pp_def_s)
438                         {
439                                 add_define(substtext ? substtext : "");
440                                 free(substtext);
441                                 substtext = NULL;
442                         }
443                         line_number++;
444                         char_number = 1;
445                         pop_start();
446                         pop_start();
447                 }
448
449         /* #undef handling */
450 ^{ws}*#{ws}*undef{ws}*  push_to(pp_undef);
451 <pp_undef>{cident}      {
452                                 del_define(yytext);
453                                 pop_start();
454                                 /*push_to(pp_ignore);*/
455                         }
456
457         /* Conditional handling */
458 <INITIAL,pp_strips,pp_stripe,pp_stripp,pp_false>^{ws}*#{ws}*if{ws}*     {
459                         if(YY_START == pp_false)
460                         {
461                                 if(yydebug)
462                                         printf("(%d)#if ignored\n", line_number);
463                                 push_if(0, 0, 1);
464                                 push_to(pp_ignore_eol);
465                         }
466                         else
467                         {
468                                 push_to(INITIAL);
469                                 want_nl = 1;
470                                 return tIF;
471                         }
472                 }
473 <INITIAL,pp_strips,pp_stripe,pp_stripp,pp_false>^{ws}*#{ws}*ifdef{ws}*  {
474                         if(YY_START == pp_false)
475                         {
476                                 if(yydebug)
477                                         printf("(%d)#ifdef ignored\n", line_number);
478                                 push_if(0, 0, 1);
479                                 push_to(pp_ignore_eol);
480                         }
481                         else
482                         {
483                                 push_to(INITIAL);
484                                 want_nl = 1;
485                                 want_ident = 1;
486                                 return tIFDEF;
487                         }
488                 }
489 <INITIAL,pp_strips,pp_stripe,pp_stripp,pp_false>^{ws}*#{ws}*ifndef{ws}* {
490                         if(YY_START == pp_false)
491                         {
492                                 if(yydebug)
493                                         printf("(%d)#ifndef ignored\n", line_number);
494                                 push_if(0, 0, 1);
495                                 push_to(pp_ignore_eol);
496                         }
497                         else
498                         {
499                                 push_to(INITIAL);
500                                 want_nl = 1;
501                                 want_ident = 1;
502                                 return tIFNDEF;
503                         }
504                 }
505 <INITIAL,pp_strips,pp_stripe,pp_stripp,pp_false>^{ws}*#{ws}*elif{ws}*   {
506                         if(!isnevertrue_if())
507                         {
508                                 push_to(INITIAL);
509                                 want_nl = 1;
510                                 return tELIF;
511                         }
512                         else if(YY_START == pp_false)
513                                 push_to(pp_ignore_eol);
514                         if(yydebug)
515                                 printf("(%d)#elif ignored\n", line_number);
516                 }
517 <INITIAL,pp_strips,pp_stripe,pp_stripp,pp_false>^{ws}*#{ws}*else{ws}*   {
518                         if(!isnevertrue_if())
519                         {
520                                 push_to(INITIAL);
521                                 want_nl = 1;
522                                 return tELSE;
523                         }
524                         if(yydebug)
525                                 printf("(%d)#else ignored\n", line_number);
526                 }
527 <INITIAL,pp_strips,pp_stripe,pp_stripp,pp_false>^{ws}*#{ws}*endif{ws}*  {
528                         if(!isnevertrue_if())
529                         {
530                                 want_nl = 1;
531                                 return tENDIF;
532                         }
533                         else
534                         {
535                                 if(yydebug)
536                                         printf("(%d)#endif ignored\n", line_number);
537                                 pop_if();
538                         }
539                 }
540
541         /* The error directive */
542 <INITIAL,pp_strips,pp_stripe,pp_stripp>^{ws}*#{ws}*error{ws}*   push_to(pp_error);
543 <pp_error>[^\n]*        yyerror("Error directive: %s", yytext);
544 <pp_false>^{ws}*#{ws}*error[^\n]* {
545                         if(yydebug)
546                                 printf("(%d)#error ignored\n", line_number);
547                 }
548
549         /* preprocessor junk */
550 <INITIAL,pp_strips,pp_stripe,pp_stripp,pp_false>^{ws}*#{ws}*pragma[^\n]*        ;       /* Ignore #pragma */
551 <INITIAL,pp_strips,pp_stripe,pp_stripp,pp_false>^{ws}*#{ws}*line[^\n]*          ;       /* Ignore #line */
552  /* We'll get an error on malformed #xxx statements
553   * by not recognising '#' at all. This helps tracking
554   * preprocessor errors.
555   */
556  /*^{ws}*#{ws}*                 ;        Ignore # */
557
558 <pp_strips>\{           stripslevel++;
559 <pp_strips>\}           stripslevel--;
560 <pp_strips>;            if(!stripslevel) pop_start();
561 <pp_strips>\/[^*\n]             ; /* To catch comments */
562 <pp_strips>[^\{\};\n#/]*        ; /* Ignore rest */
563
564 <pp_stripe>\{           stripslevel++;
565 <pp_stripe>\}   {
566                         stripslevel--;
567                         if(!stripslevel) pop_start();
568                 }
569 <pp_stripe>;            if(!stripslevel) pop_start();
570 <pp_stripe>\/[^*\n]             ; /* To catch comments */
571 <pp_stripe>[^\{\};\n#/]*        ; /* Ignore rest */
572
573 <pp_stripp>\(           stripplevel++;
574 <pp_stripp>\)           {
575                                 stripplevel--;
576                                 if(!stripplevel)
577                                 {
578                                         pop_start();
579                                         push_to(pp_stripp_final);
580                                 }
581                         }
582 <pp_stripp>\/[^*\n]             ; /* To catch comments */
583 <pp_stripp>[^\(\);\n#/]*        ; /* Ignore rest */
584
585 <pp_stripp_final>{ws}*  ; /* Ignore */
586 <pp_stripp_final>;      pop_start(); /* Kill the semicolon */
587 <pp_stripp_final>\n     line_number++; char_number = 1; pop_start();
588 <pp_stripp_final>.      yyless(0); pop_start();
589
590 <pp_false>.             ;       /* Ignore everything except #xxx during false #if state */
591
592 <pp_ignore_eol>[^\n]*   pop_start();
593
594  /* These are special cases due to filename scanning */
595 <yywf>[Dd][Ii][Ss][Cc][Aa][Rr][Dd][Aa][Bb][Ll][Ee]      return DISCARDABLE;
596 <yywf>[Ff][Ii][Xx][Ee][Dd]                              return tFIXED;
597 <yywf>[Ii][Mm][Pp][Uu][Rr][Ee]                          return IMPURE;
598 <yywf>[Mm][Oo][Vv][Ee][Aa][Bb][Ll][Ee]                  return MOVEABLE;
599 <yywf>[Ll][Oo][Aa][Dd][Oo][Nn][Cc][Aa][Ll][Ll]          return LOADONCALL;
600 <yywf>[Pp][Rr][Ee][Ll][Oo][Aa][Dd]                      return PRELOAD;
601 <yywf>[Pp][Uu][Rr][Ee]                                  return tPURE;
602
603 \{                      return tBEGIN;
604 \}                      return tEND;
605
606 [0-9]+[lL]?             { yylval.num = strtoul(yytext,  0, 10); return toupper(yytext[yyleng-1]) == 'L' ? LNUMBER : NUMBER; }
607 0[xX][0-9A-Fa-f]+[lL]?  { yylval.num = strtoul(yytext,  0, 16); return toupper(yytext[yyleng-1]) == 'L' ? LNUMBER : NUMBER; }
608 0[oO][0-7]+[lL]?        { yylval.num = strtoul(yytext+2, 0, 8); return toupper(yytext[yyleng-1]) == 'L' ? LNUMBER : NUMBER; }
609 [A-Za-z_0-9]+           {
610                                 struct keyword *token;
611                                 struct pp_entry *ppp;
612
613                                 want_rscname = 0;
614                                 
615                                 if(want_ident)
616                                 {
617                                         /* Prevent preprocessor subst */
618                                         want_ident = 0;
619                                         yylval.str = make_string(yytext);
620                                 #ifdef LEX_DEBUG
621                                         printf("want IDENT (%s, %d, %d): <%s>\n", input_name, line_number, char_number, yytext);
622                                 #endif
623                                         return IDENT;
624                                 }
625                                 else if((ppp = pp_lookup(yytext)) != NULL)
626                                 {
627                                         /* Do preprocessor substitution,
628                                          * but expand only if macro is not
629                                          * already expanding.
630                                          */
631                                         if(!ppp->expanding)
632                                         {
633                                 #ifdef LEX_DEBUG
634                                                 printf("expand IDENT (%s, %d, %d): <%s>\n", input_name, line_number, char_number, yytext);
635                                 #endif
636                                                 push_buffer(YY_CURRENT_BUFFER, ppp, NULL);
637                                                 yy_scan_string(ppp->subst);
638                                         }
639                                 }
640                                 else if((token = iskeyword(yytext)) != NULL
641                                   && !(!token->alwayskeyword && want_rscname))
642                                 {
643                                         switch(token->token)
644                                         {
645                                         case tDEFINED:
646                                                 want_ident = 1;
647                                                 break;
648                                         /*case RCDATA:*/
649                                         case CURSOR:
650                                         case tBITMAP:
651                                         case MESSAGETABLE:
652                                         case DLGINIT:
653                                                 push_to(yywf);
654                                                 break;
655                                         case FONT:
656                                         case ICON:
657                                                 if(!indialog)
658                                                         push_to(yywf);
659                                                 break;
660                                         case DIALOG:
661                                         case DIALOGEX:
662                                                 indialog = 1;
663                                                 break;
664                                         }
665                                         return token->token;
666                                 }
667                                 else
668                                 {
669                                         yylval.str = make_string(yytext);
670                                 #ifdef LEX_DEBUG
671                                         printf("%s IDENT (%s, %d, %d): <%s>\n",
672                                                 want_rscname ? "rscname" : "just",
673                                                 input_name,
674                                                 line_number,
675                                                 char_number,
676                                                 yytext);
677                                 #endif
678                                         return IDENT;
679                                 }
680                         }
681 \|\|                    return LOGOR;
682 \&\&                    return LOGAND;
683 \=\=                    return EQ;
684 \!\=                    return NE;
685 \<\=                    return LTE;
686 \>\=                    return GTE;
687
688 <yywf>[^ \f\t\r\n\"]*   { pop_start(); yylval.str = make_filename(yytext, yyleng); return FILENAME; }
689 <yywf>\"                push_to(yywf_s);
690 <yywf_s>[^\"\n]*\"      { pop_start(); pop_start(); yylval.str = make_filename(yytext, yyleng-1); return FILENAME; }
691 <yywf_s>\n              yyerror("Newline in filename");
692
693 L\"                     {
694                                 push_to(yylstr);
695                                 wbufidx = 0;
696                                 if(!win32)
697                                         yywarning("16bit resource contains unicode strings\n");
698                         }
699 <yylstr>\"              {
700                                 pop_start();
701                                 yylval.str = get_buffered_wstring();
702                                 return tSTRING;
703                         }
704 <yylstr>\n              yyerror("Unterminated string");
705 <yylstr>\\[0-7]{1,6}    { /* octal escape sequence */
706                                 int result;
707                                 result = strtol(yytext+1, 0, 8);
708                                 if ( result > 0xffff )
709                                         yyerror("Character constant out of range");
710                                 addwchar((short)result);
711                         }
712 <yylstr>\\x[0-9a-fA-F]{4} {  /* hex escape sequence */
713                                 int result;
714                                 result = strtol(yytext+2, 0, 16);
715                                 addwchar((short)result);
716                         }
717 <yylstr>\\[0-9]+        yyerror("Bad escape secuence");
718 <yylstr>\\a             addwchar('\a');
719 <yylstr>\\b             addwchar('\b');
720 <yylstr>\\f             addwchar('\f');
721 <yylstr>\\n             addwchar('\n');
722 <yylstr>\\r             addwchar('\r');
723 <yylstr>\\t             addwchar('\t');
724 <yylstr>\\v             addwchar('\v');
725 <yylstr>\\(.|\n)        addwchar(yytext[1]);
726 <yylstr>\"\"            addcchar('\"');         /* "bla""bla"  -> "bla\"bla" */
727 <yylstr>\\\"\"          addcchar('\"');         /* "bla\""bla" -> "bla\"bla" */
728 <yylstr>\"{ws}+\"       ;                       /* "bla" "bla" -> "blabla" */
729 <yylstr>[^\\\n\"]+      {
730                                 char *yptr = yytext;
731                                 while(*yptr)    /* FIXME: codepage translation */
732                                         addwchar(*yptr++ & 0xff);
733                         }
734
735 \"                      {
736                                 push_to(yystr);
737                                 cbufidx = 0;
738                         }
739 <yystr>\"               {
740                                 pop_start();
741                                 yylval.str = get_buffered_cstring();
742                                 return tSTRING;
743                         }
744 <yystr>\n               yyerror("Unterminated string");
745 <yystr>\\[0-7]{1,3}     { /* octal escape sequence */
746                                 int result;
747                                 result = strtol(yytext+1, 0, 8);
748                                 if ( result > 0xff )
749                                         yyerror("Character constant out of range");
750                                 addcchar((char)result);
751                         }
752 <yystr>\\x[0-9a-fA-F]{2} {  /* hex escape sequence */
753                                 int result;
754                                 result = strtol(yytext+2, 0, 16);
755                                 addcchar((char)result);
756                         }
757 <yystr>\\[0-9]+         yyerror("Bad escape secuence");
758 <yystr>\\a              addcchar('\a');
759 <yystr>\\b              addcchar('\b');
760 <yystr>\\f              addcchar('\f');
761 <yystr>\\n              addcchar('\n');
762 <yystr>\\r              addcchar('\r');
763 <yystr>\\t              addcchar('\t');
764 <yystr>\\v              addcchar('\v');
765 <yystr>\\(.|\n)         addcchar(yytext[1]);
766 <yystr>[^\\\n\"]+       {
767                                 char *yptr = yytext;
768                                 while(*yptr)
769                                         addcchar(*yptr++);
770                         }
771 <yystr>\"\"             addcchar('\"');         /* "bla""bla"   -> "bla\"bla" */
772 <yystr>\\\"\"           addcchar('\"');         /* "bla\""bla"  -> "bla\"bla" */
773 <yystr>\"{ws}+\"        ;                       /* "bla" "bla"  -> "blabla" */
774 <yystr>.                yywarning("Matched %c", *yytext);
775
776
777 \'                      {
778                                 push_to(yyrcd);
779                                 cbufidx = 0;
780                         }
781 <yyrcd>\'               {
782                                 pop_start();
783                                 yylval.raw = new_raw_data();
784                                 yylval.raw->size = cbufidx;
785                                 yylval.raw->data = xmalloc(yylval.raw->size);
786                                 memcpy(yylval.raw->data, cbuffer, yylval.raw->size);
787                                 return RAWDATA;
788                         }
789 <yyrcd>[0-9a-fA-F]{2}   {
790                                 int result;
791                                 result = strtol(yytext, 0, 16);
792                                 addcchar((char)result);
793                         }
794 <yyrcd>{ws}+            ;       /* Ignore space */
795 <yyrcd>\n               line_number++; char_number = 1;
796 <yyrcd>.                yyerror("Malformed data-line");
797
798 <INITIAL,pp_ignore,pp_def_s,pp_strips,pp_stripe,pp_stripp>"/*"  push_to(comment);       /* Eat comment */
799 <comment>[^*\n]*        ;
800 <comment>"*"+[^*/\n]*   ;
801 <comment>\n             line_number++; char_number = 1;
802 <comment>"*"+"/"        pop_start();
803
804 ;[^\n]*                 ; /* Eat comment */
805 <INITIAL,pp_ignore,pp_def_s>"//"[^\n]*          ; /* Eat comment */
806
807 <INITIAL,yywf,pp_false,pp_strips,pp_stripe,pp_stripp>\n {
808                                 if(YY_START == yywf)
809                                         pop_start();
810                                 line_number++;
811                                 char_number = 1;
812                                 if(want_nl)
813                                 {
814                                         want_nl = 0;
815                                         return tNL;
816                                 }
817                         }
818 <INITIAL,yywf>{ws}+     ;       /* Eat whitespace */
819
820 <INITIAL>.              return yytext[0];
821 <<EOF>>                 {
822                                 YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
823                                 if(!pop_buffer())
824                                 {
825                                         if(YY_START == pp_strips || YY_START == pp_stripe || YY_START == pp_stripp || YY_START == pp_stripp_final)
826                                                 yyerror("Unexpected end of file during c-junk scanning (started at %d)", cjunk_tagline);
827                                         else
828                                                 yyterminate();
829                                 }
830                                 yy_delete_buffer(b);
831                         }
832
833 <*>.|\n                 {
834                                 /* Catch all rule to find any unmatched text */
835                                 if(*yytext == '\n')
836                                 {
837                                         line_number++;
838                                         char_number = 1;
839                                 }
840                                 yywarning("Unmatched text '%c' (0x%02x) YY_START=%d stripslevel=%d",
841                                         isprint(*yytext) ? *yytext : '.', *yytext, YY_START,stripslevel);
842                         }
843
844 %%
845
846 #ifndef yywrap
847 int yywrap(void)
848 {
849 #if 0
850         if(bufferstackidx > 0)
851         {
852                 return 0;
853         }
854 #endif
855         return 1;
856 }
857 #endif
858
859 /* These dup functions copy the enclosed '\0' from
860  * the resource string.
861  */
862 void addcchar(char c)
863 {
864         if(cbufidx >= cbufalloc)
865         {
866                 cbufalloc += 1024;
867                 cbuffer = xrealloc(cbuffer, cbufalloc * sizeof(cbuffer[0]));
868                 if(cbufalloc > 65536)
869                         yywarning("Reallocating string buffer larger than 64kB");
870         }
871         cbuffer[cbufidx++] = c;
872 }
873
874 void addwchar(short s)
875 {
876         if(wbufidx >= wbufalloc)
877         {
878                 wbufalloc += 1024;
879                 wbuffer = xrealloc(wbuffer, wbufalloc * sizeof(wbuffer[0]));
880                 if(wbufalloc > 65536)
881                         yywarning("Reallocating wide string buffer larger than 64kB");
882         }
883
884         /*
885          * BS 08-Aug-1999 FIXME: The '& 0xff' is probably a bug, but I have
886          * not experienced it yet and I seem to remember that this was for
887          * a reason. But, as so many things you tend to forget why.
888          * I guess that there were problems due to the sign extension of
889          * shorts WRT chars (e.g. 0x80 becomes 0xff80 instead of 0x0080).
890          * This should then be fixed in the lexer calling the function.
891          */
892         wbuffer[wbufidx++] = (short)(s & 0xff);
893 }
894
895 string_t *get_buffered_cstring(void)
896 {
897         string_t *str = new_string();
898         str->size = cbufidx;
899         str->type = str_char;
900         str->str.cstr = (char *)xmalloc(cbufidx+1);
901         memcpy(str->str.cstr, cbuffer, cbufidx);
902         str->str.cstr[cbufidx] = '\0';
903 /*      printf("got cstring \"%s\"\n", str->str.cstr); */
904         return str;
905 }
906
907 string_t *get_buffered_wstring(void)
908 {
909         string_t *str = new_string();
910         str->size = wbufidx;
911         str->type = str_unicode;
912         str->str.wstr = (short *)xmalloc(2*(wbufidx+1));
913         memcpy(str->str.wstr, wbuffer, wbufidx);
914         str->str.wstr[wbufidx] = 0;
915         return str;
916 }
917
918 string_t *make_string(char *s)
919 {
920         string_t *str = new_string();
921         str->size = strlen(s);
922         str->type = str_char;
923         str->str.cstr = (char *)xmalloc(str->size+1);
924         memcpy(str->str.cstr, s, str->size+1);
925         return str;
926 }
927
928 string_t *make_filename(char *s, int len)
929 {
930         char *cptr;
931         string_t *str = new_string();
932
933         str->size = len;
934         str->type = str_char;
935         str->str.cstr = (char *)xmalloc(str->size+1);
936         memcpy(str->str.cstr, s, str->size);
937         str->str.cstr[str->size] = '\0';
938
939         /* Remove escaped backslash and convert to forward */
940         cptr = str->str.cstr;
941         for(cptr = str->str.cstr; (cptr = strchr(cptr, '\\')) != NULL; cptr++)
942         {
943                 if(cptr[1] == '\\')
944                 {
945                         memmove(cptr, cptr+1, strlen(cptr));
946                         str->size--;
947                 }
948                 *cptr = '/';
949         }
950
951         /* Convert to lower case. Seems to be reasonable to do */
952         for(cptr = str->str.cstr; !leave_case && *cptr; cptr++)
953         {
954                 *cptr = tolower(*cptr);
955         }
956         return str;
957 }
958
959 /* Called from the parser to signal filename request */
960 void set_yywf(void)
961 {
962         push_to(yywf);
963 }
964
965 /* Called from the parser to signal preprocessor if case */
966 void set_pp_ignore(int state)
967 {
968         if(state)
969                 push_to(pp_false);
970         else
971                 pop_start();
972 }
973
974 /* Called from the parser to kill c-junk */
975 void strip_extern(void)
976 {
977         cjunk_tagline = line_number;
978         push_to(pp_stripe);
979 }
980
981 void strip_til_semicolon(void)
982 {
983         cjunk_tagline = line_number;
984         push_to(pp_strips);
985 }
986
987 void strip_til_parenthesis(void)
988 {
989         cjunk_tagline = line_number;
990         stripplevel = 1;        /* One scanned already */
991         push_to(pp_stripp);
992 }
993