Bump version for general release.
[binutils.git] / binutils / mclex.c
blob2f0e144b0e4b59627b0909b9e689e3a9d650556c
1 /* mclex.c -- lexer for Windows mc files parser.
2 Copyright 2007
3 Free Software Foundation, Inc.
5 Written by Kai Tietz, Onevision.
7 This file is part of GNU Binutils.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
22 02110-1301, USA. */
24 /* This is a lexer used by the Windows rc file parser.
25 It basically just recognized a bunch of keywords. */
27 #include "sysdep.h"
28 #include "bfd.h"
29 #include "bucomm.h"
30 #include "libiberty.h"
31 #include "safe-ctype.h"
32 #include "windmc.h"
33 #include "mcparse.h"
35 #include <assert.h>
37 /* Exported globals. */
38 bfd_boolean mclex_want_nl = FALSE;
39 bfd_boolean mclex_want_line = FALSE;
40 bfd_boolean mclex_want_filename = FALSE;
42 /* Local globals. */
43 static unichar *input_stream = NULL;
44 static unichar *input_stream_pos = NULL;
45 static int input_line = 1;
46 static const char *input_filename = NULL;
48 void
49 mc_set_content (const unichar *src)
51 if (!src)
52 return;
53 input_stream = input_stream_pos = unichar_dup (src);
56 void
57 mc_set_inputfile (const char *name)
59 if (! name || *name == 0)
60 input_filename = "-";
61 else
63 const char *s1 = strrchr (name, '/');
64 const char *s2 = strrchr (name, '\\');
66 if (! s1)
67 s1 = s2;
68 if (s1 && s2 && s1 < s2)
69 s1 = s2;
70 if (! s1)
71 s1 = name;
72 else
73 s1++;
74 s1 = xstrdup (s1);
75 input_filename = s1;
79 static void
80 show_msg (const char *kind, const char *msg, va_list argp)
82 fprintf (stderr, "In %s at line %d: %s: ", input_filename, input_line, kind);
83 vfprintf (stderr, msg, argp);
84 fprintf (stderr, ".\n");
87 void
88 mc_warn (const char *s, ...)
90 va_list argp;
91 va_start (argp, s);
92 show_msg ("warning", s, argp);
93 va_end (argp);
96 void
97 mc_fatal (const char *s, ...)
99 va_list argp;
100 va_start (argp, s);
101 show_msg ("fatal", s, argp);
102 va_end (argp);
103 xexit (1);
108 yyerror (const char *s, ...)
110 va_list argp;
111 va_start (argp, s);
112 show_msg ("parser", s, argp);
113 va_end (argp);
114 return 1;
117 static unichar *
118 get_diff (unichar *end, unichar *start)
120 unichar *ret;
121 unichar save = *end;
123 *end = 0;
124 ret = unichar_dup (start);
125 *end = save;
126 return ret;
129 static rc_uint_type
130 parse_digit (unichar ch)
132 rc_uint_type base = 10, v = 0, c;
134 if (ch == '0')
136 base = 8;
137 switch (input_stream_pos[0])
139 case 'x': case 'X': base = 16; input_stream_pos++; break;
140 case 'o': case 'O': base = 8; input_stream_pos++; break;
141 case 'b': case 'B': base = 2; input_stream_pos++; break;
144 else
145 v = (rc_uint_type) (ch - '0');
147 while ((ch = input_stream_pos[0]) != 0)
149 if (ch >= 'A' && ch <= 'F')
150 c = (rc_uint_type) (ch - 'A') + 10;
151 else if (ch >= 'a' && ch <= 'f')
152 c = (rc_uint_type) (ch - 'a') + 10;
153 else if (ch >= '0' && ch <= '9')
154 c = (rc_uint_type) (ch - '0');
155 else
156 break;
157 v *= base;
158 v += c;
159 ++input_stream_pos;
161 if (input_stream_pos[0] == 'U' || input_stream_pos[0] == 'u')
162 input_stream_pos++;
163 if (input_stream_pos[0] == 'L' || input_stream_pos[0] == 'l')
164 input_stream_pos++;
165 if (input_stream_pos[0] == 'L' || input_stream_pos[0] == 'l')
166 input_stream_pos++;
167 return v;
170 static mc_keyword *keyword_top = NULL;
172 const mc_keyword *
173 enum_facility (int e)
175 mc_keyword *h = keyword_top;
177 while (h != NULL)
179 while (h && strcmp (h->group_name, "facility") != 0)
180 h = h->next;
181 if (e == 0)
182 return h;
183 --e;
184 if (h)
185 h = h->next;
187 return h;
190 const mc_keyword *
191 enum_severity (int e)
193 mc_keyword *h = keyword_top;
195 while (h != NULL)
197 while (h && strcmp (h->group_name, "severity") != 0)
198 h = h->next;
199 if (e == 0)
200 return h;
201 --e;
202 if (h)
203 h = h->next;
205 return h;
208 static void
209 mc_add_keyword_ascii (const char *sz, int rid, const char *grp, rc_uint_type nv, const char *sv)
211 unichar *usz, *usv = NULL;
212 rc_uint_type usz_len;
214 unicode_from_codepage (&usz_len, &usz, sz, CP_ACP);
215 if (sv)
216 unicode_from_codepage (&usz_len, &usv, sv, CP_ACP);
217 mc_add_keyword (usz, rid, grp, nv, usv);
220 void
221 mc_add_keyword (unichar *usz, int rid, const char *grp, rc_uint_type nv, unichar *sv)
223 mc_keyword *p, *c, *n;
224 size_t len = unichar_len (usz);
226 c = keyword_top;
227 p = NULL;
228 while (c != NULL)
230 if (c->len > len)
231 break;
232 if (c->len == len)
234 int e = memcmp (usz, c->usz, len * sizeof (unichar));
236 if (e < 0)
237 break;
238 if (! e)
240 if (! strcmp (grp, "keyword") || strcmp (c->group_name, grp) != 0)
241 fatal (_("Duplicate symbol entered into keyword list."));
242 c->rid = rid;
243 c->nval = nv;
244 c->sval = (!sv ? NULL : unichar_dup (sv));
245 if (! strcmp (grp, "language"))
247 const wind_language_t *lag = wind_find_language_by_id ((unsigned) nv);
249 if (lag == NULL)
250 fatal ("Language ident 0x%lx is not resolvable.\n", (long) nv);
251 memcpy (&c->lang_info, lag, sizeof (*lag));
253 return;
256 c = (p = c)->next;
258 n = xmalloc (sizeof (mc_keyword));
259 n->next = c;
260 n->len = len;
261 n->group_name = grp;
262 n->usz = usz;
263 n->rid = rid;
264 n->nval = nv;
265 n->sval = (!sv ? NULL : unichar_dup (sv));
266 if (! strcmp (grp, "language"))
268 const wind_language_t *lag = wind_find_language_by_id ((unsigned) nv);
269 if (lag == NULL)
270 fatal ("Language ident 0x%lx is not resolvable.\n", (long) nv);
271 memcpy (&n->lang_info, lag, sizeof (*lag));
273 if (! p)
274 keyword_top = n;
275 else
276 p->next = n;
279 static int
280 mc_token (const unichar *t, size_t len)
282 static int was_init = 0;
283 mc_keyword *k;
285 if (! was_init)
287 was_init = 1;
288 mc_add_keyword_ascii ("OutputBase", MCOUTPUTBASE, "keyword", 0, NULL);
289 mc_add_keyword_ascii ("MessageIdTypedef", MCMESSAGEIDTYPEDEF, "keyword", 0, NULL);
290 mc_add_keyword_ascii ("SeverityNames", MCSEVERITYNAMES, "keyword", 0, NULL);
291 mc_add_keyword_ascii ("FacilityNames", MCFACILITYNAMES, "keyword", 0, NULL);
292 mc_add_keyword_ascii ("LanguageNames", MCLANGUAGENAMES, "keyword", 0, NULL);
293 mc_add_keyword_ascii ("MessageId", MCMESSAGEID, "keyword", 0, NULL);
294 mc_add_keyword_ascii ("Severity", MCSEVERITY, "keyword", 0, NULL);
295 mc_add_keyword_ascii ("Facility", MCFACILITY, "keyword", 0, NULL);
296 mc_add_keyword_ascii ("SymbolicName", MCSYMBOLICNAME, "keyword", 0, NULL);
297 mc_add_keyword_ascii ("Language", MCLANGUAGE, "keyword", 0, NULL);
298 mc_add_keyword_ascii ("Success", MCTOKEN, "severity", 0, NULL);
299 mc_add_keyword_ascii ("Informational", MCTOKEN, "severity", 1, NULL);
300 mc_add_keyword_ascii ("Warning", MCTOKEN, "severity", 2, NULL);
301 mc_add_keyword_ascii ("Error", MCTOKEN, "severity", 3, NULL);
302 mc_add_keyword_ascii ("System", MCTOKEN, "facility", 0xff, NULL);
303 mc_add_keyword_ascii ("Application", MCTOKEN, "facility", 0xfff, NULL);
304 mc_add_keyword_ascii ("English", MCTOKEN, "language", 0x409, "MSG00001");
306 k = keyword_top;
307 if (!len || !t || *t == 0)
308 return -1;
309 while (k != NULL)
311 if (k->len > len)
312 break;
313 if (k->len == len)
315 if (! memcmp (k->usz, t, len * sizeof (unichar)))
317 if (k->rid == MCTOKEN)
318 yylval.tok = k;
319 return k->rid;
322 k = k->next;
324 return -1;
328 yylex (void)
330 unichar *start_token;
331 unichar ch;
333 if (! input_stream_pos)
335 fatal ("Input stream not setuped.\n");
336 return -1;
338 if (mclex_want_line)
340 start_token = input_stream_pos;
341 if (input_stream_pos[0] == '.'
342 && (input_stream_pos[1] == '\n'
343 || (input_stream_pos[1] == '\r' && input_stream_pos[2] == '\n')))
345 mclex_want_line = FALSE;
346 while (input_stream_pos[0] != 0 && input_stream_pos[0] != '\n')
347 ++input_stream_pos;
348 if (input_stream_pos[0] == '\n')
349 ++input_stream_pos;
350 return MCENDLINE;
352 while (input_stream_pos[0] != 0 && input_stream_pos[0] != '\n')
353 ++input_stream_pos;
354 if (input_stream_pos[0] == '\n')
355 ++input_stream_pos;
356 yylval.ustr = get_diff (input_stream_pos, start_token);
357 return MCLINE;
359 while ((ch = input_stream_pos[0]) <= 0x20)
361 if (ch == 0)
362 return -1;
363 ++input_stream_pos;
364 if (ch == '\n')
365 input_line += 1;
366 if (mclex_want_nl && ch == '\n')
368 mclex_want_nl = FALSE;
369 return NL;
372 start_token = input_stream_pos;
373 ++input_stream_pos;
374 if (mclex_want_filename)
376 mclex_want_filename = FALSE;
377 if (ch == '"')
379 start_token++;
380 while ((ch = input_stream_pos[0]) != 0)
382 if (ch == '"')
383 break;
384 ++input_stream_pos;
386 yylval.ustr = get_diff (input_stream_pos, start_token);
387 if (ch == '"')
388 ++input_stream_pos;
390 else
392 while ((ch = input_stream_pos[0]) != 0)
394 if (ch <= 0x20 || ch == ')')
395 break;
396 ++input_stream_pos;
398 yylval.ustr = get_diff (input_stream_pos, start_token);
400 return MCFILENAME;
402 switch (ch)
404 case ';':
405 ++start_token;
406 while (input_stream_pos[0] != '\n' && input_stream_pos[0] != 0)
407 ++input_stream_pos;
408 if (input_stream_pos[0] == '\n')
409 input_stream_pos++;
410 yylval.ustr = get_diff (input_stream_pos, start_token);
411 return MCCOMMENT;
412 case '=':
413 return '=';
414 case '(':
415 return '(';
416 case ')':
417 return ')';
418 case '+':
419 return '+';
420 case ':':
421 return ':';
422 case '0': case '1': case '2': case '3': case '4':
423 case '5': case '6': case '7': case '8': case '9':
424 yylval.ival = parse_digit (ch);
425 return MCNUMBER;
426 default:
427 if (ch >= 0x40)
429 int ret;
430 while (input_stream_pos[0] >= 0x40 || (input_stream_pos[0] >= '0' && input_stream_pos[0] <= '9'))
431 ++input_stream_pos;
432 ret = mc_token (start_token, (size_t) (input_stream_pos - start_token));
433 if (ret != -1)
434 return ret;
435 yylval.ustr = get_diff (input_stream_pos, start_token);
436 return MCIDENT;
438 yyerror ("illegal character 0x%x.", ch);
440 return -1;