From Ton van Overbeek <tvoverbe@wk.estec.esa.nl>:
[external/binutils.git] / binutils / rcparse.y
1 %{ /* rcparse.y -- parser for Windows rc files
2    Copyright 1997 Free Software Foundation, Inc.
3    Written by Ian Lance Taylor, Cygnus Support.
4
5    This file is part of GNU Binutils.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.  */
21
22 /* This is a parser for Windows rc files.  It is based on the parser
23    by Gunther Ebert <gunther.ebert@ixos-leipzig.de>.  */
24
25 #include "bfd.h"
26 #include "bucomm.h"
27 #include "libiberty.h"
28 #include "windres.h"
29
30 #include <ctype.h>
31
32 /* The current language.  */
33
34 static unsigned short language;
35
36 /* The resource information during a sub statement.  */
37
38 static struct res_res_info sub_res_info;
39
40 /* Dialog information.  This is built by the nonterminals styles and
41    controls.  */
42
43 static struct dialog dialog;
44
45 /* This is used when building a style.  It is modified by the
46    nonterminal styleexpr.  */
47
48 static unsigned long style;
49
50 /* These are used when building a control.  They are set before using
51    control_params.  */
52
53 static unsigned long base_style;
54 static unsigned long default_style;
55 static unsigned long class;
56
57 %}
58
59 %union
60 {
61   struct accelerator acc;
62   struct accelerator *pacc;
63   struct dialog_control *dialog_control;
64   struct menuitem *menuitem;
65   struct
66   {
67     struct rcdata_item *first;
68     struct rcdata_item *last;
69   } rcdata;
70   struct rcdata_item *rcdata_item;
71   struct stringtable_data *stringtable;
72   struct fixed_versioninfo *fixver;
73   struct ver_info *verinfo;
74   struct ver_stringinfo *verstring;
75   struct ver_varinfo *vervar;
76   struct res_id id;
77   struct res_res_info res_info;
78   struct
79   {
80     unsigned short on;
81     unsigned short off;
82   } memflags;
83   struct
84   {
85     unsigned long val;
86     /* Nonzero if this number was explicitly specified as long.  */
87     int dword;
88   } i;
89   unsigned long il;
90   unsigned short is;
91   const char *s;
92   struct
93   {
94     unsigned long length;
95     const char *s;
96   } ss;
97 };
98
99 %token BEG END
100 %token ACCELERATORS VIRTKEY ASCII NOINVERT SHIFT CONTROL ALT
101 %token BITMAP
102 %token CURSOR
103 %token DIALOG DIALOGEX EXSTYLE CAPTION CLASS STYLE
104 %token AUTO3STATE AUTOCHECKBOX AUTORADIOBUTTON CHECKBOX COMBOBOX CTEXT
105 %token DEFPUSHBUTTON EDITTEXT GROUPBOX LISTBOX LTEXT PUSHBOX PUSHBUTTON
106 %token RADIOBUTTON RTEXT SCROLLBAR STATE3 USERBUTTON
107 %token BEDIT HEDIT IEDIT
108 %token FONT
109 %token ICON
110 %token LANGUAGE CHARACTERISTICS VERSION
111 %token MENU MENUEX MENUITEM SEPARATOR POPUP CHECKED GRAYED HELP INACTIVE
112 %token MENUBARBREAK MENUBREAK
113 %token MESSAGETABLE
114 %token RCDATA
115 %token STRINGTABLE
116 %token VERSIONINFO FILEVERSION PRODUCTVERSION FILEFLAGSMASK FILEFLAGS
117 %token FILEOS FILETYPE FILESUBTYPE BLOCKSTRINGFILEINFO BLOCKVARFILEINFO
118 %token VALUE
119 %token <s> BLOCK
120 %token MOVEABLE FIXED PURE IMPURE PRELOAD LOADONCALL DISCARDABLE
121 %token NOT
122 %token <s> QUOTEDSTRING STRING
123 %token <i> NUMBER
124 %token <ss> SIZEDSTRING
125
126 %type <pacc> acc_entries
127 %type <acc> acc_entry acc_event
128 %type <dialog_control> control control_params
129 %type <menuitem> menuitems menuitem menuexitems menuexitem
130 %type <rcdata> optrcdata_data optrcdata_data_int rcdata_data
131 %type <rcdata_item> opt_control_data
132 %type <fixver> fixedverinfo
133 %type <verinfo> verblocks
134 %type <verstring> vervals
135 %type <vervar> vertrans
136 %type <res_info> suboptions memflags_move_discard memflags_move
137 %type <memflags> memflag
138 %type <id> id
139 %type <il> exstyle parennumber
140 %type <il> numexpr posnumexpr cnumexpr optcnumexpr cposnumexpr
141 %type <is> acc_options acc_option menuitem_flags menuitem_flag
142 %type <s> optstringc file_name
143 %type <i> sizednumexpr sizedposnumexpr
144
145 %left '|'
146 %left '^'
147 %left '&'
148 %left '+' '-'
149 %left '*' '/' '%'
150 %right '~' NEG
151
152 %%
153
154 input:
155           /* empty */
156         | input newcmd accelerator
157         | input newcmd bitmap
158         | input newcmd cursor
159         | input newcmd dialog
160         | input newcmd font
161         | input newcmd icon
162         | input newcmd language
163         | input newcmd menu
164         | input newcmd menuex
165         | input newcmd messagetable
166         | input newcmd rcdata
167         | input newcmd stringtable
168         | input newcmd user
169         | input newcmd versioninfo
170         ;
171
172 newcmd:
173           /* empty */
174           {
175             rcparse_discard_strings ();
176           }
177         ;
178
179 /* Accelerator resources.  */
180
181 accelerator:
182           id ACCELERATORS suboptions BEG acc_entries END
183           {
184             define_accelerator ($1, &$3, $5);
185           }
186         ;
187
188 acc_entries:
189           /* empty */
190           {
191             $$ = NULL;
192           }
193         | acc_entries acc_entry
194           {
195             struct accelerator *a;
196
197             a = (struct accelerator *) res_alloc (sizeof *a);
198             *a = $2;
199             if ($1 == NULL)
200               $$ = a;
201             else
202               {
203                 struct accelerator **pp;
204
205                 for (pp = &$1->next; *pp != NULL; pp = &(*pp)->next)
206                   ;
207                 *pp = a;
208                 $$ = $1;
209               }
210           }
211         ;
212
213 acc_entry:
214           acc_event cposnumexpr
215           {
216             $$ = $1;
217             $$.id = $2;
218           }
219         | acc_event cposnumexpr ',' acc_options
220           {
221             $$ = $1;
222             $$.id = $2;
223             $$.flags |= $4;
224           }
225         ;
226
227 acc_event:
228           QUOTEDSTRING
229           {
230             const char *s = $1;
231
232             $$.id = 0;
233             if (*s != '^')
234               $$.flags = 0;
235             else
236               {
237                 $$.flags = ACC_CONTROL;
238                 ++s;
239               }
240             $$.key = *s;
241             if (s[1] != '\0')
242               rcparse_warning ("accelerator should only be one character");
243           }
244         | posnumexpr
245           {
246             $$.flags = 0;
247             $$.id = 0;
248             $$.key = $1;
249           }
250         ;
251
252 acc_options:
253           acc_option
254           {
255             $$ = $1;
256           }
257         | acc_options ',' acc_option
258           {
259             $$ = $1 | $3;
260           }
261         ;
262
263 acc_option:
264           VIRTKEY
265           {
266             $$ = ACC_VIRTKEY;
267           }
268         | ASCII
269           {
270             /* This is just the absence of VIRTKEY.  */
271             $$ = 0;
272           }
273         | NOINVERT
274           {
275             $$ = ACC_NOINVERT;
276           }
277         | SHIFT
278           {
279             $$ = ACC_SHIFT;
280           }
281         | CONTROL
282           {
283             $$ = ACC_CONTROL;
284           }
285         | ALT
286           {
287             $$ = ACC_ALT;
288           }
289         ;
290
291 /* Bitmap resources.  */
292
293 bitmap:
294           id BITMAP memflags_move file_name
295           {
296             define_bitmap ($1, &$3, $4);
297           }
298         ;
299
300 /* Cursor resources.  */
301
302 cursor:
303           id CURSOR memflags_move_discard file_name
304           {
305             define_cursor ($1, &$3, $4);
306           }
307         ;
308
309 /* Dialog resources.  */
310
311 dialog:
312           id DIALOG memflags_move exstyle posnumexpr cnumexpr cnumexpr
313             cnumexpr
314             {
315               memset (&dialog, 0, sizeof dialog);
316               dialog.x = $5;
317               dialog.y = $6;
318               dialog.width = $7;
319               dialog.height = $8;
320               dialog.style = WS_POPUP | WS_BORDER | WS_SYSMENU;
321               dialog.exstyle = $4;
322               dialog.menu.named = 1;
323               dialog.class.named = 1;
324               dialog.font = NULL;
325               dialog.ex = NULL;
326               dialog.controls = NULL;
327               sub_res_info = $3;
328             }
329             styles BEG controls END
330           {
331             define_dialog ($1, &sub_res_info, &dialog);
332           }
333         | id DIALOGEX memflags_move exstyle posnumexpr cnumexpr cnumexpr
334             cnumexpr
335             {
336               memset (&dialog, 0, sizeof dialog);
337               dialog.x = $5;
338               dialog.y = $6;
339               dialog.width = $7;
340               dialog.height = $8;
341               dialog.style = WS_POPUP | WS_BORDER | WS_SYSMENU;
342               dialog.exstyle = $4;
343               dialog.menu.named = 1;
344               dialog.class.named = 1;
345               dialog.font = NULL;
346               dialog.ex = ((struct dialog_ex *)
347                            res_alloc (sizeof (struct dialog_ex)));
348               memset (dialog.ex, 0, sizeof (struct dialog_ex));
349               dialog.controls = NULL;
350               sub_res_info = $3;
351             }
352             styles BEG controls END
353           {
354             define_dialog ($1, &sub_res_info, &dialog);
355           }
356         | id DIALOGEX memflags_move exstyle posnumexpr cnumexpr cnumexpr
357             cnumexpr cnumexpr
358             {
359               memset (&dialog, 0, sizeof dialog);
360               dialog.x = $5;
361               dialog.y = $6;
362               dialog.width = $7;
363               dialog.height = $8;
364               dialog.style = WS_POPUP | WS_BORDER | WS_SYSMENU;
365               dialog.exstyle = $4;
366               dialog.menu.named = 1;
367               dialog.class.named = 1;
368               dialog.font = NULL;
369               dialog.ex = ((struct dialog_ex *)
370                            res_alloc (sizeof (struct dialog_ex)));
371               memset (dialog.ex, 0, sizeof (struct dialog_ex));
372               dialog.ex->help = $9;
373               dialog.controls = NULL;
374               sub_res_info = $3;
375             }
376             styles BEG controls END
377           {
378             define_dialog ($1, &sub_res_info, &dialog);
379           }
380         ;
381
382 exstyle:
383           /* empty */
384           {
385             $$ = 0;
386           }
387         | EXSTYLE '=' numexpr
388           {
389             $$ = $3;
390           }
391         ;
392
393 styles:
394           /* empty */
395         | styles CAPTION QUOTEDSTRING
396           {
397             unicode_from_ascii ((int *) NULL, &dialog.caption, $3);
398           }
399         | styles CLASS id
400           {
401             dialog.class = $3;
402           }
403         | styles STYLE
404             { style = dialog.style; }
405             styleexpr
406           {
407             dialog.style = style;
408           }
409         | styles EXSTYLE numexpr
410           {
411             dialog.exstyle = $3;
412           }
413         | styles FONT numexpr ',' QUOTEDSTRING
414           {
415             dialog.style |= DS_SETFONT;
416             dialog.pointsize = $3;
417             unicode_from_ascii ((int *) NULL, &dialog.font, $5);
418           }
419         | styles FONT numexpr ',' QUOTEDSTRING cnumexpr cnumexpr
420           {
421             dialog.style |= DS_SETFONT;
422             dialog.pointsize = $3;
423             unicode_from_ascii ((int *) NULL, &dialog.font, $5);
424             if (dialog.ex == NULL)
425               rcparse_warning ("extended FONT requires DIALOGEX");
426             else
427               {
428                 dialog.ex->weight = $6;
429                 dialog.ex->italic = $7;
430               }
431           }
432         | styles MENU id
433           {
434             dialog.menu = $3;
435           }
436         | styles CHARACTERISTICS numexpr
437           {
438             sub_res_info.characteristics = $3;
439           }
440         | styles LANGUAGE numexpr cnumexpr
441           {
442             sub_res_info.language = $3 | ($4 << 8);
443           }
444         | styles VERSION numexpr
445           {
446             sub_res_info.version = $3;
447           }
448         ;
449
450 controls:
451           /* empty */
452         | controls control
453           {
454             struct dialog_control **pp;
455
456             for (pp = &dialog.controls; *pp != NULL; pp = &(*pp)->next)
457               ;
458             *pp = $2;
459           }
460         ;
461
462 control:
463           AUTO3STATE
464             {
465               default_style = BS_AUTO3STATE | WS_TABSTOP;
466               base_style = BS_AUTO3STATE;
467               class = CTL_BUTTON;
468             }
469             control_params
470           {
471             $$ = $3;
472           }
473         | AUTOCHECKBOX
474             {
475               default_style = BS_AUTOCHECKBOX | WS_TABSTOP;
476               base_style = BS_AUTOCHECKBOX;
477               class = CTL_BUTTON;
478             }
479             control_params
480           {
481             $$ = $3;
482           }
483         | AUTORADIOBUTTON
484             {
485               default_style = BS_AUTORADIOBUTTON | WS_TABSTOP;
486               base_style = BS_AUTORADIOBUTTON;
487               class = CTL_BUTTON;
488             }
489             control_params
490           {
491             $$ = $3;
492           }
493         | BEDIT
494             {
495               default_style = ES_LEFT | WS_BORDER | WS_TABSTOP;
496               base_style = ES_LEFT | WS_BORDER | WS_TABSTOP;
497               class = CTL_EDIT;
498             }
499             control_params
500           {
501             $$ = $3;
502             if (dialog.ex == NULL)
503               rcparse_warning ("IEDIT requires DIALOGEX");
504             res_string_to_id (&$$->class, "BEDIT");
505           }
506         | CHECKBOX
507             {
508               default_style = BS_CHECKBOX | WS_TABSTOP;
509               base_style = BS_CHECKBOX | WS_TABSTOP;
510               class = CTL_BUTTON;
511             }
512             control_params
513           {
514             $$ = $3;
515           }
516         | COMBOBOX
517             {
518               default_style = CBS_SIMPLE | WS_TABSTOP;
519               base_style = 0;
520               class = CTL_COMBOBOX;
521             }
522             control_params
523           {
524             $$ = $3;
525           }
526         | CONTROL optstringc numexpr cnumexpr control_styleexpr cnumexpr
527             cnumexpr cnumexpr cnumexpr optcnumexpr opt_control_data
528           {
529             $$ = define_control ($2, $3, $6, $7, $8, $9, $4, style, $10);
530             if ($11 != NULL)
531               {
532                 if (dialog.ex == NULL)
533                   rcparse_warning ("control data requires DIALOGEX");
534                 $$->data = $11;
535               }
536           }
537         | CONTROL optstringc numexpr cnumexpr control_styleexpr cnumexpr
538             cnumexpr cnumexpr cnumexpr cnumexpr cnumexpr opt_control_data
539           {
540             $$ = define_control ($2, $3, $6, $7, $8, $9, $4, style, $10);
541             if (dialog.ex == NULL)
542               rcparse_warning ("help ID requires DIALOGEX");
543             $$->help = $11;
544             $$->data = $12;
545           }
546         | CTEXT
547             {
548               default_style = SS_CENTER | WS_GROUP;
549               base_style = SS_CENTER;
550               class = CTL_STATIC;
551             }
552             control_params
553           {
554             $$ = $3;
555           }
556         | DEFPUSHBUTTON
557             {
558               default_style = BS_DEFPUSHBUTTON | WS_TABSTOP;
559               base_style = BS_DEFPUSHBUTTON | WS_TABSTOP;
560               class = CTL_BUTTON;
561             }
562             control_params
563           {
564             $$ = $3;
565           }
566         | EDITTEXT
567             {
568               default_style = ES_LEFT | WS_BORDER | WS_TABSTOP;
569               base_style = ES_LEFT | WS_BORDER | WS_TABSTOP;
570               class = CTL_EDIT;
571             }
572             control_params
573           {
574             $$ = $3;
575           }
576         | GROUPBOX
577             {
578               default_style = BS_GROUPBOX;
579               base_style = BS_GROUPBOX;
580               class = CTL_BUTTON;
581             }
582             control_params
583           {
584             $$ = $3;
585           }
586         | HEDIT
587             {
588               default_style = ES_LEFT | WS_BORDER | WS_TABSTOP;
589               base_style = ES_LEFT | WS_BORDER | WS_TABSTOP;
590               class = CTL_EDIT;
591             }
592             control_params
593           {
594             $$ = $3;
595             if (dialog.ex == NULL)
596               rcparse_warning ("IEDIT requires DIALOGEX");
597             res_string_to_id (&$$->class, "HEDIT");
598           }
599         | ICON optstringc numexpr cnumexpr cnumexpr opt_control_data
600           {
601             $$ = define_control ($2, $3, $4, $5, 0, 0, CTL_STATIC,
602                                  SS_ICON | WS_CHILD | WS_VISIBLE, 0);
603             if ($6 != NULL)
604               {
605                 if (dialog.ex == NULL)
606                   rcparse_warning ("control data requires DIALOGEX");
607                 $$->data = $6;
608               }
609           }
610         | ICON optstringc numexpr cnumexpr cnumexpr cnumexpr cnumexpr
611             icon_styleexpr optcnumexpr opt_control_data
612           {
613             $$ = define_control ($2, $3, $4, $5, $6, $7, CTL_STATIC,
614                                  style, $9);
615             if ($10 != NULL)
616               {
617                 if (dialog.ex == NULL)
618                   rcparse_warning ("control data requires DIALOGEX");
619                 $$->data = $10;
620               }
621           }
622         | ICON optstringc numexpr cnumexpr cnumexpr cnumexpr cnumexpr
623             icon_styleexpr cnumexpr cnumexpr opt_control_data
624           {
625             $$ = define_control ($2, $3, $4, $5, $6, $7, CTL_STATIC,
626                                  style, $9);
627             if (dialog.ex == NULL)
628               rcparse_warning ("help ID requires DIALOGEX");
629             $$->help = $10;
630             $$->data = $11;
631           }
632         | IEDIT
633             {
634               default_style = ES_LEFT | WS_BORDER | WS_TABSTOP;
635               base_style = ES_LEFT | WS_BORDER | WS_TABSTOP;
636               class = CTL_EDIT;
637             }
638             control_params
639           {
640             $$ = $3;
641             if (dialog.ex == NULL)
642               rcparse_warning ("IEDIT requires DIALOGEX");
643             res_string_to_id (&$$->class, "IEDIT");
644           }
645         | LISTBOX
646             {
647               default_style = LBS_NOTIFY | WS_BORDER;
648               base_style = LBS_NOTIFY | WS_BORDER;
649               class = CTL_LISTBOX;
650             }
651             control_params
652           {
653             $$ = $3;
654           }
655         | LTEXT
656             {
657               default_style = SS_LEFT | WS_GROUP;
658               base_style = SS_LEFT;
659               class = CTL_STATIC;
660             }
661             control_params
662           {
663             $$ = $3;
664           }
665         | PUSHBOX
666             {
667               default_style = BS_PUSHBOX | WS_TABSTOP;
668               base_style = BS_PUSHBOX;
669               class = CTL_BUTTON;
670             }
671             control_params
672           {
673             $$ = $3;
674           }
675         | PUSHBUTTON
676             {
677               default_style = BS_PUSHBUTTON | WS_TABSTOP;
678               base_style = BS_PUSHBUTTON | WS_TABSTOP;
679               class = CTL_BUTTON;
680             }
681             control_params
682           {
683             $$ = $3;
684           }
685         | RADIOBUTTON
686             {
687               default_style = BS_RADIOBUTTON | WS_TABSTOP;
688               base_style = BS_RADIOBUTTON;
689               class = CTL_BUTTON;
690             }
691             control_params
692           {
693             $$ = $3;
694           }
695         | RTEXT
696             {
697               default_style = SS_RIGHT | WS_GROUP;
698               base_style = SS_RIGHT;
699               class = CTL_STATIC;
700             }
701             control_params
702           {
703             $$ = $3;
704           }
705         | SCROLLBAR
706             {
707               default_style = SBS_HORZ;
708               base_style = 0;
709               class = CTL_SCROLLBAR;
710             }
711             control_params
712           {
713             $$ = $3;
714           }
715         | STATE3
716             {
717               default_style = BS_3STATE | WS_TABSTOP;
718               base_style = BS_3STATE;
719               class = CTL_BUTTON;
720             }
721             control_params
722           {
723             $$ = $3;
724           }
725         | USERBUTTON QUOTEDSTRING ',' numexpr ',' numexpr ',' numexpr ','
726             numexpr ',' numexpr ',' 
727             { style = WS_CHILD | WS_VISIBLE; }
728             styleexpr optcnumexpr
729           {
730             $$ = define_control ($2, $4, $6, $8, $10, $12, CTL_BUTTON,
731                                  style, $16);
732           }
733         ;
734
735 /* Parameters for a control.  The static variables DEFAULT_STYLE,
736    BASE_STYLE, and CLASS must be initialized before this nonterminal
737    is used.  DEFAULT_STYLE is the style to use if no style expression
738    is specified.  BASE_STYLE is the base style to use if a style
739    expression is specified; the style expression modifies the base
740    style.  CLASS is the class of the control.  */
741
742 control_params:
743           optstringc numexpr cnumexpr cnumexpr cnumexpr cnumexpr
744             opt_control_data
745           {
746             $$ = define_control ($1, $2, $3, $4, $5, $6, class,
747                                  default_style | WS_CHILD | WS_VISIBLE, 0);
748             if ($7 != NULL)
749               {
750                 if (dialog.ex == NULL)
751                   rcparse_warning ("control data requires DIALOGEX");
752                 $$->data = $7;
753               }
754           }
755         | optstringc numexpr cnumexpr cnumexpr cnumexpr cnumexpr
756             control_params_styleexpr optcnumexpr opt_control_data
757           {
758             $$ = define_control ($1, $2, $3, $4, $5, $6, class, style, $8);
759             if ($9 != NULL)
760               {
761                 if (dialog.ex == NULL)
762                   rcparse_warning ("control data requires DIALOGEX");
763                 $$->data = $9;
764               }
765           }
766         | optstringc numexpr cnumexpr cnumexpr cnumexpr cnumexpr
767             control_params_styleexpr cnumexpr cnumexpr opt_control_data
768           {
769             $$ = define_control ($1, $2, $3, $4, $5, $6, class, style, $8);
770             if (dialog.ex == NULL)
771               rcparse_warning ("help ID requires DIALOGEX");
772             $$->help = $9;
773             $$->data = $10;
774           }
775         ;
776
777 optstringc:
778           /* empty */
779           {
780             $$ = NULL;
781           }
782         | QUOTEDSTRING ','
783           {
784             $$ = $1;
785           }
786         ;
787
788 opt_control_data:
789           /* empty */
790           {
791             $$ = NULL;
792           }
793         | BEG optrcdata_data END
794           {
795             $$ = $2.first;
796           }
797         ;
798
799 /* These only exist to parse a reduction out of a common case.  */
800
801 control_styleexpr:
802           ','
803           { style = WS_CHILD | WS_VISIBLE; }
804           styleexpr
805         ;
806
807 icon_styleexpr:
808           ','
809           { style = SS_ICON | WS_CHILD | WS_VISIBLE; }
810           styleexpr
811         ;
812
813 control_params_styleexpr:
814           ','
815           { style = base_style | WS_CHILD | WS_VISIBLE; }
816           styleexpr
817         ;
818
819 /* Font resources.  */
820
821 font:
822           id FONT memflags_move_discard file_name
823           {
824             define_font ($1, &$3, $4);
825           }
826         ;
827
828 /* Icon resources.  */
829
830 icon:
831           id ICON memflags_move_discard file_name
832           {
833             define_icon ($1, &$3, $4);
834           }
835         ;
836
837 /* Language command.  This changes the static variable language, which
838    affects all subsequent resources.  */
839
840 language:
841           LANGUAGE numexpr cnumexpr
842           {
843             language = $2 | ($3 << 8);
844           }
845         ;
846
847 /* Menu resources.  */
848
849 menu:
850           id MENU suboptions BEG menuitems END
851           {
852             define_menu ($1, &$3, $5);
853           }
854         ;
855
856 menuitems:
857           /* empty */
858           {
859             $$ = NULL;
860           }
861         | menuitems menuitem
862           {
863             if ($1 == NULL)
864               $$ = $2;
865             else
866               {
867                 struct menuitem **pp;
868
869                 for (pp = &$1->next; *pp != NULL; pp = &(*pp)->next)
870                   ;
871                 *pp = $2;
872                 $$ = $1;
873               }
874           }
875         ;
876
877 menuitem:
878           MENUITEM QUOTEDSTRING cnumexpr menuitem_flags
879           {
880             $$ = define_menuitem ($2, $3, $4, 0, 0, NULL);
881           }
882         | MENUITEM SEPARATOR
883           {
884             $$ = define_menuitem (NULL, 0, 0, 0, 0, NULL);
885           }
886         | POPUP QUOTEDSTRING menuitem_flags BEG menuitems END
887           {
888             $$ = define_menuitem ($2, 0, $3, 0, 0, $5);
889           }
890         ;
891
892 menuitem_flags:
893           /* empty */
894           {
895             $$ = 0;
896           }
897         | menuitem_flags ',' menuitem_flag
898           {
899             $$ = $1 | $3;
900           }
901         | menuitem_flags menuitem_flag
902           {
903             $$ = $1 | $2;
904           }
905         ;
906
907 menuitem_flag:
908           CHECKED
909           {
910             $$ = MENUITEM_CHECKED;
911           }
912         | GRAYED
913           {
914             $$ = MENUITEM_GRAYED;
915           }
916         | HELP
917           {
918             $$ = MENUITEM_HELP;
919           }
920         | INACTIVE
921           {
922             $$ = MENUITEM_INACTIVE;
923           }
924         | MENUBARBREAK
925           {
926             $$ = MENUITEM_MENUBARBREAK;
927           }
928         | MENUBREAK
929           {
930             $$ = MENUITEM_MENUBREAK;
931           }
932         ;
933
934 /* Menuex resources.  */
935
936 menuex:
937           id MENUEX suboptions BEG menuexitems END
938           {
939             define_menu ($1, &$3, $5);
940           }
941         ;
942
943 menuexitems:
944           /* empty */
945           {
946             $$ = NULL;
947           }
948         | menuexitems menuexitem
949           {
950             if ($1 == NULL)
951               $$ = $2;
952             else
953               {
954                 struct menuitem **pp;
955
956                 for (pp = &$1->next; *pp != NULL; pp = &(*pp)->next)
957                   ;
958                 *pp = $2;
959                 $$ = $1;
960               }
961           }
962         ;
963
964 menuexitem:
965           MENUITEM QUOTEDSTRING
966           {
967             $$ = define_menuitem ($2, 0, 0, 0, 0, NULL);
968           }
969         | MENUITEM QUOTEDSTRING cnumexpr
970           {
971             $$ = define_menuitem ($2, $3, 0, 0, 0, NULL);
972           }
973         | MENUITEM QUOTEDSTRING cnumexpr cnumexpr optcnumexpr
974           {
975             $$ = define_menuitem ($2, $3, $4, $5, 0, NULL);
976           }
977         | POPUP QUOTEDSTRING BEG menuexitems END
978           {
979             $$ = define_menuitem ($2, 0, 0, 0, 0, $4);
980           }
981         | POPUP QUOTEDSTRING cnumexpr BEG menuexitems END
982           {
983             $$ = define_menuitem ($2, $3, 0, 0, 0, $5);
984           }
985         | POPUP QUOTEDSTRING cnumexpr cnumexpr BEG menuexitems END
986           {
987             $$ = define_menuitem ($2, $3, $4, 0, 0, $6);
988           }
989         | POPUP QUOTEDSTRING cnumexpr cnumexpr cnumexpr optcnumexpr
990             BEG menuexitems END
991           {
992             $$ = define_menuitem ($2, $3, $4, $5, $6, $8);
993           }
994         ;
995
996 /* Messagetable resources.  */
997
998 messagetable:
999           id MESSAGETABLE memflags_move file_name
1000           {
1001             define_messagetable ($1, &$3, $4);
1002           }
1003         ;
1004
1005 /* Rcdata resources.  */
1006
1007 rcdata:
1008           id RCDATA suboptions BEG optrcdata_data END
1009           {
1010             define_rcdata ($1, &$3, $5.first);
1011           }
1012         ;
1013
1014 /* We use a different lexing algorithm, because rcdata strings may
1015    contain embedded null bytes, and we need to know the length to use.  */
1016
1017 optrcdata_data:
1018           {
1019             rcparse_rcdata ();
1020           }
1021           optrcdata_data_int
1022           {
1023             rcparse_normal ();
1024             $$ = $2;
1025           }
1026         ;
1027
1028 optrcdata_data_int:
1029           /* empty */
1030           {
1031             $$.first = NULL;
1032             $$.last = NULL;
1033           }
1034         | rcdata_data
1035           {
1036             $$ = $1;
1037           }
1038         ;
1039
1040 rcdata_data:
1041           SIZEDSTRING
1042           {
1043             struct rcdata_item *ri;
1044
1045             ri = define_rcdata_string ($1.s, $1.length);
1046             $$.first = ri;
1047             $$.last = ri;
1048           }
1049         | sizednumexpr
1050           {
1051             struct rcdata_item *ri;
1052
1053             ri = define_rcdata_number ($1.val, $1.dword);
1054             $$.first = ri;
1055             $$.last = ri;
1056           }
1057         | rcdata_data ',' SIZEDSTRING
1058           {
1059             struct rcdata_item *ri;
1060
1061             ri = define_rcdata_string ($3.s, $3.length);
1062             $$.first = $1.first;
1063             $1.last->next = ri;
1064             $$.last = ri;
1065           }
1066         | rcdata_data ',' sizednumexpr
1067           {
1068             struct rcdata_item *ri;
1069
1070             ri = define_rcdata_number ($3.val, $3.dword);
1071             $$.first = $1.first;
1072             $1.last->next = ri;
1073             $$.last = ri;
1074           }
1075         ;
1076
1077 /* Stringtable resources.  */
1078
1079 stringtable:
1080           STRINGTABLE suboptions BEG 
1081             { sub_res_info = $2; }
1082             string_data END
1083         ;
1084
1085 string_data:
1086           /* empty */
1087         | string_data numexpr QUOTEDSTRING
1088           {
1089             define_stringtable (&sub_res_info, $2, $3);
1090           }
1091         | string_data numexpr ',' QUOTEDSTRING
1092           {
1093             define_stringtable (&sub_res_info, $2, $4);
1094           }
1095         ;
1096
1097 /* User defined resources.  We accept general suboptions in the
1098    file_name case to keep the parser happy.  */
1099
1100 user:
1101           id id suboptions BEG optrcdata_data END
1102           {
1103             define_user_data ($1, $2, &$3, $5.first);
1104           }
1105         | id id suboptions file_name
1106           {
1107             define_user_file ($1, $2, &$3, $4);
1108           }
1109         ;
1110
1111 /* Versioninfo resources.  */
1112
1113 versioninfo:
1114           id VERSIONINFO fixedverinfo BEG verblocks END
1115           {
1116             define_versioninfo ($1, language, $3, $5);
1117           }
1118         ;
1119
1120 fixedverinfo:
1121           /* empty */
1122           {
1123             $$ = ((struct fixed_versioninfo *)
1124                   res_alloc (sizeof (struct fixed_versioninfo)));
1125             memset ($$, 0, sizeof (struct fixed_versioninfo));
1126           }
1127         | fixedverinfo FILEVERSION numexpr cnumexpr cnumexpr cnumexpr
1128           {
1129             $1->file_version_ms = ($3 << 16) | $4;
1130             $1->file_version_ls = ($5 << 16) | $6;
1131             $$ = $1;
1132           }
1133         | fixedverinfo PRODUCTVERSION numexpr cnumexpr cnumexpr cnumexpr
1134           {
1135             $1->product_version_ms = ($3 << 16) | $4;
1136             $1->product_version_ls = ($5 << 16) | $6;
1137             $$ = $1;
1138           }
1139         | fixedverinfo FILEFLAGSMASK numexpr
1140           {
1141             $1->file_flags_mask = $3;
1142             $$ = $1;
1143           }
1144         | fixedverinfo FILEFLAGS numexpr
1145           {
1146             $1->file_flags = $3;
1147             $$ = $1;
1148           }
1149         | fixedverinfo FILEOS numexpr
1150           {
1151             $1->file_os = $3;
1152             $$ = $1;
1153           }
1154         | fixedverinfo FILETYPE numexpr
1155           {
1156             $1->file_type = $3;
1157             $$ = $1;
1158           }
1159         | fixedverinfo FILESUBTYPE numexpr
1160           {
1161             $1->file_subtype = $3;
1162             $$ = $1;
1163           }
1164         ;
1165
1166 /* To handle verblocks successfully, the lexer handles BLOCK
1167    specially.  A BLOCK "StringFileInfo" is returned as
1168    BLOCKSTRINGFILEINFO.  A BLOCK "VarFileInfo" is returned as
1169    BLOCKVARFILEINFO.  A BLOCK with some other string returns BLOCK
1170    with the string as the value.  */
1171
1172 verblocks:
1173           /* empty */
1174           {
1175             $$ = NULL;
1176           }
1177         | verblocks BLOCKSTRINGFILEINFO BEG BLOCK BEG vervals END END
1178           {
1179             $$ = append_ver_stringfileinfo ($1, $4, $6);
1180           }
1181         | verblocks BLOCKVARFILEINFO BEG VALUE QUOTEDSTRING vertrans END
1182           {
1183             $$ = append_ver_varfileinfo ($1, $5, $6);
1184           }
1185         ;
1186
1187 vervals:
1188           /* empty */
1189           {
1190             $$ = NULL;
1191           }
1192         | vervals VALUE QUOTEDSTRING ',' QUOTEDSTRING
1193           {
1194             $$ = append_verval ($1, $3, $5);
1195           }
1196         ;
1197
1198 vertrans:
1199           /* empty */
1200           {
1201             $$ = NULL;
1202           }
1203         | vertrans cnumexpr cnumexpr
1204           {
1205             $$ = append_vertrans ($1, $2, $3);
1206           }
1207         ;
1208
1209 /* A resource ID.  */
1210
1211 id:
1212           posnumexpr
1213           {
1214             $$.named = 0;
1215             $$.u.id = $1;
1216           }
1217         | STRING
1218           {
1219             char *copy, *s;
1220
1221             /* It seems that resource ID's are forced to upper case.  */
1222             copy = xstrdup ($1);
1223             for (s = copy; *s != '\0'; s++)
1224               if (islower (*s))
1225                 *s = toupper (*s);
1226             res_string_to_id (&$$, copy);
1227             free (copy);
1228           }
1229         ;
1230
1231 /* Generic suboptions.  These may appear before the BEGIN in any
1232    multiline statement.  */
1233
1234 suboptions:
1235           /* empty */
1236           {
1237             memset (&$$, 0, sizeof (struct res_res_info));
1238             $$.language = language;
1239             /* FIXME: Is this the right default?  */
1240             $$.memflags = MEMFLAG_MOVEABLE;
1241           }
1242         | suboptions memflag
1243           {
1244             $$ = $1;
1245             $$.memflags |= $2.on;
1246             $$.memflags &=~ $2.off;
1247           }
1248         | suboptions CHARACTERISTICS numexpr
1249           {
1250             $$ = $1;
1251             $$.characteristics = $3;
1252           }
1253         | suboptions LANGUAGE numexpr cnumexpr
1254           {
1255             $$ = $1;
1256             $$.language = $3 | ($4 << 8);
1257           }
1258         | suboptions VERSION numexpr
1259           {
1260             $$ = $1;
1261             $$.version = $3;
1262           }
1263         ;
1264
1265 /* Memory flags which default to MOVEABLE and DISCARDABLE.  */
1266
1267 memflags_move_discard:
1268           /* empty */
1269           {
1270             memset (&$$, 0, sizeof (struct res_res_info));
1271             $$.language = language;
1272             $$.memflags = MEMFLAG_MOVEABLE | MEMFLAG_DISCARDABLE;
1273           }
1274         | memflags_move_discard memflag
1275           {
1276             $$ = $1;
1277             $$.memflags |= $2.on;
1278             $$.memflags &=~ $2.off;
1279           }
1280         ;
1281
1282 /* Memory flags which default to MOVEABLE.  */
1283
1284 memflags_move:
1285           /* empty */
1286           {
1287             memset (&$$, 0, sizeof (struct res_res_info));
1288             $$.language = language;
1289             $$.memflags = MEMFLAG_MOVEABLE;
1290           }
1291         | memflags_move_discard memflag
1292           {
1293             $$ = $1;
1294             $$.memflags |= $2.on;
1295             $$.memflags &=~ $2.off;
1296           }
1297         ;
1298
1299 /* Memory flags.  This returns a struct with two integers, because we
1300    sometimes want to set bits and we sometimes want to clear them.  */
1301
1302 memflag:
1303           MOVEABLE
1304           {
1305             $$.on = MEMFLAG_MOVEABLE;
1306             $$.off = 0;
1307           }
1308         | FIXED
1309           {
1310             $$.on = 0;
1311             $$.off = MEMFLAG_MOVEABLE;
1312           }
1313         | PURE
1314           {
1315             $$.on = MEMFLAG_PURE;
1316             $$.off = 0;
1317           }
1318         | IMPURE
1319           {
1320             $$.on = 0;
1321             $$.off = MEMFLAG_PURE;
1322           }
1323         | PRELOAD
1324           {
1325             $$.on = MEMFLAG_PRELOAD;
1326             $$.off = 0;
1327           }
1328         | LOADONCALL
1329           {
1330             $$.on = 0;
1331             $$.off = MEMFLAG_PRELOAD;
1332           }
1333         | DISCARDABLE
1334           {
1335             $$.on = MEMFLAG_DISCARDABLE;
1336             $$.off = 0;
1337           }
1338         ;
1339
1340 /* A file name.  */
1341
1342 file_name:
1343           QUOTEDSTRING
1344           {
1345             $$ = $1;
1346           }
1347         | STRING
1348           {
1349             $$ = $1;
1350           }
1351         ;
1352
1353 /* A style expression.  This changes the static variable STYLE.  We do
1354    it this way because rc appears to permit a style to be set to
1355    something like
1356        WS_GROUP | NOT WS_TABSTOP
1357    to mean that a default of WS_TABSTOP should be removed.  Anything
1358    which wants to accept a style must first set STYLE to the default
1359    value.  The styleexpr nonterminal will change STYLE as specified by
1360    the user.  Note that we do not accept arbitrary expressions here,
1361    just numbers separated by '|'.  */
1362
1363 styleexpr:
1364           parennumber
1365           {
1366             style |= $1;
1367           }
1368         | NOT parennumber
1369           {
1370             style &=~ $2;
1371           }
1372         | styleexpr '|' parennumber
1373           {
1374             style |= $3;
1375           }
1376         | styleexpr '|' NOT parennumber
1377           {
1378             style &=~ $4;
1379           }
1380         ;
1381
1382 parennumber:
1383           NUMBER
1384           {
1385             $$ = $1.val;
1386           }
1387         | '(' numexpr ')'
1388           {
1389             $$ = $2;
1390           }
1391         ;
1392
1393 /* An optional expression with a leading comma.  */
1394
1395 optcnumexpr:
1396           /* empty */
1397           {
1398             $$ = 0;
1399           }
1400         | cnumexpr
1401           {
1402             $$ = $1;
1403           }
1404         ;
1405
1406 /* An expression with a leading comma.  */
1407
1408 cnumexpr:
1409           ',' numexpr
1410           {
1411             $$ = $2;
1412           }
1413         ;
1414
1415 /* A possibly negated numeric expression.  */
1416
1417 numexpr:
1418           sizednumexpr
1419           {
1420             $$ = $1.val;
1421           }
1422         ;
1423
1424 /* A possibly negated expression with a size.  */
1425
1426 sizednumexpr:
1427           NUMBER
1428           {
1429             $$ = $1;
1430           }
1431         | '(' sizednumexpr ')'
1432           {
1433             $$ = $2;
1434           }
1435         | '~' sizednumexpr %prec '~'
1436           {
1437             $$.val = ~ $2.val;
1438             $$.dword = $2.dword;
1439           }
1440         | '-' sizednumexpr %prec NEG
1441           {
1442             $$.val = - $2.val;
1443             $$.dword = $2.dword;
1444           }
1445         | sizednumexpr '*' sizednumexpr
1446           {
1447             $$.val = $1.val * $3.val;
1448             $$.dword = $1.dword || $3.dword;
1449           }
1450         | sizednumexpr '/' sizednumexpr
1451           {
1452             $$.val = $1.val / $3.val;
1453             $$.dword = $1.dword || $3.dword;
1454           }
1455         | sizednumexpr '%' sizednumexpr
1456           {
1457             $$.val = $1.val % $3.val;
1458             $$.dword = $1.dword || $3.dword;
1459           }
1460         | sizednumexpr '+' sizednumexpr
1461           {
1462             $$.val = $1.val + $3.val;
1463             $$.dword = $1.dword || $3.dword;
1464           }
1465         | sizednumexpr '-' sizednumexpr
1466           {
1467             $$.val = $1.val - $3.val;
1468             $$.dword = $1.dword || $3.dword;
1469           }
1470         | sizednumexpr '&' sizednumexpr
1471           {
1472             $$.val = $1.val & $3.val;
1473             $$.dword = $1.dword || $3.dword;
1474           }
1475         | sizednumexpr '^' sizednumexpr
1476           {
1477             $$.val = $1.val ^ $3.val;
1478             $$.dword = $1.dword || $3.dword;
1479           }
1480         | sizednumexpr '|' sizednumexpr
1481           {
1482             $$.val = $1.val | $3.val;
1483             $$.dword = $1.dword || $3.dword;
1484           }
1485         ;
1486
1487 /* An expression with a leading comma which does not use unary
1488    negation.  */
1489
1490 cposnumexpr:
1491           ',' posnumexpr
1492           {
1493             $$ = $2;
1494           }
1495         ;
1496
1497 /* An expression which does not use unary negation.  */
1498
1499 posnumexpr:
1500           sizedposnumexpr
1501           {
1502             $$ = $1.val;
1503           }
1504         ;
1505
1506 /* An expression which does not use unary negation.  We separate unary
1507    negation to avoid parsing conflicts when two numeric expressions
1508    appear consecutively.  */
1509
1510 sizedposnumexpr:
1511           NUMBER
1512           {
1513             $$ = $1;
1514           }
1515         | '(' sizednumexpr ')'
1516           {
1517             $$ = $2;
1518           }
1519         | '~' sizednumexpr %prec '~'
1520           {
1521             $$.val = ~ $2.val;
1522             $$.dword = $2.dword;
1523           }
1524         | sizedposnumexpr '*' sizednumexpr
1525           {
1526             $$.val = $1.val * $3.val;
1527             $$.dword = $1.dword || $3.dword;
1528           }
1529         | sizedposnumexpr '/' sizednumexpr
1530           {
1531             $$.val = $1.val / $3.val;
1532             $$.dword = $1.dword || $3.dword;
1533           }
1534         | sizedposnumexpr '%' sizednumexpr
1535           {
1536             $$.val = $1.val % $3.val;
1537             $$.dword = $1.dword || $3.dword;
1538           }
1539         | sizedposnumexpr '+' sizednumexpr
1540           {
1541             $$.val = $1.val + $3.val;
1542             $$.dword = $1.dword || $3.dword;
1543           }
1544         | sizedposnumexpr '-' sizednumexpr
1545           {
1546             $$.val = $1.val - $3.val;
1547             $$.dword = $1.dword || $3.dword;
1548           }
1549         | sizedposnumexpr '&' sizednumexpr
1550           {
1551             $$.val = $1.val & $3.val;
1552             $$.dword = $1.dword || $3.dword;
1553           }
1554         | sizedposnumexpr '^' sizednumexpr
1555           {
1556             $$.val = $1.val ^ $3.val;
1557             $$.dword = $1.dword || $3.dword;
1558           }
1559         | sizedposnumexpr '|' sizednumexpr
1560           {
1561             $$.val = $1.val | $3.val;
1562             $$.dword = $1.dword || $3.dword;
1563           }
1564         ;
1565
1566 %%
1567
1568 /* Set the language from the command line.  */
1569
1570 void
1571 rcparse_set_language (lang)
1572      int lang;
1573 {
1574   language = lang;
1575 }