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