| %{ /* mcparse.y -- parser for Windows mc files | |
| Copyright (C) 2007-2023 Free Software Foundation, Inc. | |
| Parser for Windows mc files | |
| Written by Kai Tietz, Onevision. | |
| This file is part of GNU Binutils. | |
| This program is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 3 of the License, or | |
| (at your option) any later version. | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with this program; if not, write to the Free Software | |
| Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA | |
| 02110-1301, USA. */ | |
| /* This is a parser for Windows rc files. It is based on the parser | |
| by Gunther Ebert <gunther.ebert@ixos-leipzig.de>. */ | |
| #include "sysdep.h" | |
| #include "bfd.h" | |
| #include "bucomm.h" | |
| #include "libiberty.h" | |
| #include "windmc.h" | |
| #include "safe-ctype.h" | |
| static rc_uint_type mc_last_id = 0; | |
| static rc_uint_type mc_sefa_val = 0; | |
| static unichar *mc_last_symbol = NULL; | |
| static const mc_keyword *mc_cur_severity = NULL; | |
| static const mc_keyword *mc_cur_facility = NULL; | |
| static mc_node *cur_node = NULL; | |
| %} | |
| %union | |
| { | |
| rc_uint_type ival; | |
| unichar *ustr; | |
| const mc_keyword *tok; | |
| mc_node *nod; | |
| }; | |
| %start input | |
| %token NL | |
| %token<ustr> MCIDENT MCFILENAME MCLINE MCCOMMENT | |
| %token<tok> MCTOKEN | |
| %token MCENDLINE | |
| %token MCLANGUAGENAMES MCFACILITYNAMES MCSEVERITYNAMES MCOUTPUTBASE MCMESSAGEIDTYPEDEF | |
| %token MCLANGUAGE MCMESSAGEID MCSEVERITY MCFACILITY MCSYMBOLICNAME | |
| %token <ival> MCNUMBER | |
| %type<ival> id vid sefasy_def | |
| %type<ustr> alias_name token lines comments | |
| %type<tok> lang | |
| %% | |
| input: entities | |
| ; | |
| entities: | |
| /* empty */ | |
| | entities entity | |
| ; | |
| entity: global_section | |
| | message | |
| | comments | |
| { | |
| cur_node = mc_add_node (); | |
| cur_node->user_text = $1; | |
| } | |
| | error { mc_fatal ("syntax error"); } | |
| ; | |
| global_section: | |
| MCSEVERITYNAMES '=' '(' severitymaps ')' | |
| | MCSEVERITYNAMES '=' '(' severitymaps error { mc_fatal ("missing ')' in SeverityNames"); } | |
| | MCSEVERITYNAMES '=' error { mc_fatal ("missing '(' in SeverityNames"); } | |
| | MCSEVERITYNAMES error { mc_fatal ("missing '=' for SeverityNames"); } | |
| | MCLANGUAGENAMES '=' '(' langmaps ')' | |
| | MCLANGUAGENAMES '=' '(' langmaps error { mc_fatal ("missing ')' in LanguageNames"); } | |
| | MCLANGUAGENAMES '=' error { mc_fatal ("missing '(' in LanguageNames"); } | |
| | MCLANGUAGENAMES error { mc_fatal ("missing '=' for LanguageNames"); } | |
| | MCFACILITYNAMES '=' '(' facilitymaps ')' | |
| | MCFACILITYNAMES '=' '(' facilitymaps error { mc_fatal ("missing ')' in FacilityNames"); } | |
| | MCFACILITYNAMES '=' error { mc_fatal ("missing '(' in FacilityNames"); } | |
| | MCFACILITYNAMES error { mc_fatal ("missing '=' for FacilityNames"); } | |
| | MCOUTPUTBASE '=' MCNUMBER | |
| { | |
| if ($3 != 10 && $3 != 16) | |
| mc_fatal ("OutputBase allows 10 or 16 as value"); | |
| mcset_out_values_are_decimal = ($3 == 10 ? 1 : 0); | |
| } | |
| | MCMESSAGEIDTYPEDEF '=' MCIDENT | |
| { | |
| mcset_msg_id_typedef = $3; | |
| } | |
| | MCMESSAGEIDTYPEDEF '=' error | |
| { | |
| mc_fatal ("MessageIdTypedef expects an identifier"); | |
| } | |
| | MCMESSAGEIDTYPEDEF error | |
| { | |
| mc_fatal ("missing '=' for MessageIdTypedef"); | |
| } | |
| ; | |
| severitymaps: | |
| severitymap | |
| | severitymaps severitymap | |
| | error { mc_fatal ("severity ident missing"); } | |
| ; | |
| severitymap: | |
| token '=' MCNUMBER alias_name | |
| { | |
| mc_add_keyword ($1, MCTOKEN, "severity", $3, $4); | |
| } | |
| | token '=' error { mc_fatal ("severity number missing"); } | |
| | token error { mc_fatal ("severity missing '='"); } | |
| ; | |
| facilitymaps: | |
| facilitymap | |
| | facilitymaps facilitymap | |
| | error { mc_fatal ("missing ident in FacilityNames"); } | |
| ; | |
| facilitymap: | |
| token '=' MCNUMBER alias_name | |
| { | |
| mc_add_keyword ($1, MCTOKEN, "facility", $3, $4); | |
| } | |
| | token '=' error { mc_fatal ("facility number missing"); } | |
| | token error { mc_fatal ("facility missing '='"); } | |
| ; | |
| langmaps: | |
| langmap | |
| | langmaps langmap | |
| | error { mc_fatal ("missing ident in LanguageNames"); } | |
| ; | |
| langmap: | |
| token '=' MCNUMBER lex_want_filename ':' MCFILENAME | |
| { | |
| mc_add_keyword ($1, MCTOKEN, "language", $3, $6); | |
| } | |
| | token '=' MCNUMBER lex_want_filename ':' error { mc_fatal ("missing filename in LanguageNames"); } | |
| | token '=' MCNUMBER error { mc_fatal ("missing ':' in LanguageNames"); } | |
| | token '=' error { mc_fatal ("missing language code in LanguageNames"); } | |
| | token error { mc_fatal ("missing '=' for LanguageNames"); } | |
| ; | |
| alias_name: | |
| /* empty */ | |
| { | |
| $$ = NULL; | |
| } | |
| | ':' MCIDENT | |
| { | |
| $$ = $2; | |
| } | |
| | ':' error { mc_fatal ("illegal token in identifier"); $$ = NULL; } | |
| ; | |
| message: | |
| id sefasy_def | |
| { | |
| cur_node = mc_add_node (); | |
| cur_node->symbol = mc_last_symbol; | |
| cur_node->facility = mc_cur_facility; | |
| cur_node->severity = mc_cur_severity; | |
| cur_node->id = ($1 & 0xffffUL); | |
| cur_node->vid = ($1 & 0xffffUL) | mc_sefa_val; | |
| cur_node->id_typecast = mcset_msg_id_typedef; | |
| mc_last_id = $1; | |
| } | |
| lang_entities | |
| ; | |
| id: MCMESSAGEID '=' vid { $$ = $3; } | |
| | MCMESSAGEID '=' error { mc_fatal ("missing number in MessageId"); $$ = 0; } | |
| | MCMESSAGEID error { mc_fatal ("missing '=' for MessageId"); $$ = 0; } | |
| ; | |
| vid: /* empty */ | |
| { | |
| $$ = ++mc_last_id; | |
| } | |
| | MCNUMBER | |
| { | |
| $$ = $1; | |
| } | |
| | '+' MCNUMBER | |
| { | |
| $$ = mc_last_id + $2; | |
| } | |
| | '+' error { mc_fatal ("missing number after MessageId '+'"); } | |
| ; | |
| sefasy_def: | |
| /* empty */ | |
| { | |
| $$ = 0; | |
| mc_sefa_val = (mcset_custom_bit ? 1 : 0) << 29; | |
| mc_last_symbol = NULL; | |
| mc_cur_severity = NULL; | |
| mc_cur_facility = NULL; | |
| } | |
| | sefasy_def severity | |
| { | |
| if ($1 & 1) | |
| mc_warn (_("duplicate definition of Severity")); | |
| $$ = $1 | 1; | |
| } | |
| | sefasy_def facility | |
| { | |
| if ($1 & 2) | |
| mc_warn (_("duplicate definition of Facility")); | |
| $$ = $1 | 2; | |
| } | |
| | sefasy_def symbol | |
| { | |
| if ($1 & 4) | |
| mc_warn (_("duplicate definition of SymbolicName")); | |
| $$ = $1 | 4; | |
| } | |
| ; | |
| severity: MCSEVERITY '=' MCTOKEN | |
| { | |
| mc_sefa_val &= ~ (0x3UL << 30); | |
| mc_sefa_val |= (($3->nval & 0x3UL) << 30); | |
| mc_cur_severity = $3; | |
| } | |
| ; | |
| facility: MCFACILITY '=' MCTOKEN | |
| { | |
| mc_sefa_val &= ~ (0xfffUL << 16); | |
| mc_sefa_val |= (($3->nval & 0xfffUL) << 16); | |
| mc_cur_facility = $3; | |
| } | |
| ; | |
| symbol: MCSYMBOLICNAME '=' MCIDENT | |
| { | |
| mc_last_symbol = $3; | |
| } | |
| ; | |
| lang_entities: | |
| lang_entity | |
| | lang_entities lang_entity | |
| ; | |
| lang_entity: | |
| lang lex_want_line lines MCENDLINE | |
| { | |
| mc_node_lang *h; | |
| h = mc_add_node_lang (cur_node, $1, cur_node->vid); | |
| h->message = $3; | |
| if (mcset_max_message_length != 0 && unichar_len (h->message) > mcset_max_message_length) | |
| mc_warn ("message length to long"); | |
| } | |
| ; | |
| lines: MCLINE | |
| { | |
| $$ = $1; | |
| } | |
| | lines MCLINE | |
| { | |
| unichar *h; | |
| rc_uint_type l1,l2; | |
| l1 = unichar_len ($1); | |
| l2 = unichar_len ($2); | |
| h = (unichar *) res_alloc ((l1 + l2 + 1) * sizeof (unichar)); | |
| if (l1) memcpy (h, $1, l1 * sizeof (unichar)); | |
| if (l2) memcpy (&h[l1], $2, l2 * sizeof (unichar)); | |
| h[l1 + l2] = 0; | |
| $$ = h; | |
| } | |
| | error { mc_fatal ("missing end of message text"); $$ = NULL; } | |
| | lines error { mc_fatal ("missing end of message text"); $$ = $1; } | |
| ; | |
| comments: MCCOMMENT { $$ = $1; } | |
| | comments MCCOMMENT | |
| { | |
| unichar *h; | |
| rc_uint_type l1,l2; | |
| l1 = unichar_len ($1); | |
| l2 = unichar_len ($2); | |
| h = (unichar *) res_alloc ((l1 + l2 + 1) * sizeof (unichar)); | |
| if (l1) memcpy (h, $1, l1 * sizeof (unichar)); | |
| if (l2) memcpy (&h[l1], $2, l2 * sizeof (unichar)); | |
| h[l1 + l2] = 0; | |
| $$ = h; | |
| } | |
| ; | |
| lang: MCLANGUAGE lex_want_nl '=' MCTOKEN NL | |
| { | |
| $$ = $4; | |
| } | |
| | MCLANGUAGE lex_want_nl '=' MCIDENT NL | |
| { | |
| $$ = NULL; | |
| mc_fatal (_("undeclared language identifier")); | |
| } | |
| | MCLANGUAGE lex_want_nl '=' token error | |
| { | |
| $$ = NULL; | |
| mc_fatal ("missing newline after Language"); | |
| } | |
| | MCLANGUAGE lex_want_nl '=' error | |
| { | |
| $$ = NULL; | |
| mc_fatal ("missing ident for Language"); | |
| } | |
| | MCLANGUAGE error | |
| { | |
| $$ = NULL; | |
| mc_fatal ("missing '=' for Language"); | |
| } | |
| ; | |
| token: MCIDENT { $$ = $1; } | |
| | MCTOKEN { $$ = $1->usz; } | |
| ; | |
| lex_want_nl: | |
| /* Empty */ { mclex_want_nl = 1; } | |
| ; | |
| lex_want_line: | |
| /* Empty */ { mclex_want_line = 1; } | |
| ; | |
| lex_want_filename: | |
| /* Empty */ { mclex_want_filename = 1; } | |
| ; | |
| %% | |
| /* Something else. */ |