summaryrefslogtreecommitdiffstats
path: root/binutils-2.25/binutils/rcparse.y
diff options
context:
space:
mode:
Diffstat (limited to 'binutils-2.25/binutils/rcparse.y')
-rw-r--r--binutils-2.25/binutils/rcparse.y2013
1 files changed, 2013 insertions, 0 deletions
diff --git a/binutils-2.25/binutils/rcparse.y b/binutils-2.25/binutils/rcparse.y
new file mode 100644
index 00000000..f4101d59
--- /dev/null
+++ b/binutils-2.25/binutils/rcparse.y
@@ -0,0 +1,2013 @@
+%{ /* rcparse.y -- parser for Windows rc files
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2007, 2008,
+ 2011 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
+%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;
+ 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;
+ }
+ ;
+
+/* 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;
+ $1->file_version_ls = ($5 << 16) | $6;
+ $$ = $1;
+ }
+ | fixedverinfo PRODUCTVERSION numexpr optcnumexpr optcnumexpr
+ optcnumexpr
+ {
+ $1->product_version_ms = ($3 << 16) | $4;
+ $1->product_version_ls = ($5 << 16) | $6;
+ $$ = $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;
+ $$.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;
+ }
+ | 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;
+ $$.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;
+ }
+ | 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;
+}