1 | /* -*-C-*-
|
---|
2 | *
|
---|
3 | * Copyright 1998-2000 Bertho A. Stultiens (BS)
|
---|
4 | *
|
---|
5 | * 21-May-2000 BS - Fixed the ident requirement of resource names
|
---|
6 | * which can be keywords.
|
---|
7 | * 30-Apr-2000 BS - Reintegration into the wine-tree
|
---|
8 | * 11-Jan-2000 BS - Very drastic cleanup because we don't have a
|
---|
9 | * preprocessor in here anymore.
|
---|
10 | * 02-Jan-2000 BS - Removed the preprocessor code
|
---|
11 | * 23-Dec-1999 BS - Removed the copyright for Martin von Loewis.
|
---|
12 | * There is really nothing left of his code in
|
---|
13 | * this parser.
|
---|
14 | * 20-Jun-1998 BS - Changed the filename conversion. Filenames are
|
---|
15 | * case-sensitive inder *nix, but not under dos.
|
---|
16 | * default behaviour is to convert to lower case.
|
---|
17 | * - All backslashes are converted to forward and
|
---|
18 | * both single and double slash is recognized as
|
---|
19 | * MS/Borland does.
|
---|
20 | * - Fixed a bug in 'yywf' case that prevented
|
---|
21 | * double quoted names to be scanned propperly.
|
---|
22 | *
|
---|
23 | * 19-May-1998 BS - Started to build a preprocessor.
|
---|
24 | * - Changed keyword processing completely to
|
---|
25 | * table-lookups.
|
---|
26 | *
|
---|
27 | * 20-Apr-1998 BS - Added ';' comment stripping
|
---|
28 | *
|
---|
29 | * 17-Apr-1998 BS - Made the win32 keywords optional when compiling in
|
---|
30 | * 16bit mode
|
---|
31 | *
|
---|
32 | * 15-Apr-1998 BS - Changed string handling to include escapes
|
---|
33 | * - Added unicode string handling (no codepage
|
---|
34 | * translation though).
|
---|
35 | * - 'Borrowed' the main idea of string scanning from
|
---|
36 | * the flex manual pages.
|
---|
37 | * - Added conditional handling of scanning depending
|
---|
38 | * on the state of the parser. This was mainly required
|
---|
39 | * to distinguish a file to load or raw data that
|
---|
40 | * follows. MS's definition of filenames is rather
|
---|
41 | * complex... It can be unquoted or double quoted. If
|
---|
42 | * double quoted, then the '\\' char is not automatically
|
---|
43 | * escaped according to Borland's rc compiler, but it
|
---|
44 | * accepts both "\\path\\file.rc" and "\path\file.rc".
|
---|
45 | * This makes life very hard! I go for the escaped
|
---|
46 | * version, as this seems to be the documented way...
|
---|
47 | * - Single quoted strings are now parsed and converted
|
---|
48 | * here.
|
---|
49 | * - Added comment stripping. The implementation is
|
---|
50 | * 'borrowed' from the flex manpages.
|
---|
51 | * - Rebuild string processing so that it may contain
|
---|
52 | * escaped '\0'.
|
---|
53 | */
|
---|
54 |
|
---|
55 | /* Exclusive string handling */
|
---|
56 | %x yystr
|
---|
57 | /* Exclusive unicode string handling */
|
---|
58 | %x yylstr
|
---|
59 | /* Exclusive rcdata single quoted data handling */
|
---|
60 | %x yyrcd
|
---|
61 | /* Exclusive comment eating... */
|
---|
62 | %x comment
|
---|
63 | /* Set when stripping c-junk */
|
---|
64 | %x pp_stripe
|
---|
65 | %x pp_strips
|
---|
66 | %x pp_stripp
|
---|
67 | %x pp_stripp_final
|
---|
68 | /* Set when scanning #line style directives */
|
---|
69 | %x pp_line
|
---|
70 |
|
---|
71 | %option stack
|
---|
72 | %option never-interactive
|
---|
73 |
|
---|
74 | /* Some shortcut definitions */
|
---|
75 | ws [ \f\t\r]
|
---|
76 | cident [a-zA-Z_][0-9a-zA-Z_]*
|
---|
77 |
|
---|
78 | %{
|
---|
79 |
|
---|
80 | /*#define LEX_DEBUG*/
|
---|
81 |
|
---|
82 | #include "config.h"
|
---|
83 |
|
---|
84 | #include <stdio.h>
|
---|
85 | #include <stdlib.h>
|
---|
86 | #include <string.h>
|
---|
87 | #include <ctype.h>
|
---|
88 | #include <assert.h>
|
---|
89 |
|
---|
90 | #include "wrc.h"
|
---|
91 | #include "utils.h"
|
---|
92 | #include "preproc.h"
|
---|
93 | #include "parser.h"
|
---|
94 | #include "newstruc.h"
|
---|
95 |
|
---|
96 | #include "y.tab.h"
|
---|
97 |
|
---|
98 | #define YY_USE_PROTOS
|
---|
99 | #define YY_NO_UNPUT
|
---|
100 | #define YY_NO_TOP_STATE
|
---|
101 |
|
---|
102 | /* Always update the current character position within a line */
|
---|
103 | #define YY_USER_ACTION char_number+=yyleng; wanted_id = want_id; want_id = 0;
|
---|
104 |
|
---|
105 | static void addcchar(char c);
|
---|
106 | static void addwchar(short s);
|
---|
107 | static string_t *get_buffered_cstring(void);
|
---|
108 | static string_t *get_buffered_wstring(void);
|
---|
109 | static string_t *make_string(char *s);
|
---|
110 |
|
---|
111 | static char *cbuffer; /* Buffers for string collection */
|
---|
112 | static int cbufidx;
|
---|
113 | static int cbufalloc = 0;
|
---|
114 | static short *wbuffer;
|
---|
115 | static int wbufidx;
|
---|
116 | static int wbufalloc = 0;
|
---|
117 | static int stripslevel = 0; /* Count {} during pp_strips/pp_stripe mode */
|
---|
118 | static int stripplevel = 0; /* Count () during pp_strips mode */
|
---|
119 | static int cjunk_tagline; /* Where did we start stripping (helps error tracking) */
|
---|
120 |
|
---|
121 | /*
|
---|
122 | * This one is a bit tricky.
|
---|
123 | * We set 'want_id' in the parser to get the first
|
---|
124 | * identifier we get across in the scanner, but we
|
---|
125 | * also want it to be reset at nearly any token we
|
---|
126 | * see. Exceptions are:
|
---|
127 | * - newlines
|
---|
128 | * - comments
|
---|
129 | * - whitespace
|
---|
130 | *
|
---|
131 | * The scanner will automatically reset 'want_id'
|
---|
132 | * after *each* scanner reduction and puts is value
|
---|
133 | * into the var below. In this way we can see the
|
---|
134 | * state after the YY_RULE_SETUP (i.e. the user action;
|
---|
135 | * see above) and don't have to worry too much when
|
---|
136 | * it needs to be reset.
|
---|
137 | */
|
---|
138 | static int wanted_id = 0;
|
---|
139 | static int save_wanted_id; /* To save across comment reductions */
|
---|
140 |
|
---|
141 | struct keyword {
|
---|
142 | char *keyword;
|
---|
143 | int token;
|
---|
144 | int isextension;
|
---|
145 | int needcase;
|
---|
146 | int alwayskw;
|
---|
147 | };
|
---|
148 |
|
---|
149 | static struct keyword keywords[] = {
|
---|
150 | { "ACCELERATORS", tACCELERATORS, 0, 0, 0},
|
---|
151 | { "ALT", tALT, 0, 0, 0},
|
---|
152 | { "ASCII", tASCII, 0, 0, 0},
|
---|
153 | { "AUTO3STATE", tAUTO3STATE, 1, 0, 0},
|
---|
154 | { "AUTOCHECKBOX", tAUTOCHECKBOX, 1, 0, 0},
|
---|
155 | { "AUTORADIOBUTTON", tAUTORADIOBUTTON, 1, 0, 0},
|
---|
156 | { "BEGIN", tBEGIN, 0, 0, 0},
|
---|
157 | { "BITMAP", tBITMAP, 0, 0, 0},
|
---|
158 | { "BLOCK", tBLOCK, 0, 0, 0},
|
---|
159 | { "BUTTON", tBUTTON, 1, 0, 0},
|
---|
160 | { "CAPTION", tCAPTION, 0, 0, 0},
|
---|
161 | { "CHARACTERISTICS", tCHARACTERISTICS, 1, 0, 0},
|
---|
162 | { "CHECKBOX", tCHECKBOX, 0, 0, 0},
|
---|
163 | { "CHECKED", tCHECKED, 0, 0, 0},
|
---|
164 | { "CLASS", tCLASS, 0, 0, 0},
|
---|
165 | { "COMBOBOX", tCOMBOBOX, 0, 0, 0},
|
---|
166 | { "CONTROL", tCONTROL, 0, 0, 0},
|
---|
167 | { "CTEXT", tCTEXT, 0, 0, 0},
|
---|
168 | { "CURSOR", tCURSOR, 0, 0, 0},
|
---|
169 | { "DEFPUSHBUTTON", tDEFPUSHBUTTON, 0, 0, 0},
|
---|
170 | { "DIALOG", tDIALOG, 0, 0, 0},
|
---|
171 | { "DIALOGEX", tDIALOGEX, 1, 0, 0},
|
---|
172 | { "DISCARDABLE", tDISCARDABLE, 0, 0, 0},
|
---|
173 | { "DLGINIT", tDLGINIT, 0, 0, 0},
|
---|
174 | { "EDITTEXT", tEDITTEXT, 0, 0, 0},
|
---|
175 | { "END", tEND, 0, 0, 0},
|
---|
176 | { "enum", tENUM, 0, 1, 1},
|
---|
177 | { "EXSTYLE", tEXSTYLE, 0, 0, 0},
|
---|
178 | { "extern", tEXTERN, 0, 1, 1},
|
---|
179 | { "FILEFLAGS", tFILEFLAGS, 0, 0, 0},
|
---|
180 | { "FILEFLAGSMASK", tFILEFLAGSMASK, 0, 0, 0},
|
---|
181 | { "FILEOS", tFILEOS, 0, 0, 0},
|
---|
182 | { "FILESUBTYPE", tFILESUBTYPE, 0, 0, 0},
|
---|
183 | { "FILETYPE", tFILETYPE, 0, 0, 0},
|
---|
184 | { "FILEVERSION", tFILEVERSION, 0, 0, 0},
|
---|
185 | { "FIXED", tFIXED, 0, 0, 0},
|
---|
186 | { "FONT", tFONT, 0, 0, 0},
|
---|
187 | { "FONTDIR", tFONTDIR, 0, 0, 0}, /* This is a Borland BRC extension */
|
---|
188 | { "GRAYED", tGRAYED, 0, 0, 0},
|
---|
189 | { "GROUPBOX", tGROUPBOX, 0, 0, 0},
|
---|
190 | { "HELP", tHELP, 0, 0, 0},
|
---|
191 | { "ICON", tICON, 0, 0, 0},
|
---|
192 | { "IMPURE", tIMPURE, 0, 0, 0},
|
---|
193 | { "INACTIVE", tINACTIVE, 0, 0, 0},
|
---|
194 | { "inline", tINLINE, 0, 1, 1},
|
---|
195 | { "LANGUAGE", tLANGUAGE, 1, 0, 1},
|
---|
196 | { "LISTBOX", tLISTBOX, 0, 0, 0},
|
---|
197 | { "LOADONCALL", tLOADONCALL, 0, 0, 0},
|
---|
198 | { "LTEXT", tLTEXT, 0, 0, 0},
|
---|
199 | { "MENU", tMENU, 0, 0, 0},
|
---|
200 | { "MENUBARBREAK", tMENUBARBREAK, 0, 0, 0},
|
---|
201 | { "MENUBREAK", tMENUBREAK, 0, 0, 0},
|
---|
202 | { "MENUEX", tMENUEX, 1, 0, 0},
|
---|
203 | { "MENUITEM", tMENUITEM, 0, 0, 0},
|
---|
204 | { "MESSAGETABLE", tMESSAGETABLE, 1, 0, 0},
|
---|
205 | { "MOVEABLE", tMOVEABLE, 0, 0, 0},
|
---|
206 | { "NOINVERT", tNOINVERT, 0, 0, 0},
|
---|
207 | { "NOT", tNOT, 0, 0, 0},
|
---|
208 | { "POPUP", tPOPUP, 0, 0, 0},
|
---|
209 | { "PRELOAD", tPRELOAD, 0, 0, 0},
|
---|
210 | { "PRODUCTVERSION", tPRODUCTVERSION, 0, 0, 0},
|
---|
211 | { "PURE", tPURE, 0, 0, 0},
|
---|
212 | { "PUSHBUTTON", tPUSHBUTTON, 0, 0, 0},
|
---|
213 | { "RADIOBUTTON", tRADIOBUTTON, 0, 0, 0},
|
---|
214 | { "RCDATA", tRCDATA, 0, 0, 0},
|
---|
215 | { "RTEXT", tRTEXT, 0, 0, 0},
|
---|
216 | { "SCROLLBAR", tSCROLLBAR, 0, 0, 0},
|
---|
217 | { "SEPARATOR", tSEPARATOR, 0, 0, 0},
|
---|
218 | { "SHIFT", tSHIFT, 0, 0, 0},
|
---|
219 | { "STATE3", tSTATE3, 1, 0, 0},
|
---|
220 | { "static", tSTATIC, 0, 1, 1},
|
---|
221 | { "STRING", tSTRING, 0, 0, 0},
|
---|
222 | { "STRINGTABLE", tSTRINGTABLE, 0, 0, 1},
|
---|
223 | { "struct", tSTRUCT, 0, 1, 1},
|
---|
224 | { "STYLE", tSTYLE, 0, 0, 0},
|
---|
225 | { "TOOLBAR", tTOOLBAR, 1, 0, 0},
|
---|
226 | { "typedef", tTYPEDEF, 0, 1, 1},
|
---|
227 | { "VALUE", tVALUE, 0, 0, 0},
|
---|
228 | { "VERSION", tVERSION, 1, 0, 0},
|
---|
229 | { "VERSIONINFO", tVERSIONINFO, 0, 0, 0},
|
---|
230 | { "VIRTKEY", tVIRTKEY, 0, 0, 0}
|
---|
231 | };
|
---|
232 |
|
---|
233 | #define NKEYWORDS (sizeof(keywords)/sizeof(keywords[0]))
|
---|
234 | #define KWP(p) ((struct keyword *)(p))
|
---|
235 | static int kw_cmp_func(const void *s1, const void *s2)
|
---|
236 | {
|
---|
237 | int ret;
|
---|
238 | ret = strcasecmp(KWP(s1)->keyword, KWP(s2)->keyword);
|
---|
239 | if(!ret && (KWP(s1)->needcase || KWP(s2)->needcase))
|
---|
240 | return strcmp(KWP(s1)->keyword, KWP(s2)->keyword);
|
---|
241 | else
|
---|
242 | return ret;
|
---|
243 | }
|
---|
244 |
|
---|
245 | #define KW_BSEARCH
|
---|
246 | #define DO_SORT
|
---|
247 | static struct keyword *iskeyword(char *kw)
|
---|
248 | {
|
---|
249 | struct keyword *kwp;
|
---|
250 | struct keyword key;
|
---|
251 | key.keyword = kw;
|
---|
252 | key.needcase = 0;
|
---|
253 | #ifdef DO_SORT
|
---|
254 | {
|
---|
255 | /* Make sure that it is sorted for bsearsh */
|
---|
256 | static int sorted = 0;
|
---|
257 | if(!sorted)
|
---|
258 | {
|
---|
259 | qsort(keywords, NKEYWORDS, sizeof(keywords[0]), kw_cmp_func);
|
---|
260 | sorted = 1;
|
---|
261 | }
|
---|
262 | }
|
---|
263 | #endif
|
---|
264 | #ifdef KW_BSEARCH
|
---|
265 | kwp = bsearch(&key, keywords, NKEYWORDS, sizeof(keywords[0]), kw_cmp_func);
|
---|
266 | #else
|
---|
267 | {
|
---|
268 | int i;
|
---|
269 | for(i = 0; i < NKEYWORDS; i++)
|
---|
270 | {
|
---|
271 | if(!kw_cmp_func(&key, &keywords[i]))
|
---|
272 | break;
|
---|
273 | }
|
---|
274 | if(i < NKEYWORDS)
|
---|
275 | kwp = &keywords[i];
|
---|
276 | else
|
---|
277 | kwp = NULL;
|
---|
278 | }
|
---|
279 | #endif
|
---|
280 |
|
---|
281 | if(kwp == NULL || (kwp->isextension && !extensions))
|
---|
282 | return NULL;
|
---|
283 | else
|
---|
284 | return kwp;
|
---|
285 | }
|
---|
286 |
|
---|
287 | %}
|
---|
288 |
|
---|
289 | /*
|
---|
290 | **************************************************************************
|
---|
291 | * The flexer starts here
|
---|
292 | **************************************************************************
|
---|
293 | */
|
---|
294 | %%
|
---|
295 | /*
|
---|
296 | * Catch the GCC-style line statements here and parse them.
|
---|
297 | * This has the advantage that you can #include at any
|
---|
298 | * stage in the resource file.
|
---|
299 | * The preprocessor generates line directives in the format:
|
---|
300 | * # <linenum> "filename" <codes>
|
---|
301 | *
|
---|
302 | * Codes can be a sequence of:
|
---|
303 | * - 1 start of new file
|
---|
304 | * - 2 returning to previous
|
---|
305 | * - 3 system header
|
---|
306 | * - 4 interpret as C-code
|
---|
307 | *
|
---|
308 | * 4 is not used and 1 mutually excludes 2
|
---|
309 | * Anyhow, we are not really interested in these at all
|
---|
310 | * because we only want to know the linenumber and
|
---|
311 | * filename.
|
---|
312 | */
|
---|
313 | <INITIAL,pp_strips,pp_stripp>^{ws}*\#{ws}* yy_push_state(pp_line);
|
---|
314 | <pp_line>[^\n]* {
|
---|
315 | int lineno;
|
---|
316 | char *cptr;
|
---|
317 | char *fname;
|
---|
318 | yy_pop_state();
|
---|
319 | lineno = (int)strtol(yytext, &cptr, 10);
|
---|
320 | if(!lineno)
|
---|
321 | yyerror("Malformed '#...' line-directive; invalid linenumber");
|
---|
322 | fname = strchr(cptr, '"');
|
---|
323 | if(!fname)
|
---|
324 | yyerror("Malformed '#...' line-directive; missing filename");
|
---|
325 | fname++;
|
---|
326 | cptr = strchr(fname, '"');
|
---|
327 | if(!cptr)
|
---|
328 | yyerror("Malformed '#...' line-directive; missing terminating \"");
|
---|
329 | *cptr = '\0';
|
---|
330 | line_number = lineno - 1; /* We didn't read the newline */
|
---|
331 | input_name = xstrdup(fname);
|
---|
332 | }
|
---|
333 |
|
---|
334 | /*
|
---|
335 | * Strip everything until a ';' taking
|
---|
336 | * into account braces {} for structures,
|
---|
337 | * classes and enums.
|
---|
338 | */
|
---|
339 | <pp_strips>\{ stripslevel++;
|
---|
340 | <pp_strips>\} stripslevel--;
|
---|
341 | <pp_strips>; if(!stripslevel) yy_pop_state();
|
---|
342 | <pp_strips>\/[^*\n] ; /* To catch comments */
|
---|
343 | <pp_strips>[^\{\};\n#/]* ; /* Ignore rest */
|
---|
344 | <pp_strips>\n line_number++; char_number = 1;
|
---|
345 |
|
---|
346 | <pp_stripp>\( stripplevel++;
|
---|
347 | <pp_stripp>\) {
|
---|
348 | stripplevel--;
|
---|
349 | if(!stripplevel)
|
---|
350 | {
|
---|
351 | yy_pop_state();
|
---|
352 | yy_push_state(pp_stripp_final);
|
---|
353 | }
|
---|
354 | }
|
---|
355 | <pp_stripp>\/[^*\n] ; /* To catch comments */
|
---|
356 | <pp_stripp>[^\(\);\n#/]* ; /* Ignore rest */
|
---|
357 | <pp_stripp>\n line_number++; char_number = 1;
|
---|
358 |
|
---|
359 | <pp_stripp_final>{ws}* ; /* Ignore */
|
---|
360 | <pp_stripp_final>; yy_pop_state(); /* Kill the semicolon */
|
---|
361 | <pp_stripp_final>\n line_number++; char_number = 1; yy_pop_state();
|
---|
362 | <pp_stripp_final>. yyless(0); yy_pop_state();
|
---|
363 |
|
---|
364 | \{ return tBEGIN;
|
---|
365 | \} return tEND;
|
---|
366 |
|
---|
367 | [0-9]+[lL]? { yylval.num = strtoul(yytext, 0, 10); return toupper(yytext[yyleng-1]) == 'L' ? tLNUMBER : tNUMBER; }
|
---|
368 | 0[xX][0-9A-Fa-f]+[lL]? { yylval.num = strtoul(yytext, 0, 16); return toupper(yytext[yyleng-1]) == 'L' ? tLNUMBER : tNUMBER; }
|
---|
369 | 0[oO][0-7]+[lL]? { yylval.num = strtoul(yytext+2, 0, 8); return toupper(yytext[yyleng-1]) == 'L' ? tLNUMBER : tNUMBER; }
|
---|
370 |
|
---|
371 | /*
|
---|
372 | * The next two rules scan identifiers and filenames.
|
---|
373 | * This is achieved by using the priority ruling
|
---|
374 | * of the scanner where a '.' is valid in a filename
|
---|
375 | * and *only* in a filename. In this case, the second
|
---|
376 | * rule will be reduced because it is longer.
|
---|
377 | */
|
---|
378 | [A-Za-z_0-9]+ {
|
---|
379 | struct keyword *tok = iskeyword(yytext);
|
---|
380 |
|
---|
381 | if(tok)
|
---|
382 | {
|
---|
383 | if(tok->token == tCLASS && !strcmp(yytext, "class"))
|
---|
384 | return tCPPCLASS;
|
---|
385 | else if(wanted_id && !tok->alwayskw)
|
---|
386 | {
|
---|
387 | yylval.str = make_string(yytext);
|
---|
388 | return tIDENT;
|
---|
389 | }
|
---|
390 | else
|
---|
391 | return tok->token;
|
---|
392 | }
|
---|
393 | else
|
---|
394 | {
|
---|
395 | yylval.str = make_string(yytext);
|
---|
396 | return tIDENT;
|
---|
397 | }
|
---|
398 | }
|
---|
399 | [A-Za-z_0-9./\\]+ yylval.str = make_string(yytext); return tFILENAME;
|
---|
400 |
|
---|
401 | /*
|
---|
402 | * Wide string scanning
|
---|
403 | */
|
---|
404 | L\" {
|
---|
405 | yy_push_state(yylstr);
|
---|
406 | wbufidx = 0;
|
---|
407 | if(!win32)
|
---|
408 | yywarning("16bit resource contains unicode strings\n");
|
---|
409 | }
|
---|
410 | <yylstr>\"{ws}+ |
|
---|
411 | <yylstr>\" {
|
---|
412 | yy_pop_state();
|
---|
413 | yylval.str = get_buffered_wstring();
|
---|
414 | return tSTRING;
|
---|
415 | }
|
---|
416 | <yylstr>\\[0-7]{1,6} { /* octal escape sequence */
|
---|
417 | int result;
|
---|
418 | result = strtol(yytext+1, 0, 8);
|
---|
419 | if ( result > 0xffff )
|
---|
420 | yyerror("Character constant out of range");
|
---|
421 | addwchar((short)result);
|
---|
422 | }
|
---|
423 | <yylstr>\\x[0-9a-fA-F]{4} { /* hex escape sequence */
|
---|
424 | int result;
|
---|
425 | result = strtol(yytext+2, 0, 16);
|
---|
426 | addwchar((short)result);
|
---|
427 | }
|
---|
428 | <yylstr>\\x[0-9a-fA-F]{1,3} { yyerror("Invalid hex escape sequence '%s'", yytext); }
|
---|
429 |
|
---|
430 | <yylstr>\\[0-9]+ yyerror("Bad escape secuence");
|
---|
431 | <yylstr>\\a addwchar('\a');
|
---|
432 | <yylstr>\\b addwchar('\b');
|
---|
433 | <yylstr>\\f addwchar('\f');
|
---|
434 | <yylstr>\\n addwchar('\n');
|
---|
435 | <yylstr>\\r addwchar('\r');
|
---|
436 | <yylstr>\\t addwchar('\t');
|
---|
437 | <yylstr>\\v addwchar('\v');
|
---|
438 | <yylstr>\\(\n|.) addwchar(yytext[1]);
|
---|
439 | <yylstr>\\\r\n addwchar(yytext[2]);
|
---|
440 | <yylstr>\"\" addcchar('\"'); /* "bla""bla" -> "bla\"bla" */
|
---|
441 | <yylstr>\\\"\" addcchar('\"'); /* "bla\""bla" -> "bla\"bla" */
|
---|
442 | <yylstr>\"{ws}+\" ; /* "bla" "bla" -> "blabla" */
|
---|
443 | <yylstr>[^\\\n\"]+ {
|
---|
444 | char *yptr = yytext;
|
---|
445 | while(*yptr) /* FIXME: codepage translation */
|
---|
446 | addwchar(*yptr++ & 0xff);
|
---|
447 | }
|
---|
448 | <yylstr>\n yyerror("Unterminated string");
|
---|
449 |
|
---|
450 | /*
|
---|
451 | * Normal string scanning
|
---|
452 | */
|
---|
453 | \" yy_push_state(yystr); cbufidx = 0;
|
---|
454 | <yystr>\"{ws}+ |
|
---|
455 | <yystr>\" {
|
---|
456 | yy_pop_state();
|
---|
457 | yylval.str = get_buffered_cstring();
|
---|
458 | return tSTRING;
|
---|
459 | }
|
---|
460 | <yystr>\\[0-7]{1,3} { /* octal escape sequence */
|
---|
461 | int result;
|
---|
462 | result = strtol(yytext+1, 0, 8);
|
---|
463 | if ( result > 0xff )
|
---|
464 | yyerror("Character constant out of range");
|
---|
465 | addcchar((char)result);
|
---|
466 | }
|
---|
467 | <yystr>\\x[0-9a-fA-F]{2} { /* hex escape sequence */
|
---|
468 | int result;
|
---|
469 | result = strtol(yytext+2, 0, 16);
|
---|
470 | addcchar((char)result);
|
---|
471 | }
|
---|
472 | <yystr>\\x[0-9a-fA-F] { yyerror("Invalid hex escape sequence '%s'", yytext); }
|
---|
473 |
|
---|
474 | <yystr>\\[0-9]+ yyerror("Bad escape secuence");
|
---|
475 | <yystr>\\a addcchar('\a');
|
---|
476 | <yystr>\\b addcchar('\b');
|
---|
477 | <yystr>\\f addcchar('\f');
|
---|
478 | <yystr>\\n addcchar('\n');
|
---|
479 | <yystr>\\r addcchar('\r');
|
---|
480 | <yystr>\\t addcchar('\t');
|
---|
481 | <yystr>\\v addcchar('\v');
|
---|
482 | <yystr>\\(\n|.) addcchar(yytext[1]);
|
---|
483 | <yystr>\\\r\n addcchar(yytext[2]);
|
---|
484 | <yystr>[^\\\n\"]+ {
|
---|
485 | char *yptr = yytext;
|
---|
486 | while(*yptr)
|
---|
487 | addcchar(*yptr++);
|
---|
488 | }
|
---|
489 | <yystr>\"\" addcchar('\"'); /* "bla""bla" -> "bla\"bla" */
|
---|
490 | <yystr>\\\"\" addcchar('\"'); /* "bla\""bla" -> "bla\"bla" */
|
---|
491 | <yystr>\"{ws}+\" ; /* "bla" "bla" -> "blabla" */
|
---|
492 | <yystr>\n yyerror("Unterminated string");
|
---|
493 |
|
---|
494 | /*
|
---|
495 | * Raw data scanning
|
---|
496 | */
|
---|
497 | \' yy_push_state(yyrcd); cbufidx = 0;
|
---|
498 | <yyrcd>\' {
|
---|
499 | yy_pop_state();
|
---|
500 | yylval.raw = new_raw_data();
|
---|
501 | yylval.raw->size = cbufidx;
|
---|
502 | yylval.raw->data = xmalloc(yylval.raw->size);
|
---|
503 | memcpy(yylval.raw->data, cbuffer, yylval.raw->size);
|
---|
504 | return tRAWDATA;
|
---|
505 | }
|
---|
506 | <yyrcd>[0-9a-fA-F]{2} {
|
---|
507 | int result;
|
---|
508 | result = strtol(yytext, 0, 16);
|
---|
509 | addcchar((char)result);
|
---|
510 | }
|
---|
511 | <yyrcd>{ws}+ ; /* Ignore space */
|
---|
512 | <yyrcd>\n line_number++; char_number = 1;
|
---|
513 | <yyrcd>. yyerror("Malformed data-line");
|
---|
514 |
|
---|
515 | /*
|
---|
516 | * Comment stripping
|
---|
517 | * Should never occur after preprocessing
|
---|
518 | */
|
---|
519 | <INITIAL,pp_stripp,pp_strips>"/*" {
|
---|
520 | yy_push_state(comment);
|
---|
521 | save_wanted_id = wanted_id;
|
---|
522 | if(!no_preprocess)
|
---|
523 | yywarning("Found comments after preprocessing, please report");
|
---|
524 | }
|
---|
525 | <comment>[^*\n]* ;
|
---|
526 | <comment>"*"+[^*/\n]* ;
|
---|
527 | <comment>\n line_number++; char_number = 1;
|
---|
528 | <comment>"*"+"/" yy_pop_state(); want_id = save_wanted_id;
|
---|
529 |
|
---|
530 | ;[^\n]* want_id = wanted_id; /* not really comment, but left-over c-junk */
|
---|
531 | "//"[^\n]* want_id = wanted_id; if(!no_preprocess) yywarning("Found comments after preprocessing, please report");
|
---|
532 |
|
---|
533 | \n {
|
---|
534 | want_id = wanted_id;
|
---|
535 | line_number++;
|
---|
536 | char_number = 1;
|
---|
537 | if(want_nl)
|
---|
538 | {
|
---|
539 | want_nl = 0;
|
---|
540 | return tNL;
|
---|
541 | }
|
---|
542 | }
|
---|
543 | {ws}+ want_id = wanted_id; /* Eat whitespace */
|
---|
544 |
|
---|
545 | <INITIAL>. return yytext[0];
|
---|
546 |
|
---|
547 | <<EOF>> {
|
---|
548 | if(YY_START == pp_strips || YY_START == pp_stripe || YY_START == pp_stripp || YY_START == pp_stripp_final)
|
---|
549 | yyerror("Unexpected end of file during c-junk scanning (started at %d)", cjunk_tagline);
|
---|
550 | else
|
---|
551 | yyterminate();
|
---|
552 | }
|
---|
553 |
|
---|
554 | <*>.|\n {
|
---|
555 | /* Catch all rule to find any unmatched text */
|
---|
556 | if(*yytext == '\n')
|
---|
557 | {
|
---|
558 | line_number++;
|
---|
559 | char_number = 1;
|
---|
560 | }
|
---|
561 | yywarning("Unmatched text '%c' (0x%02x) YY_START=%d stripslevel=%d",
|
---|
562 | isprint(*yytext & 0xff) ? *yytext : '.', *yytext, YY_START,stripslevel);
|
---|
563 | }
|
---|
564 |
|
---|
565 | %%
|
---|
566 |
|
---|
567 | #ifndef yywrap
|
---|
568 | int yywrap(void)
|
---|
569 | {
|
---|
570 | #if 0
|
---|
571 | if(bufferstackidx > 0)
|
---|
572 | {
|
---|
573 | return 0;
|
---|
574 | }
|
---|
575 | #endif
|
---|
576 | return 1;
|
---|
577 | }
|
---|
578 | #endif
|
---|
579 |
|
---|
580 | /* These dup functions copy the enclosed '\0' from
|
---|
581 | * the resource string.
|
---|
582 | */
|
---|
583 | static void addcchar(char c)
|
---|
584 | {
|
---|
585 | if(cbufidx >= cbufalloc)
|
---|
586 | {
|
---|
587 | cbufalloc += 1024;
|
---|
588 | cbuffer = xrealloc(cbuffer, cbufalloc * sizeof(cbuffer[0]));
|
---|
589 | if(cbufalloc > 65536)
|
---|
590 | yywarning("Reallocating string buffer larger than 64kB");
|
---|
591 | }
|
---|
592 | cbuffer[cbufidx++] = c;
|
---|
593 | }
|
---|
594 |
|
---|
595 | static void addwchar(short s)
|
---|
596 | {
|
---|
597 | if(wbufidx >= wbufalloc)
|
---|
598 | {
|
---|
599 | wbufalloc += 1024;
|
---|
600 | wbuffer = xrealloc(wbuffer, wbufalloc * sizeof(wbuffer[0]));
|
---|
601 | if(wbufalloc > 65536)
|
---|
602 | yywarning("Reallocating wide string buffer larger than 64kB");
|
---|
603 | }
|
---|
604 |
|
---|
605 | /*
|
---|
606 | * BS 08-Aug-1999 FIXME: The '& 0xff' is probably a bug, but I have
|
---|
607 | * not experienced it yet and I seem to remember that this was for
|
---|
608 | * a reason. But, as so many things you tend to forget why.
|
---|
609 | * I guess that there were problems due to the sign extension of
|
---|
610 | * shorts WRT chars (e.g. 0x80 becomes 0xff80 instead of 0x0080).
|
---|
611 | * This should then be fixed in the lexer calling the function.
|
---|
612 | */
|
---|
613 | wbuffer[wbufidx++] = (short)(s & 0xff);
|
---|
614 | }
|
---|
615 |
|
---|
616 | static string_t *get_buffered_cstring(void)
|
---|
617 | {
|
---|
618 | string_t *str = new_string();
|
---|
619 | str->size = cbufidx;
|
---|
620 | str->type = str_char;
|
---|
621 | str->str.cstr = (char *)xmalloc(cbufidx+1);
|
---|
622 | memcpy(str->str.cstr, cbuffer, cbufidx);
|
---|
623 | str->str.cstr[cbufidx] = '\0';
|
---|
624 | return str;
|
---|
625 | }
|
---|
626 |
|
---|
627 | static string_t *get_buffered_wstring(void)
|
---|
628 | {
|
---|
629 | string_t *str = new_string();
|
---|
630 | str->size = wbufidx;
|
---|
631 | str->type = str_unicode;
|
---|
632 | str->str.wstr = (short *)xmalloc(2*(wbufidx+1));
|
---|
633 | memcpy(str->str.wstr, wbuffer, wbufidx);
|
---|
634 | str->str.wstr[wbufidx] = 0;
|
---|
635 | return str;
|
---|
636 | }
|
---|
637 |
|
---|
638 | static string_t *make_string(char *s)
|
---|
639 | {
|
---|
640 | string_t *str = new_string();
|
---|
641 | str->size = strlen(s);
|
---|
642 | str->type = str_char;
|
---|
643 | str->str.cstr = (char *)xmalloc(str->size+1);
|
---|
644 | memcpy(str->str.cstr, s, str->size+1);
|
---|
645 | return str;
|
---|
646 | }
|
---|
647 |
|
---|
648 | /* Called from the parser to kill c-junk */
|
---|
649 | void strip_extern(void)
|
---|
650 | {
|
---|
651 | cjunk_tagline = line_number;
|
---|
652 | yy_push_state(pp_stripe);
|
---|
653 | }
|
---|
654 |
|
---|
655 | void strip_til_semicolon(void)
|
---|
656 | {
|
---|
657 | cjunk_tagline = line_number;
|
---|
658 | yy_push_state(pp_strips);
|
---|
659 | }
|
---|
660 |
|
---|
661 | void strip_til_parenthesis(void)
|
---|
662 | {
|
---|
663 | cjunk_tagline = line_number;
|
---|
664 | stripplevel = 1; /* One scanned already */
|
---|
665 | yy_push_state(pp_stripp);
|
---|
666 | }
|
---|
667 |
|
---|