2014 lines
40 KiB
Plaintext
2014 lines
40 KiB
Plaintext
%{ /* rcparse.y -- parser for Windows rc files
|
|
Copyright (C) 1997-2017 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 & 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;
|
|
}
|