%{ /* 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 . */ #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 MCIDENT MCFILENAME MCLINE MCCOMMENT %token MCTOKEN %token MCENDLINE %token MCLANGUAGENAMES MCFACILITYNAMES MCSEVERITYNAMES MCOUTPUTBASE MCMESSAGEIDTYPEDEF %token MCLANGUAGE MCMESSAGEID MCSEVERITY MCFACILITY MCSYMBOLICNAME %token MCNUMBER %type id vid sefasy_def %type alias_name token lines comments %type 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. */