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