1 /* mclex.c -- lexer for Windows mc files parser.
2 Copyright (C) 2007-2022 Free Software Foundation, Inc.
4 Written by Kai Tietz, Onevision.
6 This file is part of GNU Binutils.
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
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
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.
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
23 /* This is a lexer used by the Windows rc file parser.
24 It basically just recognized a bunch of keywords. */
29 #include "libiberty.h"
30 #include "safe-ctype.h"
36 /* Exported globals. */
37 bool mclex_want_nl
= false;
38 bool mclex_want_line
= false;
39 bool mclex_want_filename
= false;
42 static unichar
*input_stream
= NULL
;
43 static unichar
*input_stream_pos
= NULL
;
44 static int input_line
= 1;
45 static const char *input_filename
= NULL
;
48 mc_set_content (const unichar
*src
)
52 input_stream
= input_stream_pos
= unichar_dup (src
);
56 mc_set_inputfile (const char *name
)
58 if (! name
|| *name
== 0)
62 const char *s1
= strrchr (name
, '/');
63 const char *s2
= strrchr (name
, '\\');
67 if (s1
&& s2
&& s1
< s2
)
79 show_msg (const char *kind
, const char *msg
, va_list argp
)
81 fprintf (stderr
, "In %s at line %d: %s: ", input_filename
, input_line
, kind
);
82 vfprintf (stderr
, msg
, argp
);
83 fprintf (stderr
, ".\n");
87 mc_warn (const char *s
, ...)
91 show_msg ("warning", s
, argp
);
96 mc_fatal (const char *s
, ...)
100 show_msg ("fatal", s
, argp
);
107 mc_error (const char *s
, ...)
111 show_msg ("parser", s
, argp
);
116 yyerror (const char *s
)
122 get_diff (unichar
*end
, unichar
*start
)
128 ret
= unichar_dup (start
);
134 parse_digit (unichar ch
)
136 rc_uint_type base
= 10, v
= 0, c
;
141 switch (input_stream_pos
[0])
143 case 'x': case 'X': base
= 16; input_stream_pos
++; break;
144 case 'o': case 'O': base
= 8; input_stream_pos
++; break;
145 case 'b': case 'B': base
= 2; input_stream_pos
++; break;
149 v
= (rc_uint_type
) (ch
- '0');
151 while ((ch
= input_stream_pos
[0]) != 0)
153 if (ch
>= 'A' && ch
<= 'F')
154 c
= (rc_uint_type
) (ch
- 'A') + 10;
155 else if (ch
>= 'a' && ch
<= 'f')
156 c
= (rc_uint_type
) (ch
- 'a') + 10;
157 else if (ch
>= '0' && ch
<= '9')
158 c
= (rc_uint_type
) (ch
- '0');
165 if (input_stream_pos
[0] == 'U' || input_stream_pos
[0] == 'u')
167 if (input_stream_pos
[0] == 'L' || input_stream_pos
[0] == 'l')
169 if (input_stream_pos
[0] == 'L' || input_stream_pos
[0] == 'l')
174 static mc_keyword
*keyword_top
= NULL
;
177 enum_facility (int e
)
179 mc_keyword
*h
= keyword_top
;
183 while (h
&& strcmp (h
->group_name
, "facility") != 0)
195 enum_severity (int e
)
197 mc_keyword
*h
= keyword_top
;
201 while (h
&& strcmp (h
->group_name
, "severity") != 0)
213 mc_add_keyword_ascii (const char *sz
, int rid
, const char *grp
, rc_uint_type nv
, const char *sv
)
215 unichar
*usz
, *usv
= NULL
;
216 rc_uint_type usz_len
;
218 unicode_from_codepage (&usz_len
, &usz
, sz
, CP_ACP
);
220 unicode_from_codepage (&usz_len
, &usv
, sv
, CP_ACP
);
221 mc_add_keyword (usz
, rid
, grp
, nv
, usv
);
225 mc_add_keyword (unichar
*usz
, int rid
, const char *grp
, rc_uint_type nv
, unichar
*sv
)
227 mc_keyword
*p
, *c
, *n
;
228 size_t len
= unichar_len (usz
);
238 int e
= memcmp (usz
, c
->usz
, len
* sizeof (unichar
));
244 if (! strcmp (grp
, "keyword") || strcmp (c
->group_name
, grp
) != 0)
245 fatal (_("Duplicate symbol entered into keyword list."));
248 c
->sval
= (!sv
? NULL
: unichar_dup (sv
));
249 if (! strcmp (grp
, "language"))
251 const wind_language_t
*lag
= wind_find_language_by_id ((unsigned) nv
);
254 fatal ("Language ident 0x%lx is not resolvable.\n", (long) nv
);
255 memcpy (&c
->lang_info
, lag
, sizeof (*lag
));
262 n
= xmalloc (sizeof (mc_keyword
));
269 n
->sval
= (!sv
? NULL
: unichar_dup (sv
));
270 if (! strcmp (grp
, "language"))
272 const wind_language_t
*lag
= wind_find_language_by_id ((unsigned) nv
);
274 fatal ("Language ident 0x%lx is not resolvable.\n", (long) nv
);
275 memcpy (&n
->lang_info
, lag
, sizeof (*lag
));
284 mc_token (const unichar
*t
, size_t len
)
286 static int was_init
= 0;
292 mc_add_keyword_ascii ("OutputBase", MCOUTPUTBASE
, "keyword", 0, NULL
);
293 mc_add_keyword_ascii ("MessageIdTypedef", MCMESSAGEIDTYPEDEF
, "keyword", 0, NULL
);
294 mc_add_keyword_ascii ("SeverityNames", MCSEVERITYNAMES
, "keyword", 0, NULL
);
295 mc_add_keyword_ascii ("FacilityNames", MCFACILITYNAMES
, "keyword", 0, NULL
);
296 mc_add_keyword_ascii ("LanguageNames", MCLANGUAGENAMES
, "keyword", 0, NULL
);
297 mc_add_keyword_ascii ("MessageId", MCMESSAGEID
, "keyword", 0, NULL
);
298 mc_add_keyword_ascii ("Severity", MCSEVERITY
, "keyword", 0, NULL
);
299 mc_add_keyword_ascii ("Facility", MCFACILITY
, "keyword", 0, NULL
);
300 mc_add_keyword_ascii ("SymbolicName", MCSYMBOLICNAME
, "keyword", 0, NULL
);
301 mc_add_keyword_ascii ("Language", MCLANGUAGE
, "keyword", 0, NULL
);
302 mc_add_keyword_ascii ("Success", MCTOKEN
, "severity", 0, NULL
);
303 mc_add_keyword_ascii ("Informational", MCTOKEN
, "severity", 1, NULL
);
304 mc_add_keyword_ascii ("Warning", MCTOKEN
, "severity", 2, NULL
);
305 mc_add_keyword_ascii ("Error", MCTOKEN
, "severity", 3, NULL
);
306 mc_add_keyword_ascii ("System", MCTOKEN
, "facility", 0xff, NULL
);
307 mc_add_keyword_ascii ("Application", MCTOKEN
, "facility", 0xfff, NULL
);
308 mc_add_keyword_ascii ("English", MCTOKEN
, "language", 0x409, "MSG00001");
311 if (!len
|| !t
|| *t
== 0)
319 if (! memcmp (k
->usz
, t
, len
* sizeof (unichar
)))
321 if (k
->rid
== MCTOKEN
)
331 /* Skip characters in input_stream_pos up to and including a newline
332 character. Returns non-zero if the newline was found, zero otherwise. */
335 skip_until_eol (void)
337 while (input_stream_pos
[0] != 0 && input_stream_pos
[0] != '\n')
339 if (input_stream_pos
[0] == 0)
341 if (input_stream_pos
[0] == '\n')
352 unichar
*start_token
;
355 if (! input_stream_pos
)
357 fatal ("Input stream not setuped.\n");
363 start_token
= input_stream_pos
;
364 if (input_stream_pos
[0] == 0)
366 /* PR 26082: Reject a period followed by EOF. */
367 if (input_stream_pos
[0] == '.' && input_stream_pos
[1] == 0)
369 if (input_stream_pos
[0] == '.'
370 && (input_stream_pos
[1] == '\n'
371 || (input_stream_pos
[1] == '\r' && input_stream_pos
[2] == '\n')))
373 mclex_want_line
= false;
374 return skip_until_eol () ? MCENDLINE
: -1;
376 if (!skip_until_eol ())
378 yylval
.ustr
= get_diff (input_stream_pos
, start_token
);
382 while ((ch
= input_stream_pos
[0]) <= 0x20)
389 if (mclex_want_nl
&& ch
== '\n')
391 mclex_want_nl
= false;
395 start_token
= input_stream_pos
;
397 if (mclex_want_filename
)
399 mclex_want_filename
= false;
403 while ((ch
= input_stream_pos
[0]) != 0)
409 yylval
.ustr
= get_diff (input_stream_pos
, start_token
);
415 while ((ch
= input_stream_pos
[0]) != 0)
417 if (ch
<= 0x20 || ch
== ')')
421 yylval
.ustr
= get_diff (input_stream_pos
, start_token
);
429 if (!skip_until_eol ())
431 yylval
.ustr
= get_diff (input_stream_pos
, start_token
);
443 case '0': case '1': case '2': case '3': case '4':
444 case '5': case '6': case '7': case '8': case '9':
445 yylval
.ival
= parse_digit (ch
);
451 while (input_stream_pos
[0] >= 0x40 || (input_stream_pos
[0] >= '0' && input_stream_pos
[0] <= '9'))
453 ret
= mc_token (start_token
, (size_t) (input_stream_pos
- start_token
));
456 yylval
.ustr
= get_diff (input_stream_pos
, start_token
);
459 mc_error ("illegal character 0x%x.", ch
);