Change regcache list to be an hash map
[deliverable/binutils-gdb.git] / binutils / mclex.c
CommitLineData
692ed3e7 1/* mclex.c -- lexer for Windows mc files parser.
b3adc24a 2 Copyright (C) 2007-2020 Free Software Foundation, Inc.
692ed3e7
NC
3
4 Written by Kai Tietz, Onevision.
5
6 This file is part of GNU Binutils.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
32866df7 10 the Free Software Foundation; either version 3 of the License, or
692ed3e7
NC
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
21 02110-1301, USA. */
22
23/* This is a lexer used by the Windows rc file parser.
24 It basically just recognized a bunch of keywords. */
25
26#include "sysdep.h"
27#include "bfd.h"
28#include "bucomm.h"
29#include "libiberty.h"
30#include "safe-ctype.h"
31#include "windmc.h"
32#include "mcparse.h"
33
34#include <assert.h>
35
36/* Exported globals. */
37bfd_boolean mclex_want_nl = FALSE;
38bfd_boolean mclex_want_line = FALSE;
39bfd_boolean mclex_want_filename = FALSE;
40
41/* Local globals. */
42static unichar *input_stream = NULL;
43static unichar *input_stream_pos = NULL;
44static int input_line = 1;
45static const char *input_filename = NULL;
46
47void
48mc_set_content (const unichar *src)
49{
50 if (!src)
51 return;
52 input_stream = input_stream_pos = unichar_dup (src);
53}
54
55void
56mc_set_inputfile (const char *name)
57{
58 if (! name || *name == 0)
59 input_filename = "-";
60 else
61 {
62 const char *s1 = strrchr (name, '/');
63 const char *s2 = strrchr (name, '\\');
64
65 if (! s1)
66 s1 = s2;
67 if (s1 && s2 && s1 < s2)
68 s1 = s2;
69 if (! s1)
70 s1 = name;
71 else
72 s1++;
73 s1 = xstrdup (s1);
74 input_filename = s1;
75 }
76}
77
78static void
79show_msg (const char *kind, const char *msg, va_list argp)
80{
81 fprintf (stderr, "In %s at line %d: %s: ", input_filename, input_line, kind);
82 vfprintf (stderr, msg, argp);
83 fprintf (stderr, ".\n");
84}
85
86void
87mc_warn (const char *s, ...)
88{
89 va_list argp;
90 va_start (argp, s);
91 show_msg ("warning", s, argp);
92 va_end (argp);
93}
94
95void
96mc_fatal (const char *s, ...)
97{
98 va_list argp;
99 va_start (argp, s);
100 show_msg ("fatal", s, argp);
101 va_end (argp);
102 xexit (1);
103}
104
105
106int
107yyerror (const char *s, ...)
108{
109 va_list argp;
110 va_start (argp, s);
111 show_msg ("parser", s, argp);
112 va_end (argp);
113 return 1;
114}
115
116static unichar *
117get_diff (unichar *end, unichar *start)
118{
119 unichar *ret;
120 unichar save = *end;
121
122 *end = 0;
123 ret = unichar_dup (start);
124 *end = save;
125 return ret;
126}
127
128static rc_uint_type
129parse_digit (unichar ch)
130{
131 rc_uint_type base = 10, v = 0, c;
132
133 if (ch == '0')
134 {
135 base = 8;
136 switch (input_stream_pos[0])
137 {
138 case 'x': case 'X': base = 16; input_stream_pos++; break;
139 case 'o': case 'O': base = 8; input_stream_pos++; break;
140 case 'b': case 'B': base = 2; input_stream_pos++; break;
141 }
142 }
143 else
144 v = (rc_uint_type) (ch - '0');
145
146 while ((ch = input_stream_pos[0]) != 0)
147 {
148 if (ch >= 'A' && ch <= 'F')
149 c = (rc_uint_type) (ch - 'A') + 10;
150 else if (ch >= 'a' && ch <= 'f')
151 c = (rc_uint_type) (ch - 'a') + 10;
152 else if (ch >= '0' && ch <= '9')
153 c = (rc_uint_type) (ch - '0');
154 else
155 break;
156 v *= base;
157 v += c;
158 ++input_stream_pos;
159 }
160 if (input_stream_pos[0] == 'U' || input_stream_pos[0] == 'u')
161 input_stream_pos++;
162 if (input_stream_pos[0] == 'L' || input_stream_pos[0] == 'l')
163 input_stream_pos++;
164 if (input_stream_pos[0] == 'L' || input_stream_pos[0] == 'l')
165 input_stream_pos++;
166 return v;
167}
168
169static mc_keyword *keyword_top = NULL;
170
171const mc_keyword *
172enum_facility (int e)
173{
174 mc_keyword *h = keyword_top;
175
176 while (h != NULL)
177 {
178 while (h && strcmp (h->group_name, "facility") != 0)
179 h = h->next;
180 if (e == 0)
181 return h;
182 --e;
183 if (h)
184 h = h->next;
185 }
186 return h;
187}
188
189const mc_keyword *
190enum_severity (int e)
191{
192 mc_keyword *h = keyword_top;
193
194 while (h != NULL)
195 {
196 while (h && strcmp (h->group_name, "severity") != 0)
197 h = h->next;
198 if (e == 0)
199 return h;
200 --e;
201 if (h)
202 h = h->next;
203 }
204 return h;
205}
206
207static void
208mc_add_keyword_ascii (const char *sz, int rid, const char *grp, rc_uint_type nv, const char *sv)
209{
210 unichar *usz, *usv = NULL;
211 rc_uint_type usz_len;
212
213 unicode_from_codepage (&usz_len, &usz, sz, CP_ACP);
214 if (sv)
215 unicode_from_codepage (&usz_len, &usv, sv, CP_ACP);
216 mc_add_keyword (usz, rid, grp, nv, usv);
217}
218
219void
220mc_add_keyword (unichar *usz, int rid, const char *grp, rc_uint_type nv, unichar *sv)
221{
222 mc_keyword *p, *c, *n;
223 size_t len = unichar_len (usz);
224
225 c = keyword_top;
226 p = NULL;
227 while (c != NULL)
228 {
229 if (c->len > len)
230 break;
231 if (c->len == len)
232 {
233 int e = memcmp (usz, c->usz, len * sizeof (unichar));
234
235 if (e < 0)
236 break;
237 if (! e)
238 {
239 if (! strcmp (grp, "keyword") || strcmp (c->group_name, grp) != 0)
240 fatal (_("Duplicate symbol entered into keyword list."));
241 c->rid = rid;
242 c->nval = nv;
243 c->sval = (!sv ? NULL : unichar_dup (sv));
244 if (! strcmp (grp, "language"))
245 {
246 const wind_language_t *lag = wind_find_language_by_id ((unsigned) nv);
247
248 if (lag == NULL)
249 fatal ("Language ident 0x%lx is not resolvable.\n", (long) nv);
250 memcpy (&c->lang_info, lag, sizeof (*lag));
251 }
252 return;
253 }
254 }
255 c = (p = c)->next;
256 }
257 n = xmalloc (sizeof (mc_keyword));
258 n->next = c;
259 n->len = len;
260 n->group_name = grp;
261 n->usz = usz;
262 n->rid = rid;
263 n->nval = nv;
264 n->sval = (!sv ? NULL : unichar_dup (sv));
265 if (! strcmp (grp, "language"))
266 {
267 const wind_language_t *lag = wind_find_language_by_id ((unsigned) nv);
268 if (lag == NULL)
269 fatal ("Language ident 0x%lx is not resolvable.\n", (long) nv);
270 memcpy (&n->lang_info, lag, sizeof (*lag));
271 }
272 if (! p)
273 keyword_top = n;
274 else
275 p->next = n;
276}
277
278static int
279mc_token (const unichar *t, size_t len)
280{
281 static int was_init = 0;
282 mc_keyword *k;
283
284 if (! was_init)
285 {
286 was_init = 1;
287 mc_add_keyword_ascii ("OutputBase", MCOUTPUTBASE, "keyword", 0, NULL);
288 mc_add_keyword_ascii ("MessageIdTypedef", MCMESSAGEIDTYPEDEF, "keyword", 0, NULL);
289 mc_add_keyword_ascii ("SeverityNames", MCSEVERITYNAMES, "keyword", 0, NULL);
290 mc_add_keyword_ascii ("FacilityNames", MCFACILITYNAMES, "keyword", 0, NULL);
291 mc_add_keyword_ascii ("LanguageNames", MCLANGUAGENAMES, "keyword", 0, NULL);
292 mc_add_keyword_ascii ("MessageId", MCMESSAGEID, "keyword", 0, NULL);
293 mc_add_keyword_ascii ("Severity", MCSEVERITY, "keyword", 0, NULL);
294 mc_add_keyword_ascii ("Facility", MCFACILITY, "keyword", 0, NULL);
295 mc_add_keyword_ascii ("SymbolicName", MCSYMBOLICNAME, "keyword", 0, NULL);
296 mc_add_keyword_ascii ("Language", MCLANGUAGE, "keyword", 0, NULL);
297 mc_add_keyword_ascii ("Success", MCTOKEN, "severity", 0, NULL);
298 mc_add_keyword_ascii ("Informational", MCTOKEN, "severity", 1, NULL);
299 mc_add_keyword_ascii ("Warning", MCTOKEN, "severity", 2, NULL);
300 mc_add_keyword_ascii ("Error", MCTOKEN, "severity", 3, NULL);
301 mc_add_keyword_ascii ("System", MCTOKEN, "facility", 0xff, NULL);
302 mc_add_keyword_ascii ("Application", MCTOKEN, "facility", 0xfff, NULL);
303 mc_add_keyword_ascii ("English", MCTOKEN, "language", 0x409, "MSG00001");
304 }
305 k = keyword_top;
306 if (!len || !t || *t == 0)
307 return -1;
308 while (k != NULL)
309 {
310 if (k->len > len)
311 break;
312 if (k->len == len)
313 {
314 if (! memcmp (k->usz, t, len * sizeof (unichar)))
315 {
316 if (k->rid == MCTOKEN)
317 yylval.tok = k;
318 return k->rid;
319 }
320 }
321 k = k->next;
322 }
323 return -1;
324}
325
25065fcd
RH
326/* Skip characters in input_stream_pos up to and including a newline
327 character. Returns non-zero if the newline was found, zero otherwise. */
328
329static int
330skip_until_eol (void)
331{
332 while (input_stream_pos[0] != 0 && input_stream_pos[0] != '\n')
333 ++input_stream_pos;
334 if (input_stream_pos[0] == 0)
335 return 0;
336 if (input_stream_pos[0] == '\n')
337 ++input_stream_pos;
338 return 1;
339}
340
692ed3e7
NC
341int
342yylex (void)
343{
344 unichar *start_token;
345 unichar ch;
346
347 if (! input_stream_pos)
348 {
349 fatal ("Input stream not setuped.\n");
350 return -1;
351 }
25065fcd 352
692ed3e7
NC
353 if (mclex_want_line)
354 {
355 start_token = input_stream_pos;
8affa48a
JA
356 if (input_stream_pos[0] == 0)
357 return -1;
25065fcd
RH
358 /* PR 26082: Reject a period followed by EOF. */
359 if (input_stream_pos[0] == '.' && input_stream_pos[1] == 0)
360 return -1;
692ed3e7
NC
361 if (input_stream_pos[0] == '.'
362 && (input_stream_pos[1] == '\n'
363 || (input_stream_pos[1] == '\r' && input_stream_pos[2] == '\n')))
8affa48a
JA
364 {
365 mclex_want_line = FALSE;
25065fcd 366 return skip_until_eol () ? MCENDLINE : -1;
8affa48a 367 }
25065fcd
RH
368 if (!skip_until_eol ())
369 return -1;
692ed3e7
NC
370 yylval.ustr = get_diff (input_stream_pos, start_token);
371 return MCLINE;
372 }
25065fcd 373
692ed3e7
NC
374 while ((ch = input_stream_pos[0]) <= 0x20)
375 {
376 if (ch == 0)
377 return -1;
378 ++input_stream_pos;
379 if (ch == '\n')
380 input_line += 1;
381 if (mclex_want_nl && ch == '\n')
382 {
383 mclex_want_nl = FALSE;
384 return NL;
385 }
386 }
387 start_token = input_stream_pos;
388 ++input_stream_pos;
389 if (mclex_want_filename)
390 {
391 mclex_want_filename = FALSE;
392 if (ch == '"')
393 {
394 start_token++;
395 while ((ch = input_stream_pos[0]) != 0)
396 {
397 if (ch == '"')
398 break;
399 ++input_stream_pos;
400 }
401 yylval.ustr = get_diff (input_stream_pos, start_token);
402 if (ch == '"')
403 ++input_stream_pos;
404 }
405 else
406 {
407 while ((ch = input_stream_pos[0]) != 0)
408 {
409 if (ch <= 0x20 || ch == ')')
410 break;
411 ++input_stream_pos;
412 }
413 yylval.ustr = get_diff (input_stream_pos, start_token);
414 }
415 return MCFILENAME;
416 }
417 switch (ch)
418 {
419 case ';':
420 ++start_token;
25065fcd
RH
421 if (!skip_until_eol ())
422 return -1;
692ed3e7
NC
423 yylval.ustr = get_diff (input_stream_pos, start_token);
424 return MCCOMMENT;
425 case '=':
426 return '=';
427 case '(':
428 return '(';
429 case ')':
430 return ')';
431 case '+':
432 return '+';
433 case ':':
434 return ':';
435 case '0': case '1': case '2': case '3': case '4':
436 case '5': case '6': case '7': case '8': case '9':
437 yylval.ival = parse_digit (ch);
438 return MCNUMBER;
439 default:
440 if (ch >= 0x40)
441 {
442 int ret;
443 while (input_stream_pos[0] >= 0x40 || (input_stream_pos[0] >= '0' && input_stream_pos[0] <= '9'))
444 ++input_stream_pos;
445 ret = mc_token (start_token, (size_t) (input_stream_pos - start_token));
446 if (ret != -1)
447 return ret;
448 yylval.ustr = get_diff (input_stream_pos, start_token);
449 return MCIDENT;
450 }
451 yyerror ("illegal character 0x%x.", ch);
452 }
453 return -1;
454}
This page took 0.49937 seconds and 4 git commands to generate.