1214571Sdim%{ /* mcparse.y -- parser for Windows mc files
2214571Sdim  Copyright 2007
3214571Sdim  Free Software Foundation, Inc.
4214571Sdim
5214571Sdim  Parser for Windows mc files
6214571Sdim  Written by Kai Tietz, Onevision.
7214571Sdim
8214571Sdim  This file is part of GNU Binutils.
9214571Sdim
10214571Sdim  This program is free software; you can redistribute it and/or modify
11214571Sdim  it under the terms of the GNU General Public License as published by
12214571Sdim  the Free Software Foundation; either version 2 of the License, or
13214571Sdim  (at your option) any later version.
14214571Sdim
15214571Sdim  This program is distributed in the hope that it will be useful,
16214571Sdim  but WITHOUT ANY WARRANTY; without even the implied warranty of
17214571Sdim  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18214571Sdim  GNU General Public License for more details.
19214571Sdim
20214571Sdim  You should have received a copy of the GNU General Public License
21214571Sdim  along with this program; if not, write to the Free Software
22214571Sdim  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
23214571Sdim  02110-1301, USA.  */
24214571Sdim
25214571Sdim/* This is a parser for Windows rc files.  It is based on the parser
26214571Sdim   by Gunther Ebert <gunther.ebert@ixos-leipzig.de>.  */
27214571Sdim
28214571Sdim#include "sysdep.h"
29214571Sdim#include "bfd.h"
30214571Sdim#include "bucomm.h"
31214571Sdim#include "libiberty.h"
32214571Sdim#include "windmc.h"
33214571Sdim#include "safe-ctype.h"
34214571Sdim
35214571Sdimstatic rc_uint_type mc_last_id = 0;
36214571Sdimstatic rc_uint_type mc_sefa_val = 0;
37214571Sdimstatic unichar *mc_last_symbol = NULL;
38214571Sdimstatic const mc_keyword *mc_cur_severity = NULL;
39214571Sdimstatic const mc_keyword *mc_cur_facility = NULL;
40214571Sdimstatic mc_node *cur_node = NULL;
41214571Sdim
42214571Sdim%}
43214571Sdim
44214571Sdim%union
45214571Sdim{
46214571Sdim  rc_uint_type ival;
47214571Sdim  unichar *ustr;
48214571Sdim  const mc_keyword *tok;
49214571Sdim  mc_node *nod;
50214571Sdim};
51214571Sdim
52214571Sdim%start input
53214571Sdim
54214571Sdim%token NL
55214571Sdim%token<ustr> MCIDENT MCFILENAME MCLINE MCCOMMENT
56214571Sdim%token<tok> MCTOKEN
57214571Sdim%token MCENDLINE
58214571Sdim%token MCLANGUAGENAMES MCFACILITYNAMES MCSEVERITYNAMES MCOUTPUTBASE MCMESSAGEIDTYPEDEF
59214571Sdim%token MCLANGUAGE MCMESSAGEID MCSEVERITY MCFACILITY MCSYMBOLICNAME
60214571Sdim%token <ival> MCNUMBER
61214571Sdim
62214571Sdim%type<ival> id vid sefasy_def
63214571Sdim%type<ustr> alias_name token lines comments
64214571Sdim%type<tok> lang
65214571Sdim
66214571Sdim%%
67214571Sdiminput:	  entities
68214571Sdim	;
69214571Sdim
70214571Sdimentities:
71214571Sdim	  /* empty */
72214571Sdim	| entities entity
73214571Sdim	;
74214571Sdimentity:	  global_section
75214571Sdim	| message
76214571Sdim	| comments
77214571Sdim	  {
78214571Sdim	    cur_node = mc_add_node ();
79214571Sdim	    cur_node->user_text = $1;
80214571Sdim	  }
81214571Sdim	| error	{ mc_fatal ("syntax error"); }
82214571Sdim;
83214571Sdim
84214571Sdimglobal_section:
85214571Sdim	  MCSEVERITYNAMES '=' '(' severitymaps ')'
86214571Sdim	| MCSEVERITYNAMES '=' '(' severitymaps error { mc_fatal ("missing ')' in SeverityNames"); }
87214571Sdim	| MCSEVERITYNAMES '=' error { mc_fatal ("missing '(' in SeverityNames"); }
88214571Sdim	| MCSEVERITYNAMES error { mc_fatal ("missing '=' for SeverityNames"); }
89214571Sdim	| MCLANGUAGENAMES '=' '(' langmaps ')'
90214571Sdim	| MCLANGUAGENAMES '=' '(' langmaps error { mc_fatal ("missing ')' in LanguageNames"); }
91214571Sdim	| MCLANGUAGENAMES '=' error { mc_fatal ("missing '(' in LanguageNames"); }
92214571Sdim	| MCLANGUAGENAMES error { mc_fatal ("missing '=' for LanguageNames"); }
93214571Sdim	| MCFACILITYNAMES '=' '(' facilitymaps ')'
94214571Sdim	| MCFACILITYNAMES '=' '(' facilitymaps error { mc_fatal ("missing ')' in FacilityNames"); }
95214571Sdim	| MCFACILITYNAMES '=' error { mc_fatal ("missing '(' in FacilityNames"); }
96214571Sdim	| MCFACILITYNAMES error { mc_fatal ("missing '=' for FacilityNames"); }
97214571Sdim	| MCOUTPUTBASE '=' MCNUMBER
98214571Sdim	  {
99214571Sdim	    if ($3 != 10 && $3 != 16)
100214571Sdim	      mc_fatal ("OutputBase allows 10 or 16 as value");
101214571Sdim	    mcset_out_values_are_decimal = ($3 == 10 ? 1 : 0);
102214571Sdim	  }
103214571Sdim	| MCMESSAGEIDTYPEDEF '=' MCIDENT
104214571Sdim	  {
105214571Sdim	    mcset_msg_id_typedef = $3;
106214571Sdim	  }
107214571Sdim	| MCMESSAGEIDTYPEDEF '=' error
108214571Sdim	  {
109214571Sdim	    mc_fatal ("MessageIdTypedef expects an identifier");
110214571Sdim	  }
111214571Sdim	| MCMESSAGEIDTYPEDEF error
112214571Sdim	  {
113214571Sdim	    mc_fatal ("missing '=' for MessageIdTypedef");
114214571Sdim	  }
115214571Sdim;
116214571Sdim
117214571Sdimseveritymaps:
118214571Sdim	  severitymap
119214571Sdim	| severitymaps severitymap
120214571Sdim	| error { mc_fatal ("severity ident missing"); }
121214571Sdim;
122214571Sdim
123214571Sdimseveritymap:
124214571Sdim	  token '=' MCNUMBER alias_name
125214571Sdim	  {
126214571Sdim	    mc_add_keyword ($1, MCTOKEN, "severity", $3, $4);
127214571Sdim	  }
128214571Sdim	| token '=' error { mc_fatal ("severity number missing"); }
129214571Sdim	| token error { mc_fatal ("severity missing '='"); }
130214571Sdim;
131214571Sdim
132214571Sdimfacilitymaps:
133214571Sdim	  facilitymap
134214571Sdim	| facilitymaps facilitymap
135214571Sdim	| error { mc_fatal ("missing ident in FacilityNames"); }
136214571Sdim;
137214571Sdim
138214571Sdimfacilitymap:
139214571Sdim	  token '=' MCNUMBER alias_name
140214571Sdim	  {
141214571Sdim	    mc_add_keyword ($1, MCTOKEN, "facility", $3, $4);
142214571Sdim	  }
143214571Sdim	| token '=' error { mc_fatal ("facility number missing"); }
144214571Sdim	| token error { mc_fatal ("facility missing '='"); }
145214571Sdim;
146214571Sdim
147214571Sdimlangmaps:
148214571Sdim	  langmap
149214571Sdim	| langmaps langmap
150214571Sdim	| error { mc_fatal ("missing ident in LanguageNames"); }
151214571Sdim;
152214571Sdim
153214571Sdimlangmap:
154214571Sdim	  token '=' MCNUMBER lex_want_filename ':' MCFILENAME
155214571Sdim	  {
156214571Sdim	    mc_add_keyword ($1, MCTOKEN, "language", $3, $6);
157214571Sdim	  }
158214571Sdim	| token '=' MCNUMBER lex_want_filename ':' error { mc_fatal ("missing filename in LanguageNames"); }
159214571Sdim	| token '=' MCNUMBER error { mc_fatal ("missing ':' in LanguageNames"); }
160214571Sdim	| token '=' error { mc_fatal ("missing language code in LanguageNames"); }
161214571Sdim	| token error { mc_fatal ("missing '=' for LanguageNames"); }
162214571Sdim;
163214571Sdim
164214571Sdimalias_name:
165214571Sdim	  /* empty */
166214571Sdim	  {
167214571Sdim	    $$ = NULL;
168214571Sdim	  }
169214571Sdim	| ':' MCIDENT
170214571Sdim	  {
171214571Sdim	    $$ = $2;
172214571Sdim	  }
173214571Sdim	| ':' error { mc_fatal ("illegal token in identifier"); $$ = NULL; }
174214571Sdim;
175214571Sdim
176214571Sdimmessage:
177214571Sdim	  id sefasy_def
178214571Sdim	  {
179214571Sdim	    cur_node = mc_add_node ();
180214571Sdim	    cur_node->symbol = mc_last_symbol;
181214571Sdim	    cur_node->facility = mc_cur_facility;
182214571Sdim	    cur_node->severity = mc_cur_severity;
183214571Sdim	    cur_node->id = ($1 & 0xffffUL);
184214571Sdim	    cur_node->vid = ($1 & 0xffffUL) | mc_sefa_val;
185214571Sdim	    mc_last_id = $1;
186214571Sdim	  }
187214571Sdim	  lang_entities
188214571Sdim;
189214571Sdim
190214571Sdimid:	  MCMESSAGEID '=' vid { $$ = $3; }
191214571Sdim	| MCMESSAGEID '=' error { mc_fatal ("missing number in MessageId"); $$ = 0; }
192214571Sdim	| MCMESSAGEID error { mc_fatal ("missing '=' for MessageId"); $$ = 0; }
193214571Sdim;
194214571Sdim
195214571Sdimvid:	  /* empty */
196214571Sdim	  {
197214571Sdim	    $$ = ++mc_last_id;
198214571Sdim	  }
199214571Sdim	| MCNUMBER
200214571Sdim	  {
201214571Sdim	    $$ = $1;
202214571Sdim	  }
203214571Sdim	| '+' MCNUMBER
204214571Sdim	  {
205214571Sdim	    $$ = mc_last_id + $2;
206214571Sdim	  }
207214571Sdim	| '+' error { mc_fatal ("missing number after MessageId '+'"); }
208214571Sdim;
209214571Sdim
210214571Sdimsefasy_def:
211214571Sdim	  /* empty */
212214571Sdim	  {
213214571Sdim	    $$ = 0;
214214571Sdim	    mc_sefa_val = (mcset_custom_bit ? 1 : 0) << 29;
215214571Sdim	    mc_last_symbol = NULL;
216214571Sdim	    mc_cur_severity = NULL;
217214571Sdim	    mc_cur_facility = NULL;
218214571Sdim	  }
219214571Sdim	| sefasy_def severity
220214571Sdim	  {
221214571Sdim	    if ($1 & 1)
222214571Sdim	      mc_warn (_("duplicate definition of Severity"));
223214571Sdim	    $$ = $1 | 1;
224214571Sdim	  }
225214571Sdim	| sefasy_def facility
226214571Sdim	  {
227214571Sdim	    if ($1 & 2)
228214571Sdim	      mc_warn (_("duplicate definition of Facility"));
229214571Sdim	    $$ = $1 | 2;
230214571Sdim	  }
231214571Sdim	| sefasy_def symbol
232214571Sdim	  {
233214571Sdim	    if ($1 & 4)
234214571Sdim	      mc_warn (_("duplicate definition of SymbolicName"));
235214571Sdim	    $$ = $1 | 4;
236214571Sdim	  }
237214571Sdim;
238214571Sdim
239214571Sdimseverity: MCSEVERITY '=' MCTOKEN
240214571Sdim	  {
241214571Sdim	    mc_sefa_val &= ~ (0x3UL << 30);
242214571Sdim	    mc_sefa_val |= (($3->nval & 0x3UL) << 30);
243214571Sdim	    mc_cur_severity = $3;
244214571Sdim	  }
245214571Sdim;
246214571Sdim
247214571Sdimfacility: MCFACILITY '=' MCTOKEN
248214571Sdim	  {
249214571Sdim	    mc_sefa_val &= ~ (0xfffUL << 16);
250214571Sdim	    mc_sefa_val |= (($3->nval & 0xfffUL) << 16);
251214571Sdim	    mc_cur_facility = $3;
252214571Sdim	  }
253214571Sdim;
254214571Sdim
255214571Sdimsymbol: MCSYMBOLICNAME '=' MCIDENT
256214571Sdim	{
257214571Sdim	  mc_last_symbol = $3;
258214571Sdim	}
259214571Sdim;
260214571Sdim
261214571Sdimlang_entities:
262214571Sdim	  lang_entity
263214571Sdim	| lang_entities lang_entity
264214571Sdim;
265214571Sdim
266214571Sdimlang_entity:
267214571Sdim	  lang lex_want_line lines MCENDLINE
268214571Sdim	  {
269214571Sdim	    mc_node_lang *h;
270214571Sdim	    h = mc_add_node_lang (cur_node, $1, cur_node->vid);
271214571Sdim	    h->message = $3;
272214571Sdim	    if (mcset_max_message_length != 0 && unichar_len (h->message) > mcset_max_message_length)
273214571Sdim	      mc_warn ("message length to long");
274214571Sdim	  }
275214571Sdim;
276214571Sdim
277214571Sdimlines:	  MCLINE
278214571Sdim	  {
279214571Sdim	    $$ = $1;
280214571Sdim	  }
281214571Sdim	| lines MCLINE
282214571Sdim	  {
283214571Sdim	    unichar *h;
284214571Sdim	    rc_uint_type l1,l2;
285214571Sdim	    l1 = unichar_len ($1);
286214571Sdim	    l2 = unichar_len ($2);
287214571Sdim	    h = (unichar *) res_alloc ((l1 + l2 + 1) * sizeof (unichar));
288214571Sdim	    if (l1) memcpy (h, $1, l1 * sizeof (unichar));
289214571Sdim	    if (l2) memcpy (&h[l1], $2, l2 * sizeof (unichar));
290214571Sdim	    h[l1 + l2] = 0;
291214571Sdim	    $$ = h;
292214571Sdim	  }
293214571Sdim	| error { mc_fatal ("missing end of message text"); $$ = NULL; }
294214571Sdim	| lines error { mc_fatal ("missing end of message text"); $$ = $1; }
295214571Sdim;
296214571Sdim
297214571Sdimcomments: MCCOMMENT { $$ = $1; }
298214571Sdim	| comments MCCOMMENT
299214571Sdim	  {
300214571Sdim	    unichar *h;
301214571Sdim	    rc_uint_type l1,l2;
302214571Sdim	    l1 = unichar_len ($1);
303214571Sdim	    l2 = unichar_len ($2);
304214571Sdim	    h = (unichar *) res_alloc ((l1 + l2 + 1) * sizeof (unichar));
305214571Sdim	    if (l1) memcpy (h, $1, l1 * sizeof (unichar));
306214571Sdim	    if (l2) memcpy (&h[l1], $2, l2 * sizeof (unichar));
307214571Sdim	    h[l1 + l2] = 0;
308214571Sdim	    $$ = h;
309214571Sdim	  }
310214571Sdim;
311214571Sdim
312214571Sdimlang:	  MCLANGUAGE lex_want_nl '=' MCTOKEN NL
313214571Sdim	  {
314214571Sdim	    $$ = $4;
315214571Sdim	  }
316214571Sdim	| MCLANGUAGE lex_want_nl '=' MCIDENT NL
317214571Sdim	  {
318214571Sdim	    $$ = NULL;
319214571Sdim	    mc_fatal (_("undeclared language identifier"));
320214571Sdim	  }
321214571Sdim	| MCLANGUAGE lex_want_nl '=' token error
322214571Sdim	  {
323214571Sdim	    $$ = NULL;
324214571Sdim	    mc_fatal ("missing newline after Language");
325214571Sdim	  }
326214571Sdim	| MCLANGUAGE lex_want_nl '=' error
327214571Sdim	  {
328214571Sdim	    $$ = NULL;
329214571Sdim	    mc_fatal ("missing ident for Language");
330214571Sdim	  }
331214571Sdim	| MCLANGUAGE error
332214571Sdim	  {
333214571Sdim	    $$ = NULL;
334214571Sdim	    mc_fatal ("missing '=' for Language");
335214571Sdim	  }
336214571Sdim;
337214571Sdim
338214571Sdimtoken: 	MCIDENT { $$ = $1; }
339214571Sdim	|  MCTOKEN { $$ = $1->usz; }
340214571Sdim;
341214571Sdim
342214571Sdimlex_want_nl:
343214571Sdim	  /* Empty */	{ mclex_want_nl = 1; }
344214571Sdim;
345214571Sdim
346214571Sdimlex_want_line:
347214571Sdim	  /* Empty */	{ mclex_want_line = 1; }
348214571Sdim;
349214571Sdim
350214571Sdimlex_want_filename:
351214571Sdim	  /* Empty */	{ mclex_want_filename = 1; }
352214571Sdim;
353214571Sdim
354214571Sdim%%
355214571Sdim
356214571Sdim/* Something else.  */
357