]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - binutils/rclex.l
* symbols.c (colon) [!WORKING_DOT_WORD]: Don't declare
[thirdparty/binutils-gdb.git] / binutils / rclex.l
CommitLineData
252b5132 1%{ /* rclex.l -- lexer for Windows rc files parser */
2da42df6 2/* Copyright 1997, 1998, 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
252b5132
RH
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"
3882b010 29#include "safe-ctype.h"
252b5132
RH
30#include "windres.h"
31#include "rcparse.h"
32
252b5132
RH
33#include <assert.h>
34
35/* Whether we are in rcdata mode, in which we returns the lengths of
36 strings. */
37
38static int rcdata_mode;
39
1a624788
DD
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
48static 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
55static char *initial_fn;
56
252b5132
RH
57/* List of allocated strings. */
58
59struct alloc_string
60{
61 struct alloc_string *next;
62 char *s;
63};
64
65static struct alloc_string *strings;
66
67/* Local functions. */
68
2da42df6
AJ
69static void cpp_line (const char *);
70static char *handle_quotes (const char *, unsigned long *);
71static char *get_string (int);
252b5132
RH
72
73%}
74
75%%
76
1a624788
DD
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); }
252b5132
RH
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)
1a624788 166 MAYBE_RETURN (BLOCKSTRINGFILEINFO);
252b5132
RH
167 else if (strncmp (s, "VarFileInfo",
168 sizeof "VarFileInfo" - 1) == 0
169 && s + sizeof "VarFileInfo" - 1 == send)
1a624788 170 MAYBE_RETURN (BLOCKVARFILEINFO);
252b5132
RH
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;
1a624788 179 MAYBE_RETURN (BLOCK);
252b5132
RH
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;
1a624788 190 MAYBE_RETURN (NUMBER);
252b5132
RH
191 }
192
193[0-9][x0-9A-Fa-f]* {
194 yylval.i.val = strtoul (yytext, 0, 0);
195 yylval.i.dword = 0;
1a624788 196 MAYBE_RETURN (NUMBER);
252b5132
RH
197 }
198
6e5f5201 199("\""[^\"\n]*"\""[ \t\n]*)+ {
252b5132
RH
200 char *s;
201 unsigned long length;
202
203 s = handle_quotes (yytext, &length);
204 if (! rcdata_mode)
205 {
206 yylval.s = s;
1a624788 207 MAYBE_RETURN (QUOTEDSTRING);
252b5132
RH
208 }
209 else
210 {
211 yylval.ss.length = length;
212 yylval.ss.s = s;
1a624788 213 MAYBE_RETURN (SIZEDSTRING);
252b5132
RH
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;
1a624788 229 MAYBE_RETURN (STRING);
252b5132
RH
230 }
231
232[\n] { ++rc_lineno; }
233[ \t\r]+ { /* ignore whitespace */ }
1a624788 234. { MAYBE_RETURN (*yytext); }
252b5132
RH
235
236%%
237#ifndef yywrap
238/* This is needed for some versions of lex. */
2da42df6 239int yywrap (void)
252b5132
RH
240{
241 return 1;
242}
243#endif
244
245/* Handle a C preprocessor line. */
246
247static void
2da42df6 248cpp_line (const char *s)
252b5132
RH
249{
250 int line;
251 char *send, *fn;
252
253 ++s;
3882b010 254 while (ISSPACE (*s))
252b5132
RH
255 ++s;
256
257 line = strtol (s, &send, 0);
3882b010 258 if (*send != '\0' && ! ISSPACE (*send))
252b5132
RH
259 return;
260
261 /* Subtract 1 because we are about to count the newline. */
262 rc_lineno = line - 1;
263
264 s = send;
3882b010 265 while (ISSPACE (*s))
252b5132
RH
266 ++s;
267
268 if (*s != '"')
269 return;
270
271 ++s;
272 send = strchr (s, '"');
273 if (send == NULL)
274 return;
275
276 fn = (char *) xmalloc (send - s + 1);
277 strncpy (fn, s, send - s);
278 fn[send - s] = '\0';
279
280 free (rc_filename);
281 rc_filename = fn;
1a624788
DD
282
283 if (!initial_fn)
284 {
285 initial_fn = xmalloc (strlen (fn) + 1);
4c30641a 286 strcpy (initial_fn, fn);
1a624788
DD
287 }
288
289 /* Allow the initial file, regardless of name. Suppress all other
4c30641a 290 files if they end in ".h" (this allows included "*.rc"). */
1a624788
DD
291 if (strcmp (initial_fn, fn) == 0
292 || strcmp (fn + strlen (fn) - 2, ".h") != 0)
293 suppress_cpp_data = 0;
294 else
295 suppress_cpp_data = 1;
252b5132
RH
296}
297
298/* Handle a quoted string. The quotes are stripped. A pair of quotes
299 in a string are turned into a single quote. Adjacent strings are
300 merged separated by whitespace are merged, as in C. */
301
302static char *
2da42df6 303handle_quotes (const char *input, unsigned long *len)
252b5132
RH
304{
305 char *ret, *s;
306 const char *t;
307 int ch;
308
309 ret = get_string (strlen (input) + 1);
310
311 s = ret;
312 t = input;
313 if (*t == '"')
314 ++t;
315 while (*t != '\0')
316 {
317 if (*t == '\\')
318 {
319 ++t;
320 switch (*t)
321 {
322 case '\0':
323 rcparse_warning ("backslash at end of string");
324 break;
325
326 case '\"':
327 rcparse_warning ("use \"\" to put \" in a string");
328 break;
329
330 case 'a':
4d0b1625 331 *s++ = ESCAPE_B; /* Strange, but true... */
252b5132
RH
332 ++t;
333 break;
334
335 case 'b':
336 *s++ = ESCAPE_B;
337 ++t;
338 break;
339
340 case 'f':
341 *s++ = ESCAPE_F;
342 ++t;
343 break;
344
345 case 'n':
346 *s++ = ESCAPE_N;
347 ++t;
348 break;
349
350 case 'r':
351 *s++ = ESCAPE_R;
352 ++t;
353 break;
354
355 case 't':
356 *s++ = ESCAPE_T;
357 ++t;
358 break;
359
360 case 'v':
361 *s++ = ESCAPE_V;
362 ++t;
363 break;
364
365 case '\\':
366 *s++ = *t++;
367 break;
368
369 case '0': case '1': case '2': case '3':
370 case '4': case '5': case '6': case '7':
371 ch = *t - '0';
372 ++t;
373 if (*t >= '0' && *t <= '7')
374 {
375 ch = (ch << 3) | (*t - '0');
376 ++t;
377 if (*t >= '0' && *t <= '7')
378 {
379 ch = (ch << 3) | (*t - '0');
380 ++t;
381 }
382 }
383 *s++ = ch;
384 break;
385
386 case 'x':
387 ++t;
388 ch = 0;
389 while (1)
390 {
391 if (*t >= '0' && *t <= '9')
392 ch = (ch << 4) | (*t - '0');
393 else if (*t >= 'a' && *t <= 'f')
4c30641a 394 ch = (ch << 4) | (*t - 'a' + 10);
252b5132 395 else if (*t >= 'A' && *t <= 'F')
4c30641a 396 ch = (ch << 4) | (*t - 'A' + 10);
252b5132
RH
397 else
398 break;
399 ++t;
400 }
401 *s++ = ch;
402 break;
403
404 default:
405 rcparse_warning ("unrecognized escape sequence");
406 *s++ = '\\';
407 *s++ = *t++;
408 break;
409 }
410 }
411 else if (*t != '"')
412 *s++ = *t++;
413 else if (t[1] == '\0')
414 break;
415 else if (t[1] == '"')
416 {
417 *s++ = '"';
418 t += 2;
419 }
420 else
421 {
422 ++t;
3882b010
L
423 assert (ISSPACE (*t));
424 while (ISSPACE (*t))
0e11a9e9
CF
425 {
426 if ((*t) == '\n')
427 ++rc_lineno;
428 ++t;
429 }
252b5132
RH
430 if (*t == '\0')
431 break;
432 assert (*t == '"');
433 ++t;
434 }
435 }
436
437 *s = '\0';
438
439 *len = s - ret;
440
441 return ret;
442}
443
444/* Allocate a string of a given length. */
445
446static char *
2da42df6 447get_string (int len)
252b5132
RH
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;
405c98a4 455 strings = as;
252b5132
RH
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
463void
2da42df6 464rcparse_discard_strings (void)
252b5132
RH
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
484void
2da42df6 485rcparse_rcdata (void)
252b5132
RH
486{
487 rcdata_mode = 1;
488}
489
490/* Go back to normal mode from rcdata mode. */
491
492void
2da42df6 493rcparse_normal (void)
252b5132
RH
494{
495 rcdata_mode = 0;
496}