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