| %{ /* rcparse.y -- parser for Windows rc files | |
| Copyright (C) 1997-2025 Free Software Foundation, Inc. | |
| Written by Ian Lance Taylor, Cygnus Support. | |
| Extended 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 "windres.h" | |
| #include "safe-ctype.h" | |
| /* The current language. */ | |
| static unsigned short language; | |
| /* The resource information during a sub statement. */ | |
| static rc_res_res_info sub_res_info; | |
| /* Dialog information. This is built by the nonterminals styles and | |
| controls. */ | |
| static rc_dialog dialog; | |
| /* This is used when building a style. It is modified by the | |
| nonterminal styleexpr. */ | |
| static unsigned long style; | |
| /* These are used when building a control. They are set before using | |
| control_params. */ | |
| static rc_uint_type base_style; | |
| static rc_uint_type default_style; | |
| static rc_res_id class; | |
| static rc_res_id res_text_field; | |
| static unichar null_unichar; | |
| /* This is used for COMBOBOX, LISTBOX and EDITTEXT which | |
| do not allow resource 'text' field in control definition. */ | |
| static const rc_res_id res_null_text = { 1, {{0, &null_unichar}}}; | |
| %} | |
| %union | |
| { | |
| rc_accelerator acc; | |
| rc_accelerator *pacc; | |
| rc_dialog_control *dialog_control; | |
| rc_menuitem *menuitem; | |
| struct | |
| { | |
| rc_rcdata_item *first; | |
| rc_rcdata_item *last; | |
| } rcdata; | |
| rc_rcdata_item *rcdata_item; | |
| rc_fixed_versioninfo *fixver; | |
| rc_ver_info *verinfo; | |
| rc_ver_stringtable *verstringtable; | |
| rc_ver_stringinfo *verstring; | |
| rc_ver_varinfo *vervar; | |
| rc_toolbar_item *toobar_item; | |
| rc_res_id id; | |
| rc_res_res_info res_info; | |
| struct | |
| { | |
| rc_uint_type on; | |
| rc_uint_type off; | |
| } memflags; | |
| struct | |
| { | |
| rc_uint_type val; | |
| /* Nonzero if this number was explicitly specified as long. */ | |
| int dword; | |
| } i; | |
| rc_uint_type il; | |
| rc_uint_type is; | |
| const char *s; | |
| struct | |
| { | |
| rc_uint_type length; | |
| const char *s; | |
| } ss; | |
| unichar *uni; | |
| struct | |
| { | |
| rc_uint_type length; | |
| const unichar *s; | |
| } suni; | |
| }; | |
| %token BEG END | |
| %token ACCELERATORS VIRTKEY ASCII NOINVERT SHIFT CONTROL ALT | |
| %token BITMAP | |
| %token CURSOR | |
| %token DIALOG DIALOGEX EXSTYLE CAPTION CLASS STYLE | |
| %token AUTO3STATE AUTOCHECKBOX AUTORADIOBUTTON CHECKBOX COMBOBOX CTEXT | |
| %token DEFPUSHBUTTON EDITTEXT GROUPBOX LISTBOX LTEXT PUSHBOX PUSHBUTTON | |
| %token RADIOBUTTON RTEXT SCROLLBAR STATE3 USERBUTTON | |
| %token BEDIT HEDIT IEDIT | |
| %token FONT | |
| %token ICON | |
| %token ANICURSOR ANIICON DLGINCLUDE DLGINIT FONTDIR HTML MANIFEST PLUGPLAY VXD TOOLBAR BUTTON | |
| %token LANGUAGE CHARACTERISTICS VERSIONK | |
| %token MENU MENUEX MENUITEM SEPARATOR POPUP CHECKED GRAYED HELP INACTIVE OWNERDRAW | |
| %token MENUBARBREAK MENUBREAK | |
| %token MESSAGETABLE | |
| %token RCDATA | |
| %token STRINGTABLE | |
| %token VERSIONINFO FILEVERSION PRODUCTVERSION FILEFLAGSMASK FILEFLAGS | |
| %token FILEOS FILETYPE FILESUBTYPE BLOCKSTRINGFILEINFO BLOCKVARFILEINFO | |
| %token VALUE | |
| %token <s> BLOCK | |
| %token MOVEABLE FIXED PURE IMPURE PRELOAD LOADONCALL DISCARDABLE | |
| %token NOT | |
| %token <uni> QUOTEDUNISTRING | |
| %token <s> QUOTEDSTRING STRING | |
| %token <i> NUMBER | |
| %token <suni> SIZEDUNISTRING | |
| %token <ss> SIZEDSTRING | |
| %token IGNORED_TOKEN | |
| %type <pacc> acc_entries | |
| %type <acc> acc_entry acc_event | |
| %type <dialog_control> control control_params | |
| %type <menuitem> menuitems menuitem menuexitems menuexitem | |
| %type <rcdata> optrcdata_data optrcdata_data_int rcdata_data | |
| %type <rcdata_item> opt_control_data | |
| %type <fixver> fixedverinfo | |
| %type <verinfo> verblocks | |
| %type <verstringtable> verstringtables | |
| %type <verstring> vervals | |
| %type <vervar> vertrans | |
| %type <toobar_item> toolbar_data | |
| %type <res_info> suboptions memflags_move_discard memflags_move | |
| %type <memflags> memflag | |
| %type <id> id rcdata_id optresidc resref resid cresid | |
| %type <il> exstyle parennumber | |
| %type <il> numexpr posnumexpr cnumexpr optcnumexpr cposnumexpr | |
| %type <is> acc_options acc_option menuitem_flags menuitem_flag | |
| %type <s> file_name | |
| %type <uni> res_unicode_string resname res_unicode_string_concat | |
| %type <ss> sizedstring | |
| %type <suni> sizedunistring res_unicode_sizedstring res_unicode_sizedstring_concat | |
| %type <i> sizednumexpr sizedposnumexpr | |
| %left '|' | |
| %left '^' | |
| %left '&' | |
| %left '+' '-' | |
| %left '*' '/' '%' | |
| %right '~' NEG | |
| %% | |
| input: | |
| /* empty */ | |
| | input accelerator | |
| | input bitmap | |
| | input cursor | |
| | input dialog | |
| | input font | |
| | input icon | |
| | input language | |
| | input menu | |
| | input menuex | |
| | input messagetable | |
| | input stringtable | |
| | input toolbar | |
| | input user | |
| | input versioninfo | |
| | input IGNORED_TOKEN | |
| ; | |
| /* Accelerator resources. */ | |
| accelerator: | |
| id ACCELERATORS suboptions BEG acc_entries END | |
| { | |
| define_accelerator ($1, &$3, $5); | |
| if (yychar != YYEMPTY) | |
| YYERROR; | |
| rcparse_discard_strings (); | |
| } | |
| ; | |
| acc_entries: | |
| /* empty */ | |
| { | |
| $$ = NULL; | |
| } | |
| | acc_entries acc_entry | |
| { | |
| rc_accelerator *a; | |
| a = (rc_accelerator *) res_alloc (sizeof *a); | |
| *a = $2; | |
| if ($1 == NULL) | |
| $$ = a; | |
| else | |
| { | |
| rc_accelerator **pp; | |
| for (pp = &$1->next; *pp != NULL; pp = &(*pp)->next) | |
| ; | |
| *pp = a; | |
| $$ = $1; | |
| } | |
| } | |
| ; | |
| acc_entry: | |
| acc_event cposnumexpr | |
| { | |
| $$ = $1; | |
| $$.id = $2; | |
| } | |
| | acc_event cposnumexpr ',' acc_options | |
| { | |
| $$ = $1; | |
| $$.id = $2; | |
| $$.flags |= $4; | |
| if (($$.flags & ACC_VIRTKEY) == 0 | |
| && ($$.flags & (ACC_SHIFT | ACC_CONTROL)) != 0) | |
| rcparse_warning (_("inappropriate modifiers for non-VIRTKEY")); | |
| } | |
| ; | |
| acc_event: | |
| QUOTEDSTRING | |
| { | |
| const char *s = $1; | |
| char ch; | |
| $$.next = NULL; | |
| $$.id = 0; | |
| ch = *s; | |
| if (ch != '^') | |
| $$.flags = 0; | |
| else | |
| { | |
| $$.flags = ACC_CONTROL | ACC_VIRTKEY; | |
| ++s; | |
| ch = TOUPPER (s[0]); | |
| } | |
| $$.key = ch; | |
| if (s[1] != '\0') | |
| rcparse_warning (_("accelerator should only be one character")); | |
| } | |
| | posnumexpr | |
| { | |
| $$.next = NULL; | |
| $$.flags = 0; | |
| $$.id = 0; | |
| $$.key = $1; | |
| } | |
| ; | |
| acc_options: | |
| acc_option | |
| { | |
| $$ = $1; | |
| } | |
| | acc_options ',' acc_option | |
| { | |
| $$ = $1 | $3; | |
| } | |
| /* I've had one report that the comma is optional. */ | |
| | acc_options acc_option | |
| { | |
| $$ = $1 | $2; | |
| } | |
| ; | |
| acc_option: | |
| VIRTKEY | |
| { | |
| $$ = ACC_VIRTKEY; | |
| } | |
| | ASCII | |
| { | |
| /* This is just the absence of VIRTKEY. */ | |
| $$ = 0; | |
| } | |
| | NOINVERT | |
| { | |
| $$ = ACC_NOINVERT; | |
| } | |
| | SHIFT | |
| { | |
| $$ = ACC_SHIFT; | |
| } | |
| | CONTROL | |
| { | |
| $$ = ACC_CONTROL; | |
| } | |
| | ALT | |
| { | |
| $$ = ACC_ALT; | |
| } | |
| ; | |
| /* Bitmap resources. */ | |
| bitmap: | |
| id BITMAP memflags_move file_name | |
| { | |
| define_bitmap ($1, &$3, $4); | |
| if (yychar != YYEMPTY) | |
| YYERROR; | |
| rcparse_discard_strings (); | |
| } | |
| ; | |
| /* Cursor resources. */ | |
| cursor: | |
| id CURSOR memflags_move_discard file_name | |
| { | |
| define_cursor ($1, &$3, $4); | |
| if (yychar != YYEMPTY) | |
| YYERROR; | |
| rcparse_discard_strings (); | |
| } | |
| ; | |
| /* Dialog resources. */ | |
| dialog: | |
| id DIALOG memflags_move exstyle posnumexpr cnumexpr cnumexpr | |
| cnumexpr | |
| { | |
| memset (&dialog, 0, sizeof dialog); | |
| dialog.x = $5; | |
| dialog.y = $6; | |
| dialog.width = $7; | |
| dialog.height = $8; | |
| dialog.style = WS_POPUP | WS_BORDER | WS_SYSMENU; | |
| dialog.exstyle = $4; | |
| dialog.menu.named = 1; | |
| dialog.class.named = 1; | |
| dialog.font = NULL; | |
| dialog.ex = NULL; | |
| dialog.controls = NULL; | |
| sub_res_info = $3; | |
| style = 0; | |
| } | |
| styles BEG controls END | |
| { | |
| define_dialog ($1, &sub_res_info, &dialog); | |
| if (yychar != YYEMPTY) | |
| YYERROR; | |
| rcparse_discard_strings (); | |
| } | |
| | id DIALOGEX memflags_move exstyle posnumexpr cnumexpr cnumexpr | |
| cnumexpr | |
| { | |
| memset (&dialog, 0, sizeof dialog); | |
| dialog.x = $5; | |
| dialog.y = $6; | |
| dialog.width = $7; | |
| dialog.height = $8; | |
| dialog.style = WS_POPUP | WS_BORDER | WS_SYSMENU; | |
| dialog.exstyle = $4; | |
| dialog.menu.named = 1; | |
| dialog.class.named = 1; | |
| dialog.font = NULL; | |
| dialog.ex = ((rc_dialog_ex *) | |
| res_alloc (sizeof (rc_dialog_ex))); | |
| memset (dialog.ex, 0, sizeof (rc_dialog_ex)); | |
| dialog.controls = NULL; | |
| sub_res_info = $3; | |
| style = 0; | |
| } | |
| styles BEG controls END | |
| { | |
| define_dialog ($1, &sub_res_info, &dialog); | |
| if (yychar != YYEMPTY) | |
| YYERROR; | |
| rcparse_discard_strings (); | |
| } | |
| | id DIALOGEX memflags_move exstyle posnumexpr cnumexpr cnumexpr | |
| cnumexpr cnumexpr | |
| { | |
| memset (&dialog, 0, sizeof dialog); | |
| dialog.x = $5; | |
| dialog.y = $6; | |
| dialog.width = $7; | |
| dialog.height = $8; | |
| dialog.style = WS_POPUP | WS_BORDER | WS_SYSMENU; | |
| dialog.exstyle = $4; | |
| dialog.menu.named = 1; | |
| dialog.class.named = 1; | |
| dialog.font = NULL; | |
| dialog.ex = ((rc_dialog_ex *) | |
| res_alloc (sizeof (rc_dialog_ex))); | |
| memset (dialog.ex, 0, sizeof (rc_dialog_ex)); | |
| dialog.ex->help = $9; | |
| dialog.controls = NULL; | |
| sub_res_info = $3; | |
| style = 0; | |
| } | |
| styles BEG controls END | |
| { | |
| define_dialog ($1, &sub_res_info, &dialog); | |
| if (yychar != YYEMPTY) | |
| YYERROR; | |
| rcparse_discard_strings (); | |
| } | |
| ; | |
| exstyle: | |
| /* empty */ | |
| { | |
| $$ = 0; | |
| } | |
| | EXSTYLE '=' numexpr | |
| { | |
| $$ = $3; | |
| } | |
| ; | |
| styles: | |
| /* empty */ | |
| | styles CAPTION res_unicode_string_concat | |
| { | |
| dialog.style |= WS_CAPTION; | |
| style |= WS_CAPTION; | |
| dialog.caption = $3; | |
| } | |
| | styles CLASS id | |
| { | |
| dialog.class = $3; | |
| } | |
| | styles STYLE | |
| styleexpr | |
| { | |
| dialog.style = style; | |
| } | |
| | styles EXSTYLE numexpr | |
| { | |
| dialog.exstyle = $3; | |
| } | |
| | styles CLASS res_unicode_string_concat | |
| { | |
| res_unistring_to_id (& dialog.class, $3); | |
| } | |
| | styles FONT numexpr ',' res_unicode_string_concat | |
| { | |
| dialog.style |= DS_SETFONT; | |
| style |= DS_SETFONT; | |
| dialog.pointsize = $3; | |
| dialog.font = $5; | |
| if (dialog.ex != NULL) | |
| { | |
| dialog.ex->weight = 0; | |
| dialog.ex->italic = 0; | |
| dialog.ex->charset = 1; | |
| } | |
| } | |
| | styles FONT numexpr ',' res_unicode_string_concat cnumexpr | |
| { | |
| dialog.style |= DS_SETFONT; | |
| style |= DS_SETFONT; | |
| dialog.pointsize = $3; | |
| dialog.font = $5; | |
| if (dialog.ex == NULL) | |
| rcparse_warning (_("extended FONT requires DIALOGEX")); | |
| else | |
| { | |
| dialog.ex->weight = $6; | |
| dialog.ex->italic = 0; | |
| dialog.ex->charset = 1; | |
| } | |
| } | |
| | styles FONT numexpr ',' res_unicode_string_concat cnumexpr cnumexpr | |
| { | |
| dialog.style |= DS_SETFONT; | |
| style |= DS_SETFONT; | |
| dialog.pointsize = $3; | |
| dialog.font = $5; | |
| if (dialog.ex == NULL) | |
| rcparse_warning (_("extended FONT requires DIALOGEX")); | |
| else | |
| { | |
| dialog.ex->weight = $6; | |
| dialog.ex->italic = $7; | |
| dialog.ex->charset = 1; | |
| } | |
| } | |
| | styles FONT numexpr ',' res_unicode_string_concat cnumexpr cnumexpr cnumexpr | |
| { | |
| dialog.style |= DS_SETFONT; | |
| style |= DS_SETFONT; | |
| dialog.pointsize = $3; | |
| dialog.font = $5; | |
| if (dialog.ex == NULL) | |
| rcparse_warning (_("extended FONT requires DIALOGEX")); | |
| else | |
| { | |
| dialog.ex->weight = $6; | |
| dialog.ex->italic = $7; | |
| dialog.ex->charset = $8; | |
| } | |
| } | |
| | styles MENU id | |
| { | |
| dialog.menu = $3; | |
| } | |
| | styles CHARACTERISTICS numexpr | |
| { | |
| sub_res_info.characteristics = $3; | |
| } | |
| | styles LANGUAGE numexpr cnumexpr | |
| { | |
| sub_res_info.language = $3 | ($4 << SUBLANG_SHIFT); | |
| } | |
| | styles VERSIONK numexpr | |
| { | |
| sub_res_info.version = $3; | |
| } | |
| ; | |
| controls: | |
| /* empty */ | |
| | controls control | |
| { | |
| rc_dialog_control **pp; | |
| for (pp = &dialog.controls; *pp != NULL; pp = &(*pp)->next) | |
| ; | |
| *pp = $2; | |
| } | |
| ; | |
| control: | |
| AUTO3STATE optresidc | |
| { | |
| default_style = BS_AUTO3STATE | WS_TABSTOP; | |
| base_style = BS_AUTO3STATE; | |
| class.named = 0; | |
| class.u.id = CTL_BUTTON; | |
| res_text_field = $2; | |
| } | |
| control_params | |
| { | |
| $$ = $4; | |
| } | |
| | AUTOCHECKBOX optresidc | |
| { | |
| default_style = BS_AUTOCHECKBOX | WS_TABSTOP; | |
| base_style = BS_AUTOCHECKBOX | WS_TABSTOP; | |
| class.named = 0; | |
| class.u.id = CTL_BUTTON; | |
| res_text_field = $2; | |
| } | |
| control_params | |
| { | |
| $$ = $4; | |
| } | |
| | AUTORADIOBUTTON optresidc | |
| { | |
| default_style = BS_AUTORADIOBUTTON | WS_TABSTOP; | |
| base_style = BS_AUTORADIOBUTTON; | |
| class.named = 0; | |
| class.u.id = CTL_BUTTON; | |
| res_text_field = $2; | |
| } | |
| control_params | |
| { | |
| $$ = $4; | |
| } | |
| | BEDIT optresidc | |
| { | |
| default_style = ES_LEFT | WS_BORDER | WS_TABSTOP; | |
| base_style = ES_LEFT | WS_BORDER | WS_TABSTOP; | |
| class.named = 0; | |
| class.u.id = CTL_EDIT; | |
| res_text_field = $2; | |
| } | |
| control_params | |
| { | |
| $$ = $4; | |
| if (dialog.ex == NULL) | |
| rcparse_warning (_("BEDIT requires DIALOGEX")); | |
| res_string_to_id (&$$->class, "BEDIT"); | |
| } | |
| | CHECKBOX optresidc | |
| { | |
| default_style = BS_CHECKBOX | WS_TABSTOP; | |
| base_style = BS_CHECKBOX | WS_TABSTOP; | |
| class.named = 0; | |
| class.u.id = CTL_BUTTON; | |
| res_text_field = $2; | |
| } | |
| control_params | |
| { | |
| $$ = $4; | |
| } | |
| | COMBOBOX | |
| { | |
| /* This is as per MSDN documentation. With some (???) | |
| versions of MS rc.exe their is no default style. */ | |
| default_style = CBS_SIMPLE | WS_TABSTOP; | |
| base_style = 0; | |
| class.named = 0; | |
| class.u.id = CTL_COMBOBOX; | |
| res_text_field = res_null_text; | |
| } | |
| control_params | |
| { | |
| $$ = $3; | |
| } | |
| | CONTROL optresidc numexpr cresid control_styleexpr cnumexpr | |
| cnumexpr cnumexpr cnumexpr optcnumexpr opt_control_data | |
| { | |
| $$ = define_control ($2, $3, $6, $7, $8, $9, $4, style, $10); | |
| if ($11 != NULL) | |
| { | |
| if (dialog.ex == NULL) | |
| rcparse_warning (_("control data requires DIALOGEX")); | |
| $$->data = $11; | |
| } | |
| } | |
| | CONTROL optresidc numexpr cresid control_styleexpr cnumexpr | |
| cnumexpr cnumexpr cnumexpr cnumexpr cnumexpr opt_control_data | |
| { | |
| $$ = define_control ($2, $3, $6, $7, $8, $9, $4, style, $10); | |
| if (dialog.ex == NULL) | |
| rcparse_warning (_("help ID requires DIALOGEX")); | |
| $$->help = $11; | |
| $$->data = $12; | |
| } | |
| | CTEXT optresidc | |
| { | |
| default_style = SS_CENTER | WS_GROUP; | |
| base_style = SS_CENTER; | |
| class.named = 0; | |
| class.u.id = CTL_STATIC; | |
| res_text_field = $2; | |
| } | |
| control_params | |
| { | |
| $$ = $4; | |
| } | |
| | DEFPUSHBUTTON optresidc | |
| { | |
| default_style = BS_DEFPUSHBUTTON | WS_TABSTOP; | |
| base_style = BS_DEFPUSHBUTTON | WS_TABSTOP; | |
| class.named = 0; | |
| class.u.id = CTL_BUTTON; | |
| res_text_field = $2; | |
| } | |
| control_params | |
| { | |
| $$ = $4; | |
| } | |
| | EDITTEXT | |
| { | |
| default_style = ES_LEFT | WS_BORDER | WS_TABSTOP; | |
| base_style = ES_LEFT | WS_BORDER | WS_TABSTOP; | |
| class.named = 0; | |
| class.u.id = CTL_EDIT; | |
| res_text_field = res_null_text; | |
| } | |
| control_params | |
| { | |
| $$ = $3; | |
| } | |
| | GROUPBOX optresidc | |
| { | |
| default_style = BS_GROUPBOX; | |
| base_style = BS_GROUPBOX; | |
| class.named = 0; | |
| class.u.id = CTL_BUTTON; | |
| res_text_field = $2; | |
| } | |
| control_params | |
| { | |
| $$ = $4; | |
| } | |
| | HEDIT optresidc | |
| { | |
| default_style = ES_LEFT | WS_BORDER | WS_TABSTOP; | |
| base_style = ES_LEFT | WS_BORDER | WS_TABSTOP; | |
| class.named = 0; | |
| class.u.id = CTL_EDIT; | |
| res_text_field = $2; | |
| } | |
| control_params | |
| { | |
| $$ = $4; | |
| if (dialog.ex == NULL) | |
| rcparse_warning (_("IEDIT requires DIALOGEX")); | |
| res_string_to_id (&$$->class, "HEDIT"); | |
| } | |
| | ICON resref numexpr cnumexpr cnumexpr opt_control_data | |
| { | |
| $$ = define_icon_control ($2, $3, $4, $5, 0, 0, 0, $6, | |
| dialog.ex); | |
| } | |
| | ICON resref numexpr cnumexpr cnumexpr cnumexpr cnumexpr | |
| opt_control_data | |
| { | |
| $$ = define_icon_control ($2, $3, $4, $5, 0, 0, 0, $8, | |
| dialog.ex); | |
| } | |
| | ICON resref numexpr cnumexpr cnumexpr cnumexpr cnumexpr | |
| icon_styleexpr optcnumexpr opt_control_data | |
| { | |
| $$ = define_icon_control ($2, $3, $4, $5, style, $9, 0, $10, | |
| dialog.ex); | |
| } | |
| | ICON resref numexpr cnumexpr cnumexpr cnumexpr cnumexpr | |
| icon_styleexpr cnumexpr cnumexpr opt_control_data | |
| { | |
| $$ = define_icon_control ($2, $3, $4, $5, style, $9, $10, $11, | |
| dialog.ex); | |
| } | |
| | IEDIT optresidc | |
| { | |
| default_style = ES_LEFT | WS_BORDER | WS_TABSTOP; | |
| base_style = ES_LEFT | WS_BORDER | WS_TABSTOP; | |
| class.named = 0; | |
| class.u.id = CTL_EDIT; | |
| res_text_field = $2; | |
| } | |
| control_params | |
| { | |
| $$ = $4; | |
| if (dialog.ex == NULL) | |
| rcparse_warning (_("IEDIT requires DIALOGEX")); | |
| res_string_to_id (&$$->class, "IEDIT"); | |
| } | |
| | LISTBOX | |
| { | |
| default_style = LBS_NOTIFY | WS_BORDER; | |
| base_style = LBS_NOTIFY | WS_BORDER; | |
| class.named = 0; | |
| class.u.id = CTL_LISTBOX; | |
| res_text_field = res_null_text; | |
| } | |
| control_params | |
| { | |
| $$ = $3; | |
| } | |
| | LTEXT optresidc | |
| { | |
| default_style = SS_LEFT | WS_GROUP; | |
| base_style = SS_LEFT; | |
| class.named = 0; | |
| class.u.id = CTL_STATIC; | |
| res_text_field = $2; | |
| } | |
| control_params | |
| { | |
| $$ = $4; | |
| } | |
| | PUSHBOX optresidc | |
| { | |
| default_style = BS_PUSHBOX | WS_TABSTOP; | |
| base_style = BS_PUSHBOX; | |
| class.named = 0; | |
| class.u.id = CTL_BUTTON; | |
| } | |
| control_params | |
| { | |
| $$ = $4; | |
| } | |
| | PUSHBUTTON optresidc | |
| { | |
| default_style = BS_PUSHBUTTON | WS_TABSTOP; | |
| base_style = BS_PUSHBUTTON | WS_TABSTOP; | |
| class.named = 0; | |
| class.u.id = CTL_BUTTON; | |
| res_text_field = $2; | |
| } | |
| control_params | |
| { | |
| $$ = $4; | |
| } | |
| | RADIOBUTTON optresidc | |
| { | |
| default_style = BS_RADIOBUTTON | WS_TABSTOP; | |
| base_style = BS_RADIOBUTTON; | |
| class.named = 0; | |
| class.u.id = CTL_BUTTON; | |
| res_text_field = $2; | |
| } | |
| control_params | |
| { | |
| $$ = $4; | |
| } | |
| | RTEXT optresidc | |
| { | |
| default_style = SS_RIGHT | WS_GROUP; | |
| base_style = SS_RIGHT; | |
| class.named = 0; | |
| class.u.id = CTL_STATIC; | |
| res_text_field = $2; | |
| } | |
| control_params | |
| { | |
| $$ = $4; | |
| } | |
| | SCROLLBAR | |
| { | |
| default_style = SBS_HORZ; | |
| base_style = 0; | |
| class.named = 0; | |
| class.u.id = CTL_SCROLLBAR; | |
| res_text_field = res_null_text; | |
| } | |
| control_params | |
| { | |
| $$ = $3; | |
| } | |
| | STATE3 optresidc | |
| { | |
| default_style = BS_3STATE | WS_TABSTOP; | |
| base_style = BS_3STATE; | |
| class.named = 0; | |
| class.u.id = CTL_BUTTON; | |
| res_text_field = $2; | |
| } | |
| control_params | |
| { | |
| $$ = $4; | |
| } | |
| | USERBUTTON resref numexpr ',' numexpr ',' numexpr ',' | |
| numexpr ',' numexpr ',' | |
| { style = WS_CHILD | WS_VISIBLE; } | |
| styleexpr optcnumexpr | |
| { | |
| rc_res_id cid; | |
| cid.named = 0; | |
| cid.u.id = CTL_BUTTON; | |
| $$ = define_control ($2, $3, $5, $7, $9, $11, cid, | |
| style, $15); | |
| } | |
| ; | |
| /* Parameters for a control. The static variables DEFAULT_STYLE, | |
| BASE_STYLE, and CLASS must be initialized before this nonterminal | |
| is used. DEFAULT_STYLE is the style to use if no style expression | |
| is specified. BASE_STYLE is the base style to use if a style | |
| expression is specified; the style expression modifies the base | |
| style. CLASS is the class of the control. */ | |
| control_params: | |
| numexpr cnumexpr cnumexpr cnumexpr cnumexpr opt_control_data | |
| { | |
| $$ = define_control (res_text_field, $1, $2, $3, $4, $5, class, | |
| default_style | WS_CHILD | WS_VISIBLE, 0); | |
| if ($6 != NULL) | |
| { | |
| if (dialog.ex == NULL) | |
| rcparse_warning (_("control data requires DIALOGEX")); | |
| $$->data = $6; | |
| } | |
| } | |
| | numexpr cnumexpr cnumexpr cnumexpr cnumexpr | |
| control_params_styleexpr optcnumexpr opt_control_data | |
| { | |
| $$ = define_control (res_text_field, $1, $2, $3, $4, $5, class, style, $7); | |
| if ($8 != NULL) | |
| { | |
| if (dialog.ex == NULL) | |
| rcparse_warning (_("control data requires DIALOGEX")); | |
| $$->data = $8; | |
| } | |
| } | |
| | numexpr cnumexpr cnumexpr cnumexpr cnumexpr | |
| control_params_styleexpr cnumexpr cnumexpr opt_control_data | |
| { | |
| $$ = define_control (res_text_field, $1, $2, $3, $4, $5, class, style, $7); | |
| if (dialog.ex == NULL) | |
| rcparse_warning (_("help ID requires DIALOGEX")); | |
| $$->help = $8; | |
| $$->data = $9; | |
| } | |
| ; | |
| cresid: | |
| ',' resid | |
| { | |
| if ($2.named) | |
| res_unistring_to_id (&$$, $2.u.n.name); | |
| else | |
| $$=$2; | |
| } | |
| ; | |
| optresidc: | |
| /* empty */ | |
| { | |
| res_string_to_id (&$$, ""); | |
| } | |
| | resid ',' { $$=$1; } | |
| ; | |
| resid: | |
| posnumexpr | |
| { | |
| $$.named = 0; | |
| $$.u.id = $1; | |
| } | |
| | res_unicode_string_concat | |
| { | |
| $$.named = 1; | |
| $$.u.n.name = $1; | |
| $$.u.n.length = unichar_len ($1); | |
| } | |
| ; | |
| opt_control_data: | |
| /* empty */ | |
| { | |
| $$ = NULL; | |
| } | |
| | BEG optrcdata_data END | |
| { | |
| $$ = $2.first; | |
| } | |
| ; | |
| /* These only exist to parse a reduction out of a common case. */ | |
| control_styleexpr: | |
| ',' | |
| { style = WS_CHILD | WS_VISIBLE; } | |
| styleexpr | |
| ; | |
| icon_styleexpr: | |
| ',' | |
| { style = SS_ICON | WS_CHILD | WS_VISIBLE; } | |
| styleexpr | |
| ; | |
| control_params_styleexpr: | |
| ',' | |
| { style = base_style | WS_CHILD | WS_VISIBLE; } | |
| styleexpr | |
| ; | |
| /* Font resources. */ | |
| font: | |
| id FONT memflags_move_discard file_name | |
| { | |
| define_font ($1, &$3, $4); | |
| if (yychar != YYEMPTY) | |
| YYERROR; | |
| rcparse_discard_strings (); | |
| } | |
| ; | |
| /* Icon resources. */ | |
| icon: | |
| id ICON memflags_move_discard file_name | |
| { | |
| define_icon ($1, &$3, $4); | |
| if (yychar != YYEMPTY) | |
| YYERROR; | |
| rcparse_discard_strings (); | |
| } | |
| ; | |
| /* Language command. This changes the static variable language, which | |
| affects all subsequent resources. */ | |
| language: | |
| LANGUAGE numexpr cnumexpr | |
| { | |
| language = $2 | ($3 << SUBLANG_SHIFT); | |
| } | |
| ; | |
| /* Menu resources. */ | |
| menu: | |
| id MENU suboptions BEG menuitems END | |
| { | |
| define_menu ($1, &$3, $5); | |
| if (yychar != YYEMPTY) | |
| YYERROR; | |
| rcparse_discard_strings (); | |
| } | |
| ; | |
| menuitems: | |
| /* empty */ | |
| { | |
| $$ = NULL; | |
| } | |
| | menuitems menuitem | |
| { | |
| if ($1 == NULL) | |
| $$ = $2; | |
| else | |
| { | |
| rc_menuitem **pp; | |
| for (pp = &$1->next; *pp != NULL; pp = &(*pp)->next) | |
| ; | |
| *pp = $2; | |
| $$ = $1; | |
| } | |
| } | |
| ; | |
| menuitem: | |
| MENUITEM res_unicode_string_concat cnumexpr menuitem_flags | |
| { | |
| $$ = define_menuitem ($2, $3, $4, 0, 0, NULL); | |
| } | |
| | MENUITEM SEPARATOR | |
| { | |
| $$ = define_menuitem (NULL, 0, 0, 0, 0, NULL); | |
| } | |
| | POPUP res_unicode_string_concat menuitem_flags BEG menuitems END | |
| { | |
| $$ = define_menuitem ($2, 0, $3, 0, 0, $5); | |
| } | |
| ; | |
| menuitem_flags: | |
| /* empty */ | |
| { | |
| $$ = 0; | |
| } | |
| | menuitem_flags ',' menuitem_flag | |
| { | |
| $$ = $1 | $3; | |
| } | |
| | menuitem_flags menuitem_flag | |
| { | |
| $$ = $1 | $2; | |
| } | |
| ; | |
| menuitem_flag: | |
| CHECKED | |
| { | |
| $$ = MENUITEM_CHECKED; | |
| } | |
| | GRAYED | |
| { | |
| $$ = MENUITEM_GRAYED; | |
| } | |
| | HELP | |
| { | |
| $$ = MENUITEM_HELP; | |
| } | |
| | INACTIVE | |
| { | |
| $$ = MENUITEM_INACTIVE; | |
| } | |
| | MENUBARBREAK | |
| { | |
| $$ = MENUITEM_MENUBARBREAK; | |
| } | |
| | MENUBREAK | |
| { | |
| $$ = MENUITEM_MENUBREAK; | |
| } | |
| | BITMAP | |
| { | |
| $$ = MENUITEM_BITMAP; | |
| } | |
| | OWNERDRAW | |
| { | |
| $$ = MENUITEM_OWNERDRAW; | |
| } | |
| ; | |
| /* Menuex resources. */ | |
| menuex: | |
| id MENUEX suboptions BEG menuexitems END | |
| { | |
| define_menu ($1, &$3, $5); | |
| if (yychar != YYEMPTY) | |
| YYERROR; | |
| rcparse_discard_strings (); | |
| } | |
| ; | |
| menuexitems: | |
| /* empty */ | |
| { | |
| $$ = NULL; | |
| } | |
| | menuexitems menuexitem | |
| { | |
| if ($1 == NULL) | |
| $$ = $2; | |
| else | |
| { | |
| rc_menuitem **pp; | |
| for (pp = &$1->next; *pp != NULL; pp = &(*pp)->next) | |
| ; | |
| *pp = $2; | |
| $$ = $1; | |
| } | |
| } | |
| ; | |
| menuexitem: | |
| MENUITEM res_unicode_string_concat | |
| { | |
| $$ = define_menuitem ($2, 0, 0, 0, 0, NULL); | |
| } | |
| | MENUITEM res_unicode_string_concat cnumexpr | |
| { | |
| $$ = define_menuitem ($2, $3, 0, 0, 0, NULL); | |
| } | |
| | MENUITEM res_unicode_string_concat cnumexpr cnumexpr optcnumexpr | |
| { | |
| $$ = define_menuitem ($2, $3, $4, $5, 0, NULL); | |
| } | |
| | MENUITEM SEPARATOR | |
| { | |
| $$ = define_menuitem (NULL, 0, 0, 0, 0, NULL); | |
| } | |
| | POPUP res_unicode_string_concat BEG menuexitems END | |
| { | |
| $$ = define_menuitem ($2, 0, 0, 0, 0, $4); | |
| } | |
| | POPUP res_unicode_string_concat cnumexpr BEG menuexitems END | |
| { | |
| $$ = define_menuitem ($2, $3, 0, 0, 0, $5); | |
| } | |
| | POPUP res_unicode_string_concat cnumexpr cnumexpr BEG menuexitems END | |
| { | |
| $$ = define_menuitem ($2, $3, $4, 0, 0, $6); | |
| } | |
| | POPUP res_unicode_string_concat cnumexpr cnumexpr cnumexpr optcnumexpr | |
| BEG menuexitems END | |
| { | |
| $$ = define_menuitem ($2, $3, $4, $5, $6, $8); | |
| } | |
| ; | |
| /* Messagetable resources. */ | |
| messagetable: | |
| id MESSAGETABLE memflags_move file_name | |
| { | |
| define_messagetable ($1, &$3, $4); | |
| if (yychar != YYEMPTY) | |
| YYERROR; | |
| rcparse_discard_strings (); | |
| } | |
| ; | |
| /* We use a different lexing algorithm, because rcdata strings may | |
| contain embedded null bytes, and we need to know the length to use. */ | |
| optrcdata_data: | |
| { | |
| rcparse_rcdata (); | |
| } | |
| optrcdata_data_int | |
| { | |
| rcparse_normal (); | |
| $$ = $2; | |
| } | |
| ; | |
| optrcdata_data_int: | |
| /* empty */ | |
| { | |
| $$.first = NULL; | |
| $$.last = NULL; | |
| } | |
| | rcdata_data | |
| { | |
| $$ = $1; | |
| } | |
| ; | |
| rcdata_data: | |
| sizedstring | |
| { | |
| rc_rcdata_item *ri; | |
| ri = define_rcdata_string ($1.s, $1.length); | |
| $$.first = ri; | |
| $$.last = ri; | |
| } | |
| | sizedunistring | |
| { | |
| rc_rcdata_item *ri; | |
| ri = define_rcdata_unistring ($1.s, $1.length); | |
| $$.first = ri; | |
| $$.last = ri; | |
| } | |
| | sizednumexpr | |
| { | |
| rc_rcdata_item *ri; | |
| ri = define_rcdata_number ($1.val, $1.dword); | |
| $$.first = ri; | |
| $$.last = ri; | |
| } | |
| | rcdata_data ',' sizedstring | |
| { | |
| rc_rcdata_item *ri; | |
| ri = define_rcdata_string ($3.s, $3.length); | |
| $$.first = $1.first; | |
| $1.last->next = ri; | |
| $$.last = ri; | |
| } | |
| | rcdata_data ',' sizedunistring | |
| { | |
| rc_rcdata_item *ri; | |
| ri = define_rcdata_unistring ($3.s, $3.length); | |
| $$.first = $1.first; | |
| $1.last->next = ri; | |
| $$.last = ri; | |
| } | |
| | rcdata_data ',' sizednumexpr | |
| { | |
| rc_rcdata_item *ri; | |
| ri = define_rcdata_number ($3.val, $3.dword); | |
| $$.first = $1.first; | |
| $1.last->next = ri; | |
| $$.last = ri; | |
| } | |
| | rcdata_data ',' | |
| { | |
| $$=$1; | |
| } | |
| ; | |
| /* Stringtable resources. */ | |
| stringtable: | |
| STRINGTABLE suboptions BEG | |
| { sub_res_info = $2; rcparse_rcdata (); } | |
| string_data END { rcparse_normal (); } | |
| ; | |
| string_data: | |
| /* empty */ | |
| | string_data numexpr res_unicode_sizedstring_concat | |
| { | |
| define_stringtable (&sub_res_info, $2, $3.s, $3.length); | |
| rcparse_discard_strings (); | |
| } | |
| | string_data numexpr ',' res_unicode_sizedstring_concat | |
| { | |
| define_stringtable (&sub_res_info, $2, $4.s, $4.length); | |
| rcparse_discard_strings (); | |
| } | |
| | string_data error | |
| { | |
| rcparse_warning (_("invalid stringtable resource.")); | |
| abort (); | |
| } | |
| ; | |
| rcdata_id: | |
| id | |
| { | |
| $$=$1; | |
| } | |
| | HTML | |
| { | |
| $$.named = 0; | |
| $$.u.id = 23; | |
| } | |
| | RCDATA | |
| { | |
| $$.named = 0; | |
| $$.u.id = RT_RCDATA; | |
| } | |
| | MANIFEST | |
| { | |
| $$.named = 0; | |
| $$.u.id = RT_MANIFEST; | |
| } | |
| | PLUGPLAY | |
| { | |
| $$.named = 0; | |
| $$.u.id = RT_PLUGPLAY; | |
| } | |
| | VXD | |
| { | |
| $$.named = 0; | |
| $$.u.id = RT_VXD; | |
| } | |
| | DLGINCLUDE | |
| { | |
| $$.named = 0; | |
| $$.u.id = RT_DLGINCLUDE; | |
| } | |
| | DLGINIT | |
| { | |
| $$.named = 0; | |
| $$.u.id = RT_DLGINIT; | |
| } | |
| | ANICURSOR | |
| { | |
| $$.named = 0; | |
| $$.u.id = RT_ANICURSOR; | |
| } | |
| | ANIICON | |
| { | |
| $$.named = 0; | |
| $$.u.id = RT_ANIICON; | |
| } | |
| ; | |
| /* User defined resources. We accept general suboptions in the | |
| file_name case to keep the parser happy. */ | |
| user: | |
| id rcdata_id suboptions BEG optrcdata_data END | |
| { | |
| define_user_data ($1, $2, &$3, $5.first); | |
| if (yychar != YYEMPTY) | |
| YYERROR; | |
| rcparse_discard_strings (); | |
| } | |
| | id rcdata_id suboptions file_name | |
| { | |
| define_user_file ($1, $2, &$3, $4); | |
| if (yychar != YYEMPTY) | |
| YYERROR; | |
| rcparse_discard_strings (); | |
| } | |
| ; | |
| toolbar: | |
| id TOOLBAR suboptions numexpr cnumexpr BEG toolbar_data END | |
| { | |
| define_toolbar ($1, &$3, $4, $5, $7); | |
| } | |
| ; | |
| toolbar_data: /* empty */ { $$= NULL; } | |
| | toolbar_data BUTTON id | |
| { | |
| rc_toolbar_item *c,*n; | |
| c = $1; | |
| n= (rc_toolbar_item *) | |
| res_alloc (sizeof (rc_toolbar_item)); | |
| if (c != NULL) | |
| while (c->next != NULL) | |
| c = c->next; | |
| n->prev = c; | |
| n->next = NULL; | |
| if (c != NULL) | |
| c->next = n; | |
| n->id = $3; | |
| if ($1 == NULL) | |
| $$ = n; | |
| else | |
| $$ = $1; | |
| } | |
| | toolbar_data SEPARATOR | |
| { | |
| rc_toolbar_item *c,*n; | |
| c = $1; | |
| n= (rc_toolbar_item *) | |
| res_alloc (sizeof (rc_toolbar_item)); | |
| if (c != NULL) | |
| while (c->next != NULL) | |
| c = c->next; | |
| n->prev = c; | |
| n->next = NULL; | |
| if (c != NULL) | |
| c->next = n; | |
| n->id.named = 0; | |
| n->id.u.id = 0; | |
| if ($1 == NULL) | |
| $$ = n; | |
| else | |
| $$ = $1; | |
| } | |
| ; | |
| /* Versioninfo resources. */ | |
| versioninfo: | |
| id VERSIONINFO fixedverinfo BEG verblocks END | |
| { | |
| define_versioninfo ($1, language, $3, $5); | |
| if (yychar != YYEMPTY) | |
| YYERROR; | |
| rcparse_discard_strings (); | |
| } | |
| ; | |
| fixedverinfo: | |
| /* empty */ | |
| { | |
| $$ = ((rc_fixed_versioninfo *) | |
| res_alloc (sizeof (rc_fixed_versioninfo))); | |
| memset ($$, 0, sizeof (rc_fixed_versioninfo)); | |
| } | |
| | fixedverinfo FILEVERSION numexpr optcnumexpr optcnumexpr | |
| optcnumexpr | |
| { | |
| $1->file_version_ms = ($3 << 16) | ($4 & 0xffff); | |
| $1->file_version_ls = ($5 << 16) | ($6 & 0xffff); | |
| $$ = $1; | |
| } | |
| | fixedverinfo PRODUCTVERSION numexpr optcnumexpr optcnumexpr | |
| optcnumexpr | |
| { | |
| $1->product_version_ms = ($3 << 16) | ($4 & 0xffff); | |
| $1->product_version_ls = ($5 << 16) | ($6 & 0xffff); | |
| $$ = $1; | |
| } | |
| | fixedverinfo FILEFLAGSMASK numexpr | |
| { | |
| $1->file_flags_mask = $3; | |
| $$ = $1; | |
| } | |
| | fixedverinfo FILEFLAGS numexpr | |
| { | |
| $1->file_flags = $3; | |
| $$ = $1; | |
| } | |
| | fixedverinfo FILEOS numexpr | |
| { | |
| $1->file_os = $3; | |
| $$ = $1; | |
| } | |
| | fixedverinfo FILETYPE numexpr | |
| { | |
| $1->file_type = $3; | |
| $$ = $1; | |
| } | |
| | fixedverinfo FILESUBTYPE numexpr | |
| { | |
| $1->file_subtype = $3; | |
| $$ = $1; | |
| } | |
| ; | |
| /* To handle verblocks successfully, the lexer handles BLOCK | |
| specially. A BLOCK "StringFileInfo" is returned as | |
| BLOCKSTRINGFILEINFO. A BLOCK "VarFileInfo" is returned as | |
| BLOCKVARFILEINFO. A BLOCK with some other string returns BLOCK | |
| with the string as the value. */ | |
| verblocks: | |
| /* empty */ | |
| { | |
| $$ = NULL; | |
| } | |
| | verblocks BLOCKSTRINGFILEINFO BEG verstringtables END | |
| { | |
| $$ = append_ver_stringfileinfo ($1, $4); | |
| } | |
| | verblocks BLOCKVARFILEINFO BEG VALUE res_unicode_string_concat vertrans END | |
| { | |
| $$ = append_ver_varfileinfo ($1, $5, $6); | |
| } | |
| ; | |
| verstringtables: | |
| /* empty */ | |
| { | |
| $$ = NULL; | |
| } | |
| | verstringtables BLOCK BEG vervals END | |
| { | |
| $$ = append_ver_stringtable ($1, $2, $4); | |
| } | |
| ; | |
| vervals: | |
| /* empty */ | |
| { | |
| $$ = NULL; | |
| } | |
| | vervals VALUE res_unicode_string_concat ',' res_unicode_string_concat | |
| { | |
| $$ = append_verval ($1, $3, $5); | |
| } | |
| ; | |
| vertrans: | |
| /* empty */ | |
| { | |
| $$ = NULL; | |
| } | |
| | vertrans cnumexpr cnumexpr | |
| { | |
| $$ = append_vertrans ($1, $2, $3); | |
| } | |
| ; | |
| /* A resource ID. */ | |
| id: | |
| posnumexpr | |
| { | |
| $$.named = 0; | |
| $$.u.id = $1; | |
| } | |
| | resname | |
| { | |
| res_unistring_to_id (&$$, $1); | |
| } | |
| ; | |
| /* A resource reference. */ | |
| resname: | |
| res_unicode_string | |
| { | |
| $$ = $1; | |
| } | |
| | STRING | |
| { | |
| unichar *h = NULL; | |
| unicode_from_ascii ((rc_uint_type *) NULL, &h, $1); | |
| $$ = h; | |
| } | |
| ; | |
| resref: | |
| posnumexpr ',' | |
| { | |
| $$.named = 0; | |
| $$.u.id = $1; | |
| } | |
| | resname | |
| { | |
| res_unistring_to_id (&$$, $1); | |
| } | |
| | resname ',' | |
| { | |
| res_unistring_to_id (&$$, $1); | |
| } | |
| ; | |
| /* Generic suboptions. These may appear before the BEGIN in any | |
| multiline statement. */ | |
| suboptions: | |
| /* empty */ | |
| { | |
| memset (&$$, 0, sizeof (rc_res_res_info)); | |
| $$.language = language; | |
| /* FIXME: Is this the right default? */ | |
| $$.memflags = MEMFLAG_MOVEABLE | MEMFLAG_PURE | MEMFLAG_DISCARDABLE; | |
| } | |
| | suboptions memflag | |
| { | |
| $$ = $1; | |
| $$.memflags |= $2.on; | |
| $$.memflags &=~ $2.off; | |
| } | |
| | suboptions CHARACTERISTICS numexpr | |
| { | |
| $$ = $1; | |
| $$.characteristics = $3; | |
| } | |
| | suboptions LANGUAGE numexpr cnumexpr | |
| { | |
| $$ = $1; | |
| $$.language = $3 | ($4 << SUBLANG_SHIFT); | |
| } | |
| | suboptions VERSIONK numexpr | |
| { | |
| $$ = $1; | |
| $$.version = $3; | |
| } | |
| ; | |
| /* Memory flags which default to MOVEABLE and DISCARDABLE. */ | |
| memflags_move_discard: | |
| /* empty */ | |
| { | |
| memset (&$$, 0, sizeof (rc_res_res_info)); | |
| $$.language = language; | |
| $$.memflags = MEMFLAG_MOVEABLE | MEMFLAG_DISCARDABLE; | |
| } | |
| | memflags_move_discard memflag | |
| { | |
| $$ = $1; | |
| $$.memflags |= $2.on; | |
| $$.memflags &=~ $2.off; | |
| } | |
| ; | |
| /* Memory flags which default to MOVEABLE. */ | |
| memflags_move: | |
| /* empty */ | |
| { | |
| memset (&$$, 0, sizeof (rc_res_res_info)); | |
| $$.language = language; | |
| $$.memflags = MEMFLAG_MOVEABLE | MEMFLAG_PURE | MEMFLAG_DISCARDABLE; | |
| } | |
| | memflags_move memflag | |
| { | |
| $$ = $1; | |
| $$.memflags |= $2.on; | |
| $$.memflags &=~ $2.off; | |
| } | |
| ; | |
| /* Memory flags. This returns a struct with two integers, because we | |
| sometimes want to set bits and we sometimes want to clear them. */ | |
| memflag: | |
| MOVEABLE | |
| { | |
| $$.on = MEMFLAG_MOVEABLE; | |
| $$.off = 0; | |
| } | |
| | FIXED | |
| { | |
| $$.on = 0; | |
| $$.off = MEMFLAG_MOVEABLE; | |
| } | |
| | PURE | |
| { | |
| $$.on = MEMFLAG_PURE; | |
| $$.off = 0; | |
| } | |
| | IMPURE | |
| { | |
| $$.on = 0; | |
| $$.off = MEMFLAG_PURE; | |
| } | |
| | PRELOAD | |
| { | |
| $$.on = MEMFLAG_PRELOAD; | |
| $$.off = 0; | |
| } | |
| | LOADONCALL | |
| { | |
| $$.on = 0; | |
| $$.off = MEMFLAG_PRELOAD; | |
| } | |
| | DISCARDABLE | |
| { | |
| $$.on = MEMFLAG_DISCARDABLE; | |
| $$.off = 0; | |
| } | |
| ; | |
| /* A file name. */ | |
| file_name: | |
| QUOTEDSTRING | |
| { | |
| $$ = $1; | |
| } | |
| | STRING | |
| { | |
| $$ = $1; | |
| } | |
| ; | |
| /* Concat string */ | |
| res_unicode_string_concat: | |
| res_unicode_string | |
| { | |
| $$ = $1; | |
| } | |
| | | |
| res_unicode_string_concat res_unicode_string | |
| { | |
| rc_uint_type l1 = unichar_len ($1); | |
| rc_uint_type l2 = unichar_len ($2); | |
| unichar *h = (unichar *) res_alloc ((l1 + l2 + 1) * sizeof (unichar)); | |
| if (l1 != 0) | |
| memcpy (h, $1, l1 * sizeof (unichar)); | |
| if (l2 != 0) | |
| memcpy (h + l1, $2, l2 * sizeof (unichar)); | |
| h[l1 + l2] = 0; | |
| $$ = h; | |
| } | |
| ; | |
| res_unicode_string: | |
| QUOTEDUNISTRING | |
| { | |
| $$ = unichar_dup ($1); | |
| } | |
| | QUOTEDSTRING | |
| { | |
| unichar *h = NULL; | |
| unicode_from_ascii ((rc_uint_type *) NULL, &h, $1); | |
| $$ = h; | |
| } | |
| ; | |
| res_unicode_sizedstring: | |
| sizedunistring | |
| { | |
| $$ = $1; | |
| } | |
| | sizedstring | |
| { | |
| unichar *h = NULL; | |
| rc_uint_type l = 0; | |
| unicode_from_ascii_len (&l, &h, $1.s, $1.length); | |
| $$.s = h; | |
| $$.length = l; | |
| } | |
| ; | |
| /* Concat string */ | |
| res_unicode_sizedstring_concat: | |
| res_unicode_sizedstring | |
| { | |
| $$ = $1; | |
| } | |
| | | |
| res_unicode_sizedstring_concat res_unicode_sizedstring | |
| { | |
| rc_uint_type l1 = $1.length; | |
| rc_uint_type l2 = $2.length; | |
| unichar *h = (unichar *) res_alloc ((l1 + l2 + 1) * sizeof (unichar)); | |
| if (l1 != 0) | |
| memcpy (h, $1.s, l1 * sizeof (unichar)); | |
| if (l2 != 0) | |
| memcpy (h + l1, $2.s, l2 * sizeof (unichar)); | |
| h[l1 + l2] = 0; | |
| $$.length = l1 + l2; | |
| $$.s = h; | |
| } | |
| ; | |
| sizedstring: | |
| SIZEDSTRING | |
| { | |
| $$ = $1; | |
| } | |
| | sizedstring SIZEDSTRING | |
| { | |
| rc_uint_type l = $1.length + $2.length; | |
| char *h = (char *) res_alloc (l); | |
| memcpy (h, $1.s, $1.length); | |
| memcpy (h + $1.length, $2.s, $2.length); | |
| $$.s = h; | |
| $$.length = l; | |
| } | |
| ; | |
| sizedunistring: | |
| SIZEDUNISTRING | |
| { | |
| $$ = $1; | |
| } | |
| | sizedunistring SIZEDUNISTRING | |
| { | |
| rc_uint_type l = $1.length + $2.length; | |
| unichar *h = (unichar *) res_alloc (l * sizeof (unichar)); | |
| memcpy (h, $1.s, $1.length * sizeof (unichar)); | |
| memcpy (h + $1.length, $2.s, $2.length * sizeof (unichar)); | |
| $$.s = h; | |
| $$.length = l; | |
| } | |
| ; | |
| /* A style expression. This changes the static variable STYLE. We do | |
| it this way because rc appears to permit a style to be set to | |
| something like | |
| WS_GROUP | NOT WS_TABSTOP | |
| to mean that a default of WS_TABSTOP should be removed. Anything | |
| which wants to accept a style must first set STYLE to the default | |
| value. The styleexpr nonterminal will change STYLE as specified by | |
| the user. Note that we do not accept arbitrary expressions here, | |
| just numbers separated by '|'. */ | |
| styleexpr: | |
| parennumber | |
| { | |
| style |= $1; | |
| } | |
| | NOT parennumber | |
| { | |
| style &=~ $2; | |
| } | |
| | styleexpr '|' parennumber | |
| { | |
| style |= $3; | |
| } | |
| | styleexpr '|' NOT parennumber | |
| { | |
| style &=~ $4; | |
| } | |
| ; | |
| parennumber: | |
| NUMBER | |
| { | |
| $$ = $1.val; | |
| } | |
| | '(' numexpr ')' | |
| { | |
| $$ = $2; | |
| } | |
| ; | |
| /* An optional expression with a leading comma. */ | |
| optcnumexpr: | |
| /* empty */ | |
| { | |
| $$ = 0; | |
| } | |
| | cnumexpr | |
| { | |
| $$ = $1; | |
| } | |
| ; | |
| /* An expression with a leading comma. */ | |
| cnumexpr: | |
| ',' numexpr | |
| { | |
| $$ = $2; | |
| } | |
| ; | |
| /* A possibly negated numeric expression. */ | |
| numexpr: | |
| sizednumexpr | |
| { | |
| $$ = $1.val; | |
| } | |
| ; | |
| /* A possibly negated expression with a size. */ | |
| sizednumexpr: | |
| NUMBER | |
| { | |
| $$ = $1; | |
| } | |
| | '(' sizednumexpr ')' | |
| { | |
| $$ = $2; | |
| } | |
| | '~' sizednumexpr %prec '~' | |
| { | |
| $$.val = ~ $2.val; | |
| $$.dword = $2.dword; | |
| } | |
| | '-' sizednumexpr %prec NEG | |
| { | |
| $$.val = - $2.val; | |
| $$.dword = $2.dword; | |
| } | |
| | sizednumexpr '*' sizednumexpr | |
| { | |
| $$.val = $1.val * $3.val; | |
| $$.dword = $1.dword || $3.dword; | |
| } | |
| | sizednumexpr '/' sizednumexpr | |
| { | |
| $$.val = $1.val / ($3.val ? $3.val : 1); | |
| $$.dword = $1.dword || $3.dword; | |
| } | |
| | sizednumexpr '%' sizednumexpr | |
| { | |
| $$.val = $1.val % ($3.val ? $3.val : 1); | |
| $$.dword = $1.dword || $3.dword; | |
| } | |
| | sizednumexpr '+' sizednumexpr | |
| { | |
| $$.val = $1.val + $3.val; | |
| $$.dword = $1.dword || $3.dword; | |
| } | |
| | sizednumexpr '-' sizednumexpr | |
| { | |
| $$.val = $1.val - $3.val; | |
| $$.dword = $1.dword || $3.dword; | |
| } | |
| | sizednumexpr '&' sizednumexpr | |
| { | |
| $$.val = $1.val & $3.val; | |
| $$.dword = $1.dword || $3.dword; | |
| } | |
| | sizednumexpr '^' sizednumexpr | |
| { | |
| $$.val = $1.val ^ $3.val; | |
| $$.dword = $1.dword || $3.dword; | |
| } | |
| | sizednumexpr '|' sizednumexpr | |
| { | |
| $$.val = $1.val | $3.val; | |
| $$.dword = $1.dword || $3.dword; | |
| } | |
| ; | |
| /* An expression with a leading comma which does not use unary | |
| negation. */ | |
| cposnumexpr: | |
| ',' posnumexpr | |
| { | |
| $$ = $2; | |
| } | |
| ; | |
| /* An expression which does not use unary negation. */ | |
| posnumexpr: | |
| sizedposnumexpr | |
| { | |
| $$ = $1.val; | |
| } | |
| ; | |
| /* An expression which does not use unary negation. We separate unary | |
| negation to avoid parsing conflicts when two numeric expressions | |
| appear consecutively. */ | |
| sizedposnumexpr: | |
| NUMBER | |
| { | |
| $$ = $1; | |
| } | |
| | '(' sizednumexpr ')' | |
| { | |
| $$ = $2; | |
| } | |
| | '~' sizednumexpr %prec '~' | |
| { | |
| $$.val = ~ $2.val; | |
| $$.dword = $2.dword; | |
| } | |
| | sizedposnumexpr '*' sizednumexpr | |
| { | |
| $$.val = $1.val * $3.val; | |
| $$.dword = $1.dword || $3.dword; | |
| } | |
| | sizedposnumexpr '/' sizednumexpr | |
| { | |
| $$.val = $1.val / ($3.val ? $3.val : 1); | |
| $$.dword = $1.dword || $3.dword; | |
| } | |
| | sizedposnumexpr '%' sizednumexpr | |
| { | |
| /* PR 17512: file: 89105a25. */ | |
| $$.val = $1.val % ($3.val ? $3.val : 1); | |
| $$.dword = $1.dword || $3.dword; | |
| } | |
| | sizedposnumexpr '+' sizednumexpr | |
| { | |
| $$.val = $1.val + $3.val; | |
| $$.dword = $1.dword || $3.dword; | |
| } | |
| | sizedposnumexpr '-' sizednumexpr | |
| { | |
| $$.val = $1.val - $3.val; | |
| $$.dword = $1.dword || $3.dword; | |
| } | |
| | sizedposnumexpr '&' sizednumexpr | |
| { | |
| $$.val = $1.val & $3.val; | |
| $$.dword = $1.dword || $3.dword; | |
| } | |
| | sizedposnumexpr '^' sizednumexpr | |
| { | |
| $$.val = $1.val ^ $3.val; | |
| $$.dword = $1.dword || $3.dword; | |
| } | |
| | sizedposnumexpr '|' sizednumexpr | |
| { | |
| $$.val = $1.val | $3.val; | |
| $$.dword = $1.dword || $3.dword; | |
| } | |
| ; | |
| %% | |
| /* Set the language from the command line. */ | |
| void | |
| rcparse_set_language (int lang) | |
| { | |
| language = lang; | |
| } |