Initial revision
[binutils.git] / binutils / rclex.l
blob06a66077f287aba5c74ce3f43a7b803473cca438
1 %{ /* rclex.l -- lexer for Windows rc files parser  */
2 /* Copyright 1997, 1998 Free Software Foundation, Inc.
3    Written by Ian Lance Taylor, Cygnus Support.
5    This file is part of GNU Binutils.
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.
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.
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.  */
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.  */
26 #include "bfd.h"
27 #include "bucomm.h"
28 #include "libiberty.h"
29 #include "windres.h"
30 #include "rcparse.h"
32 #include <ctype.h>
33 #include <assert.h>
35 /* Whether we are in rcdata mode, in which we returns the lengths of
36    strings.  */
38 static int rcdata_mode;
40 /* List of allocated strings.  */
42 struct alloc_string
44   struct alloc_string *next;
45   char *s;
48 static struct alloc_string *strings;
50 /* Local functions.  */
52 static void cpp_line PARAMS ((const char *));
53 static char *handle_quotes PARAMS ((const char *, unsigned long *));
54 static char *get_string PARAMS ((int));
60 "BEGIN"                 { return BEG; }
61 "{"                     { return BEG; }
62 "END"                   { return END; }
63 "}"                     { return END; }
64 "ACCELERATORS"          { return ACCELERATORS; }
65 "VIRTKEY"               { return VIRTKEY; }
66 "ASCII"                 { return ASCII; }
67 "NOINVERT"              { return NOINVERT; }
68 "SHIFT"                 { return SHIFT; }
69 "CONTROL"               { return CONTROL; }
70 "ALT"                   { return ALT; }
71 "BITMAP"                { return BITMAP; }
72 "CURSOR"                { return CURSOR; }
73 "DIALOG"                { return DIALOG; }
74 "DIALOGEX"              { return DIALOGEX; }
75 "EXSTYLE"               { return EXSTYLE; }
76 "CAPTION"               { return CAPTION; }
77 "CLASS"                 { return CLASS; }
78 "STYLE"                 { return STYLE; }
79 "AUTO3STATE"            { return AUTO3STATE; }
80 "AUTOCHECKBOX"          { return AUTOCHECKBOX; }
81 "AUTORADIOBUTTON"       { return AUTORADIOBUTTON; }
82 "CHECKBOX"              { return CHECKBOX; }
83 "COMBOBOX"              { return COMBOBOX; }
84 "CTEXT"                 { return CTEXT; }
85 "DEFPUSHBUTTON"         { return DEFPUSHBUTTON; }
86 "EDITTEXT"              { return EDITTEXT; }
87 "GROUPBOX"              { return GROUPBOX; }
88 "LISTBOX"               { return LISTBOX; }
89 "LTEXT"                 { return LTEXT; }
90 "PUSHBOX"               { return PUSHBOX; }
91 "PUSHBUTTON"            { return PUSHBUTTON; }
92 "RADIOBUTTON"           { return RADIOBUTTON; }
93 "RTEXT"                 { return RTEXT; }
94 "SCROLLBAR"             { return SCROLLBAR; }
95 "STATE3"                { return STATE3; }
96 "USERBUTTON"            { return USERBUTTON; }
97 "BEDIT"                 { return BEDIT; }
98 "HEDIT"                 { return HEDIT; }
99 "IEDIT"                 { return IEDIT; }
100 "FONT"                  { return FONT; }
101 "ICON"                  { return ICON; }
102 "LANGUAGE"              { return LANGUAGE; }
103 "CHARACTERISTICS"       { return CHARACTERISTICS; }
104 "VERSION"               { return VERSIONK; }
105 "MENU"                  { return MENU; }
106 "MENUEX"                { return MENUEX; }
107 "MENUITEM"              { return MENUITEM; }
108 "SEPARATOR"             { return SEPARATOR; }
109 "POPUP"                 { return POPUP; }
110 "CHECKED"               { return CHECKED; }
111 "GRAYED"                { return GRAYED; }
112 "HELP"                  { return HELP; }
113 "INACTIVE"              { return INACTIVE; }
114 "MENUBARBREAK"          { return MENUBARBREAK; }
115 "MENUBREAK"             { return MENUBREAK; }
116 "MESSAGETABLE"          { return MESSAGETABLE; }
117 "RCDATA"                { return RCDATA; }
118 "STRINGTABLE"           { return STRINGTABLE; }
119 "VERSIONINFO"           { return VERSIONINFO; }
120 "FILEVERSION"           { return FILEVERSION; }
121 "PRODUCTVERSION"        { return PRODUCTVERSION; }
122 "FILEFLAGSMASK"         { return FILEFLAGSMASK; }
123 "FILEFLAGS"             { return FILEFLAGS; }
124 "FILEOS"                { return FILEOS; }
125 "FILETYPE"              { return FILETYPE; }
126 "FILESUBTYPE"           { return FILESUBTYPE; }
127 "VALUE"                 { return VALUE; }
128 "MOVEABLE"              { return MOVEABLE; }
129 "FIXED"                 { return FIXED; }
130 "PURE"                  { return PURE; }
131 "IMPURE"                { return IMPURE; }
132 "PRELOAD"               { return PRELOAD; }
133 "LOADONCALL"            { return LOADONCALL; }
134 "DISCARDABLE"           { return DISCARDABLE; }
135 "NOT"                   { return NOT; }
137 "BLOCK"[ \t\n]*"\""[^\#\n]*"\"" {
138                           char *s, *send;
140                           /* This is a hack to let us parse version
141                              information easily.  */
143                           s = strchr (yytext, '"');
144                           ++s;
145                           send = strchr (s, '"');
146                           if (strncmp (s, "StringFileInfo",
147                                        sizeof "StringFileInfo" - 1) == 0
148                               && s + sizeof "StringFileInfo" - 1 == send)
149                             return BLOCKSTRINGFILEINFO;
150                           else if (strncmp (s, "VarFileInfo",
151                                             sizeof "VarFileInfo" - 1) == 0
152                                    && s + sizeof "VarFileInfo" - 1 == send)
153                             return BLOCKVARFILEINFO;
154                           else
155                             {
156                               char *r;
158                               r = get_string (send - s + 1);
159                               strncpy (r, s, send - s);
160                               r[send - s] = '\0';
161                               yylval.s = r;
162                               return BLOCK;
163                             }
164                         }
166 "#"[^\n]*               {
167                           cpp_line (yytext);
168                         }
170 [0-9][x0-9A-Fa-f]*L     {
171                           yylval.i.val = strtoul (yytext, 0, 0);
172                           yylval.i.dword = 1;
173                           return NUMBER;
174                         }
176 [0-9][x0-9A-Fa-f]*      {
177                           yylval.i.val = strtoul (yytext, 0, 0);
178                           yylval.i.dword = 0;
179                           return NUMBER;
180                         }
182 ("\""[^\"\n]*"\""[ \t]*)+ {
183                           char *s;
184                           unsigned long length;
186                           s = handle_quotes (yytext, &length);
187                           if (! rcdata_mode)
188                             {
189                               yylval.s = s;
190                               return QUOTEDSTRING;
191                             }
192                           else
193                             {
194                               yylval.ss.length = length;
195                               yylval.ss.s = s;
196                               return SIZEDSTRING;
197                             }
198                         }
200 [A-Za-z][^ ,\t\r\n]*    {
201                           char *s;
203                           /* I rejected comma in a string in order to
204                              handle VIRTKEY, CONTROL in an accelerator
205                              resource.  This means that an unquoted
206                              file name can not contain a comma.  I
207                              don't know what rc permits.  */
209                           s = get_string (strlen (yytext) + 1);
210                           strcpy (s, yytext);
211                           yylval.s = s;
212                           return STRING;
213                         }
215 [\n]                    { ++rc_lineno; }
216 [ \t\r]+                { /* ignore whitespace */ }
217 .                       { return *yytext; }
220 #ifndef yywrap
221 /* This is needed for some versions of lex.  */
222 int yywrap ()
224   return 1;
226 #endif
228 /* Handle a C preprocessor line.  */
230 static void
231 cpp_line (s)
232      const char *s;
234   int line;
235   char *send, *fn;
237   ++s;
238   while (isspace ((unsigned char) *s))
239     ++s;
240   
241   line = strtol (s, &send, 0);
242   if (*send != '\0' && ! isspace ((unsigned char) *send))
243     return;
245   /* Subtract 1 because we are about to count the newline.  */
246   rc_lineno = line - 1;
248   s = send;
249   while (isspace ((unsigned char) *s))
250     ++s;
252   if (*s != '"')
253     return;
255   ++s;
256   send = strchr (s, '"');
257   if (send == NULL)
258     return;
260   fn = (char *) xmalloc (send - s + 1);
261   strncpy (fn, s, send - s);
262   fn[send - s] = '\0';
264   free (rc_filename);
265   rc_filename = fn;
268 /* Handle a quoted string.  The quotes are stripped.  A pair of quotes
269    in a string are turned into a single quote.  Adjacent strings are
270    merged separated by whitespace are merged, as in C.  */
272 static char *
273 handle_quotes (input, len)
274      const char *input;
275      unsigned long *len;
277   char *ret, *s;
278   const char *t;
279   int ch;
281   ret = get_string (strlen (input) + 1);
283   s = ret;
284   t = input;
285   if (*t == '"')
286     ++t;
287   while (*t != '\0')
288     {
289       if (*t == '\\')
290         {
291           ++t;
292           switch (*t)
293             {
294             case '\0':
295               rcparse_warning ("backslash at end of string");
296               break;
298             case '\"':
299               rcparse_warning ("use \"\" to put \" in a string");
300               break;
302             case 'a':
303               *s++ = ESCAPE_A;
304               ++t;
305               break;
307             case 'b':
308               *s++ = ESCAPE_B;
309               ++t;
310               break;
312             case 'f':
313               *s++ = ESCAPE_F;
314               ++t;
315               break;
317             case 'n':
318               *s++ = ESCAPE_N;
319               ++t;
320               break;
322             case 'r':
323               *s++ = ESCAPE_R;
324               ++t;
325               break;
327             case 't':
328               *s++ = ESCAPE_T;
329               ++t;
330               break;
332             case 'v':
333               *s++ = ESCAPE_V;
334               ++t;
335               break;
337             case '\\':
338               *s++ = *t++;
339               break;
341             case '0': case '1': case '2': case '3':
342             case '4': case '5': case '6': case '7':
343               ch = *t - '0';
344               ++t;
345               if (*t >= '0' && *t <= '7')
346                 {
347                   ch = (ch << 3) | (*t - '0');
348                   ++t;
349                   if (*t >= '0' && *t <= '7')
350                     {
351                       ch = (ch << 3) | (*t - '0');
352                       ++t;
353                     }
354                 }
355               *s++ = ch;
356               break;
358             case 'x':
359               ++t;
360               ch = 0;
361               while (1)
362                 {
363                   if (*t >= '0' && *t <= '9')
364                     ch = (ch << 4) | (*t - '0');
365                   else if (*t >= 'a' && *t <= 'f')
366                     ch = (ch << 4) | (*t - 'a');
367                   else if (*t >= 'A' && *t <= 'F')
368                     ch = (ch << 4) | (*t - 'A');
369                   else
370                     break;
371                   ++t;
372                 }
373               *s++ = ch;
374               break;
376             default:
377               rcparse_warning ("unrecognized escape sequence");
378               *s++ = '\\';
379               *s++ = *t++;
380               break;
381             }
382         }
383       else if (*t != '"')
384         *s++ = *t++;
385       else if (t[1] == '\0')
386         break;
387       else if (t[1] == '"')
388         {
389           *s++ = '"';
390           t += 2;
391         }
392       else
393         {
394           ++t;
395           assert (isspace ((unsigned char) *t));
396           while (isspace ((unsigned char) *t))
397             ++t;
398           if (*t == '\0')
399             break;
400           assert (*t == '"');
401           ++t;
402         }
403     }
405   *s = '\0';
407   *len = s - ret;
409   return ret;
412 /* Allocate a string of a given length.  */
414 static char *
415 get_string (len)
416      int len;
418   struct alloc_string *as;
420   as = (struct alloc_string *) xmalloc (sizeof *as);
421   as->s = xmalloc (len);
423   as->next = strings;
424   strings = as->next;
426   return as->s;
429 /* Discard all the strings we have allocated.  The parser calls this
430    when it no longer needs them.  */
432 void
433 rcparse_discard_strings ()
435   struct alloc_string *as;
437   as = strings;
438   while (as != NULL)
439     {
440       struct alloc_string *n;
442       free (as->s);
443       n = as->next;
444       free (as);
445       as = n;
446     }
448   strings = NULL;
451 /* Enter rcdata mode.  */
453 void
454 rcparse_rcdata ()
456   rcdata_mode = 1;
459 /* Go back to normal mode from rcdata mode.  */
461 void
462 rcparse_normal ()
464   rcdata_mode = 0;