]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - binutils/rclex.l
* Makefile.am (eelf64ppc.c, eelf64lppc.c): Depend on ppc64elf.em.
[thirdparty/binutils-gdb.git] / binutils / rclex.l
1 %{ /* rclex.l -- lexer for Windows rc files parser */
2 /* Copyright 1997, 1998, 1999, 2001 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Cygnus Support.
4
5 This file is part of GNU Binutils.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA. */
21
22 /* This is a lex input file which generates a lexer used by the
23 Windows rc file parser. It basically just recognized a bunch of
24 keywords. */
25
26 #include "bfd.h"
27 #include "bucomm.h"
28 #include "libiberty.h"
29 #include "safe-ctype.h"
30 #include "windres.h"
31 #include "rcparse.h"
32
33 #include <assert.h>
34
35 /* Whether we are in rcdata mode, in which we returns the lengths of
36 strings. */
37
38 static int rcdata_mode;
39
40 /* Whether we are supressing lines from cpp (including windows.h or
41 headers from your C sources may bring in externs and typedefs).
42 When active, we return IGNORED_TOKEN, which lets us ignore these
43 outside of resource constructs. Thus, it isn't required to protect
44 all the non-preprocessor lines in your header files with #ifdef
45 RC_INVOKED. It also means your RC file can't include other RC
46 files if they're named "*.h". Sorry. Name them *.rch or whatever. */
47
48 static int suppress_cpp_data;
49
50 #define MAYBE_RETURN(x) return suppress_cpp_data ? IGNORED_TOKEN : (x)
51
52 /* The first filename we detect in the cpp output. We use this to
53 tell included files from the original file. */
54
55 static char *initial_fn;
56
57 /* List of allocated strings. */
58
59 struct alloc_string
60 {
61 struct alloc_string *next;
62 char *s;
63 };
64
65 static struct alloc_string *strings;
66
67 /* Local functions. */
68
69 static void cpp_line PARAMS ((const char *));
70 static char *handle_quotes PARAMS ((const char *, unsigned long *));
71 static char *get_string PARAMS ((int));
72
73 %}
74
75 %%
76
77 "BEGIN" { MAYBE_RETURN (BEG); }
78 "{" { MAYBE_RETURN (BEG); }
79 "END" { MAYBE_RETURN (END); }
80 "}" { MAYBE_RETURN (END); }
81 "ACCELERATORS" { MAYBE_RETURN (ACCELERATORS); }
82 "VIRTKEY" { MAYBE_RETURN (VIRTKEY); }
83 "ASCII" { MAYBE_RETURN (ASCII); }
84 "NOINVERT" { MAYBE_RETURN (NOINVERT); }
85 "SHIFT" { MAYBE_RETURN (SHIFT); }
86 "CONTROL" { MAYBE_RETURN (CONTROL); }
87 "ALT" { MAYBE_RETURN (ALT); }
88 "BITMAP" { MAYBE_RETURN (BITMAP); }
89 "CURSOR" { MAYBE_RETURN (CURSOR); }
90 "DIALOG" { MAYBE_RETURN (DIALOG); }
91 "DIALOGEX" { MAYBE_RETURN (DIALOGEX); }
92 "EXSTYLE" { MAYBE_RETURN (EXSTYLE); }
93 "CAPTION" { MAYBE_RETURN (CAPTION); }
94 "CLASS" { MAYBE_RETURN (CLASS); }
95 "STYLE" { MAYBE_RETURN (STYLE); }
96 "AUTO3STATE" { MAYBE_RETURN (AUTO3STATE); }
97 "AUTOCHECKBOX" { MAYBE_RETURN (AUTOCHECKBOX); }
98 "AUTORADIOBUTTON" { MAYBE_RETURN (AUTORADIOBUTTON); }
99 "CHECKBOX" { MAYBE_RETURN (CHECKBOX); }
100 "COMBOBOX" { MAYBE_RETURN (COMBOBOX); }
101 "CTEXT" { MAYBE_RETURN (CTEXT); }
102 "DEFPUSHBUTTON" { MAYBE_RETURN (DEFPUSHBUTTON); }
103 "EDITTEXT" { MAYBE_RETURN (EDITTEXT); }
104 "GROUPBOX" { MAYBE_RETURN (GROUPBOX); }
105 "LISTBOX" { MAYBE_RETURN (LISTBOX); }
106 "LTEXT" { MAYBE_RETURN (LTEXT); }
107 "PUSHBOX" { MAYBE_RETURN (PUSHBOX); }
108 "PUSHBUTTON" { MAYBE_RETURN (PUSHBUTTON); }
109 "RADIOBUTTON" { MAYBE_RETURN (RADIOBUTTON); }
110 "RTEXT" { MAYBE_RETURN (RTEXT); }
111 "SCROLLBAR" { MAYBE_RETURN (SCROLLBAR); }
112 "STATE3" { MAYBE_RETURN (STATE3); }
113 "USERBUTTON" { MAYBE_RETURN (USERBUTTON); }
114 "BEDIT" { MAYBE_RETURN (BEDIT); }
115 "HEDIT" { MAYBE_RETURN (HEDIT); }
116 "IEDIT" { MAYBE_RETURN (IEDIT); }
117 "FONT" { MAYBE_RETURN (FONT); }
118 "ICON" { MAYBE_RETURN (ICON); }
119 "LANGUAGE" { MAYBE_RETURN (LANGUAGE); }
120 "CHARACTERISTICS" { MAYBE_RETURN (CHARACTERISTICS); }
121 "VERSION" { MAYBE_RETURN (VERSIONK); }
122 "MENU" { MAYBE_RETURN (MENU); }
123 "MENUEX" { MAYBE_RETURN (MENUEX); }
124 "MENUITEM" { MAYBE_RETURN (MENUITEM); }
125 "SEPARATOR" { MAYBE_RETURN (SEPARATOR); }
126 "POPUP" { MAYBE_RETURN (POPUP); }
127 "CHECKED" { MAYBE_RETURN (CHECKED); }
128 "GRAYED" { MAYBE_RETURN (GRAYED); }
129 "HELP" { MAYBE_RETURN (HELP); }
130 "INACTIVE" { MAYBE_RETURN (INACTIVE); }
131 "MENUBARBREAK" { MAYBE_RETURN (MENUBARBREAK); }
132 "MENUBREAK" { MAYBE_RETURN (MENUBREAK); }
133 "MESSAGETABLE" { MAYBE_RETURN (MESSAGETABLE); }
134 "RCDATA" { MAYBE_RETURN (RCDATA); }
135 "STRINGTABLE" { MAYBE_RETURN (STRINGTABLE); }
136 "VERSIONINFO" { MAYBE_RETURN (VERSIONINFO); }
137 "FILEVERSION" { MAYBE_RETURN (FILEVERSION); }
138 "PRODUCTVERSION" { MAYBE_RETURN (PRODUCTVERSION); }
139 "FILEFLAGSMASK" { MAYBE_RETURN (FILEFLAGSMASK); }
140 "FILEFLAGS" { MAYBE_RETURN (FILEFLAGS); }
141 "FILEOS" { MAYBE_RETURN (FILEOS); }
142 "FILETYPE" { MAYBE_RETURN (FILETYPE); }
143 "FILESUBTYPE" { MAYBE_RETURN (FILESUBTYPE); }
144 "VALUE" { MAYBE_RETURN (VALUE); }
145 "MOVEABLE" { MAYBE_RETURN (MOVEABLE); }
146 "FIXED" { MAYBE_RETURN (FIXED); }
147 "PURE" { MAYBE_RETURN (PURE); }
148 "IMPURE" { MAYBE_RETURN (IMPURE); }
149 "PRELOAD" { MAYBE_RETURN (PRELOAD); }
150 "LOADONCALL" { MAYBE_RETURN (LOADONCALL); }
151 "DISCARDABLE" { MAYBE_RETURN (DISCARDABLE); }
152 "NOT" { MAYBE_RETURN (NOT); }
153
154 "BLOCK"[ \t\n]*"\""[^\#\n]*"\"" {
155 char *s, *send;
156
157 /* This is a hack to let us parse version
158 information easily. */
159
160 s = strchr (yytext, '"');
161 ++s;
162 send = strchr (s, '"');
163 if (strncmp (s, "StringFileInfo",
164 sizeof "StringFileInfo" - 1) == 0
165 && s + sizeof "StringFileInfo" - 1 == send)
166 MAYBE_RETURN (BLOCKSTRINGFILEINFO);
167 else if (strncmp (s, "VarFileInfo",
168 sizeof "VarFileInfo" - 1) == 0
169 && s + sizeof "VarFileInfo" - 1 == send)
170 MAYBE_RETURN (BLOCKVARFILEINFO);
171 else
172 {
173 char *r;
174
175 r = get_string (send - s + 1);
176 strncpy (r, s, send - s);
177 r[send - s] = '\0';
178 yylval.s = r;
179 MAYBE_RETURN (BLOCK);
180 }
181 }
182
183 "#"[^\n]* {
184 cpp_line (yytext);
185 }
186
187 [0-9][x0-9A-Fa-f]*L {
188 yylval.i.val = strtoul (yytext, 0, 0);
189 yylval.i.dword = 1;
190 MAYBE_RETURN (NUMBER);
191 }
192
193 [0-9][x0-9A-Fa-f]* {
194 yylval.i.val = strtoul (yytext, 0, 0);
195 yylval.i.dword = 0;
196 MAYBE_RETURN (NUMBER);
197 }
198
199 ("\""[^\"\n]*"\""[ \t]*)+ {
200 char *s;
201 unsigned long length;
202
203 s = handle_quotes (yytext, &length);
204 if (! rcdata_mode)
205 {
206 yylval.s = s;
207 MAYBE_RETURN (QUOTEDSTRING);
208 }
209 else
210 {
211 yylval.ss.length = length;
212 yylval.ss.s = s;
213 MAYBE_RETURN (SIZEDSTRING);
214 }
215 }
216
217 [A-Za-z][^ ,\t\r\n]* {
218 char *s;
219
220 /* I rejected comma in a string in order to
221 handle VIRTKEY, CONTROL in an accelerator
222 resource. This means that an unquoted
223 file name can not contain a comma. I
224 don't know what rc permits. */
225
226 s = get_string (strlen (yytext) + 1);
227 strcpy (s, yytext);
228 yylval.s = s;
229 MAYBE_RETURN (STRING);
230 }
231
232 [\n] { ++rc_lineno; }
233 [ \t\r]+ { /* ignore whitespace */ }
234 . { MAYBE_RETURN (*yytext); }
235
236 %%
237 #ifndef yywrap
238 /* This is needed for some versions of lex. */
239 int yywrap ()
240 {
241 return 1;
242 }
243 #endif
244
245 /* Handle a C preprocessor line. */
246
247 static void
248 cpp_line (s)
249 const char *s;
250 {
251 int line;
252 char *send, *fn;
253
254 ++s;
255 while (ISSPACE (*s))
256 ++s;
257
258 line = strtol (s, &send, 0);
259 if (*send != '\0' && ! ISSPACE (*send))
260 return;
261
262 /* Subtract 1 because we are about to count the newline. */
263 rc_lineno = line - 1;
264
265 s = send;
266 while (ISSPACE (*s))
267 ++s;
268
269 if (*s != '"')
270 return;
271
272 ++s;
273 send = strchr (s, '"');
274 if (send == NULL)
275 return;
276
277 fn = (char *) xmalloc (send - s + 1);
278 strncpy (fn, s, send - s);
279 fn[send - s] = '\0';
280
281 free (rc_filename);
282 rc_filename = fn;
283
284 if (!initial_fn)
285 {
286 initial_fn = xmalloc (strlen (fn) + 1);
287 strcpy(initial_fn, fn);
288 }
289
290 /* Allow the initial file, regardless of name. Suppress all other
291 files if they end in ".h" (this allows included "*.rc") */
292 if (strcmp (initial_fn, fn) == 0
293 || strcmp (fn + strlen (fn) - 2, ".h") != 0)
294 suppress_cpp_data = 0;
295 else
296 suppress_cpp_data = 1;
297 }
298
299 /* Handle a quoted string. The quotes are stripped. A pair of quotes
300 in a string are turned into a single quote. Adjacent strings are
301 merged separated by whitespace are merged, as in C. */
302
303 static char *
304 handle_quotes (input, len)
305 const char *input;
306 unsigned long *len;
307 {
308 char *ret, *s;
309 const char *t;
310 int ch;
311
312 ret = get_string (strlen (input) + 1);
313
314 s = ret;
315 t = input;
316 if (*t == '"')
317 ++t;
318 while (*t != '\0')
319 {
320 if (*t == '\\')
321 {
322 ++t;
323 switch (*t)
324 {
325 case '\0':
326 rcparse_warning ("backslash at end of string");
327 break;
328
329 case '\"':
330 rcparse_warning ("use \"\" to put \" in a string");
331 break;
332
333 case 'a':
334 *s++ = ESCAPE_A;
335 ++t;
336 break;
337
338 case 'b':
339 *s++ = ESCAPE_B;
340 ++t;
341 break;
342
343 case 'f':
344 *s++ = ESCAPE_F;
345 ++t;
346 break;
347
348 case 'n':
349 *s++ = ESCAPE_N;
350 ++t;
351 break;
352
353 case 'r':
354 *s++ = ESCAPE_R;
355 ++t;
356 break;
357
358 case 't':
359 *s++ = ESCAPE_T;
360 ++t;
361 break;
362
363 case 'v':
364 *s++ = ESCAPE_V;
365 ++t;
366 break;
367
368 case '\\':
369 *s++ = *t++;
370 break;
371
372 case '0': case '1': case '2': case '3':
373 case '4': case '5': case '6': case '7':
374 ch = *t - '0';
375 ++t;
376 if (*t >= '0' && *t <= '7')
377 {
378 ch = (ch << 3) | (*t - '0');
379 ++t;
380 if (*t >= '0' && *t <= '7')
381 {
382 ch = (ch << 3) | (*t - '0');
383 ++t;
384 }
385 }
386 *s++ = ch;
387 break;
388
389 case 'x':
390 ++t;
391 ch = 0;
392 while (1)
393 {
394 if (*t >= '0' && *t <= '9')
395 ch = (ch << 4) | (*t - '0');
396 else if (*t >= 'a' && *t <= 'f')
397 ch = (ch << 4) | (*t - 'a');
398 else if (*t >= 'A' && *t <= 'F')
399 ch = (ch << 4) | (*t - 'A');
400 else
401 break;
402 ++t;
403 }
404 *s++ = ch;
405 break;
406
407 default:
408 rcparse_warning ("unrecognized escape sequence");
409 *s++ = '\\';
410 *s++ = *t++;
411 break;
412 }
413 }
414 else if (*t != '"')
415 *s++ = *t++;
416 else if (t[1] == '\0')
417 break;
418 else if (t[1] == '"')
419 {
420 *s++ = '"';
421 t += 2;
422 }
423 else
424 {
425 ++t;
426 assert (ISSPACE (*t));
427 while (ISSPACE (*t))
428 ++t;
429 if (*t == '\0')
430 break;
431 assert (*t == '"');
432 ++t;
433 }
434 }
435
436 *s = '\0';
437
438 *len = s - ret;
439
440 return ret;
441 }
442
443 /* Allocate a string of a given length. */
444
445 static char *
446 get_string (len)
447 int len;
448 {
449 struct alloc_string *as;
450
451 as = (struct alloc_string *) xmalloc (sizeof *as);
452 as->s = xmalloc (len);
453
454 as->next = strings;
455 strings = as->next;
456
457 return as->s;
458 }
459
460 /* Discard all the strings we have allocated. The parser calls this
461 when it no longer needs them. */
462
463 void
464 rcparse_discard_strings ()
465 {
466 struct alloc_string *as;
467
468 as = strings;
469 while (as != NULL)
470 {
471 struct alloc_string *n;
472
473 free (as->s);
474 n = as->next;
475 free (as);
476 as = n;
477 }
478
479 strings = NULL;
480 }
481
482 /* Enter rcdata mode. */
483
484 void
485 rcparse_rcdata ()
486 {
487 rcdata_mode = 1;
488 }
489
490 /* Go back to normal mode from rcdata mode. */
491
492 void
493 rcparse_normal ()
494 {
495 rcdata_mode = 0;
496 }