First stab at Windows resource compiler:
[binutils-gdb.git] / binutils / rclex.l
1 %{ /* rclex.l -- lexer for Windows rc files parser */
2 /* Copyright 1997 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 "windres.h"
30 #include "rcparse.h"
31
32 #include <ctype.h>
33 #include <assert.h>
34
35 static void cpp_line PARAMS ((const char *));
36 static char *handle_quotes PARAMS ((const char *));
37
38 %}
39
40 %%
41
42 "BEGIN" { return BEG; }
43 "END" { return END; }
44 "ACCELERATORS" { return ACCELERATORS; }
45 "VIRTKEY" { return VIRTKEY; }
46 "ASCII" { return ASCII; }
47 "NOINVERT" { return NOINVERT; }
48 "SHIFT" { return SHIFT; }
49 "CONTROL" { return CONTROL; }
50 "ALT" { return ALT; }
51 "BITMAP" { return BITMAP; }
52 "CURSOR" { return CURSOR; }
53 "DIALOG" { return DIALOG; }
54 "DIALOGEX" { return DIALOGEX; }
55 "EXSTYLE" { return EXSTYLE; }
56 "CAPTION" { return CAPTION; }
57 "CLASS" { return CLASS; }
58 "STYLE" { return STYLE; }
59 "AUTO3STATE" { return AUTO3STATE; }
60 "AUTOCHECKBOX" { return AUTOCHECKBOX; }
61 "AUTORADIOBUTTON" { return AUTORADIOBUTTON; }
62 "CHECKBOX" { return CHECKBOX; }
63 "COMBOBOX" { return COMBOBOX; }
64 "CTEXT" { return CTEXT; }
65 "DEFPUSHBUTTON" { return DEFPUSHBUTTON; }
66 "EDITTEXT" { return EDITTEXT; }
67 "GROUPBOX" { return GROUPBOX; }
68 "LISTBOX" { return LISTBOX; }
69 "LTEXT" { return LTEXT; }
70 "PUSHBOX" { return PUSHBOX; }
71 "PUSHBUTTON" { return PUSHBUTTON; }
72 "RADIOBUTTON" { return RADIOBUTTON; }
73 "RTEXT" { return RTEXT; }
74 "SCROLLBAR" { return SCROLLBAR; }
75 "STATE3" { return STATE3; }
76 "USERBUTTON" { return USERBUTTON; }
77 "BEDIT" { return BEDIT; }
78 "HEDIT" { return HEDIT; }
79 "IEDIT" { return IEDIT; }
80 "FONT" { return FONT; }
81 "ICON" { return ICON; }
82 "LANGUAGE" { return LANGUAGE; }
83 "CHARACTERISTICS" { return CHARACTERISTICS; }
84 "VERSION" { return VERSION; }
85 "MENU" { return MENU; }
86 "MENUEX" { return MENUEX; }
87 "MENUITEM" { return MENUITEM; }
88 "SEPARATOR" { return SEPARATOR; }
89 "POPUP" { return POPUP; }
90 "CHECKED" { return CHECKED; }
91 "GRAYED" { return GRAYED; }
92 "HELP" { return HELP; }
93 "INACTIVE" { return INACTIVE; }
94 "MENUBARBREAK" { return MENUBARBREAK; }
95 "MENUBREAK" { return MENUBREAK; }
96 "MESSAGETABLE" { return MESSAGETABLE; }
97 "RCDATA" { return RCDATA; }
98 "STRINGTABLE" { return STRINGTABLE; }
99 "VERSIONINFO" { return VERSIONINFO; }
100 "FILEVERSION" { return FILEVERSION; }
101 "PRODUCTVERSION" { return PRODUCTVERSION; }
102 "FILEFLAGSMASK" { return FILEFLAGSMASK; }
103 "FILEFLAGS" { return FILEFLAGS; }
104 "FILEOS" { return FILEOS; }
105 "FILETYPE" { return FILETYPE; }
106 "FILESUBTYPE" { return FILESUBTYPE; }
107 "VALUE" { return VALUE; }
108 "MOVEABLE" { return MOVEABLE; }
109 "FIXED" { return FIXED; }
110 "PURE" { return PURE; }
111 "IMPURE" { return IMPURE; }
112 "PRELOAD" { return PRELOAD; }
113 "LOADONCALL" { return LOADONCALL; }
114 "DISCARDABLE" { return DISCARDABLE; }
115 "NOT" { return NOT; }
116
117 "BLOCK"[ \t\n]*"\""[^\#\n]*"\"" {
118 char *s, *send;
119
120 /* This is a hack to let us parse version
121 information easily. */
122
123 s = strchr (yytext, '"');
124 ++s;
125 send = strchr (s, '"');
126 if (strncmp (s, "StringFileInfo",
127 sizeof "StringFileInfo" - 1) == 0
128 && s + sizeof "StringFileInfo" - 1 == send)
129 return BLOCKSTRINGFILEINFO;
130 else if (strncmp (s, "VarFileInfo",
131 sizeof "VarFileInfo" - 1) == 0
132 && s + sizeof "VarFileInfo" - 1 == send)
133 return BLOCKVARFILEINFO;
134 else
135 {
136 yylval.s = (char *) xmalloc (send - s + 1);
137 strncpy (yylval.s, s, send - s);
138 yylval.s[send - s] = '\0';
139 return BLOCK;
140 }
141 }
142
143 "#"[^\n]* {
144 cpp_line (yytext);
145 }
146
147 [0-9][x0-9A-Fa-f]*L {
148 yylval.i.val = strtoul (yytext, 0, 0);
149 yylval.i.dword = 1;
150 return NUMBER;
151 }
152
153 [0-9][x0-9A-Fa-f]* {
154 yylval.i.val = strtoul (yytext, 0, 0);
155 yylval.i.dword = 0;
156 return NUMBER;
157 }
158
159 ("\""[^\"\n]*"\""[ \t]*)+ {
160 yylval.s = handle_quotes (yytext);
161 return QUOTEDSTRING;
162 }
163
164 [A-Za-z][^ \t\r\n]* {
165 yylval.s = xstrdup (yytext);
166 return STRING;
167 }
168
169 [\n] { ++rc_lineno; }
170 [ \t\r]+ { /* ignore whitespace */ }
171 . { return *yytext; }
172
173 %%
174 #ifndef yywrap
175 /* This is needed for some versions of lex. */
176 int yywrap ()
177 {
178 return 1;
179 }
180 #endif
181
182 /* Handle a C preprocessor line. */
183
184 static void
185 cpp_line (s)
186 const char *s;
187 {
188 int line;
189 char *send, *fn;
190
191 ++s;
192 while (isspace (*s))
193 ++s;
194
195 line = strtol (s, &send, 0);
196 if (*send != '\0' && ! isspace (*send))
197 return;
198
199 /* Subtract 1 because we are about to count the newline. */
200 rc_lineno = line - 1;
201
202 s = send;
203 while (isspace (*s))
204 ++s;
205
206 if (*s != '"')
207 return;
208
209 ++s;
210 send = strchr (s, '"');
211 if (send == NULL)
212 return;
213
214 fn = (char *) xmalloc (send - s + 1);
215 strncpy (fn, s, send - s);
216 fn[send - s] = '\0';
217
218 free (rc_filename);
219 rc_filename = fn;
220 }
221
222 /* Handle a quoted string. The quotes are stripped. A pair of quotes
223 in a string are turned into a single quote. Adjacent strings are
224 merged separated by whitespace are merged, as in C. */
225
226 static char *
227 handle_quotes (input)
228 const char *input;
229 {
230 char *ret, *s;
231 const char *t;
232 int ch;
233
234 ret = (char *) xmalloc (strlen (input) + 1);
235
236 s = ret;
237 t = input;
238 if (*t == '"')
239 ++t;
240 while (*t != '\0')
241 {
242 if (*t == '\\')
243 {
244 ++t;
245 switch (*t)
246 {
247 case '\0':
248 rcparse_warning ("backslash at end of string");
249 break;
250
251 case '\"':
252 rcparse_warning ("use \"\" to put \" in a string");
253 break;
254
255 case '\\':
256 *s++ = *t++;
257 break;
258
259 case '0': case '1': case '2': case '3':
260 case '4': case '5': case '6': case '7':
261 ch = *t - '0';
262 ++t;
263 if (*t >= '0' && *t <= '7')
264 {
265 ch = (ch << 3) | (*t - '0');
266 ++t;
267 if (*t >= '0' && *t <= '7')
268 {
269 ch = (ch << 3) | (*t - '0');
270 ++t;
271 }
272 }
273 *s++ = ch;
274 break;
275
276 case 'x':
277 ++t;
278 ch = 0;
279 while (1)
280 {
281 if (*t >= '0' && *t <= '9')
282 ch = (ch << 4) | (*t - '0');
283 else if (*t >= 'a' && *t <= 'f')
284 ch = (ch << 4) | (*t - 'a');
285 else if (*t >= 'A' && *t <= 'F')
286 ch = (ch << 4) | (*t - 'A');
287 else
288 break;
289 ++t;
290 }
291 *s++ = ch;
292 break;
293 }
294 }
295 else if (*t != '"')
296 *s++ = *t++;
297 else if (t[1] == '\0')
298 break;
299 else if (t[1] == '"')
300 {
301 *s++ = '"';
302 t += 2;
303 }
304 else
305 {
306 ++t;
307 assert (isspace (*t));
308 while (isspace (*t))
309 ++t;
310 if (*t == '\0')
311 break;
312 assert (*t == '"');
313 ++t;
314 }
315 }
316
317 *s = '\0';
318
319 return ret;
320 }