// This file is based on ld/ldgram.y and ld/ldlex.l from the binutils-gdb git repository. Original license header: /* A YACC grammar to parse a superset of the AT&T linker scripting language. Copyright (C) 1991-2016 Free Software Foundation, Inc. Written by Steve Chamberlain of Cygnus Support (steve@cygnus.com). This file is part of the 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. */ parser grammar GnuLdParser; options { tokenVocab = GnuLdLexer; } /* TODO: check right associative annotations */ /* %token INT %token NAME LNAME */ /* %right UNARY %token END %left LPAREN */ file: /*INPUT_SCRIPT*/ script_file | /*INPUT_MRI_SCRIPT*/ mri_script_file | /*INPUT_VERSION_SCRIPT*/ version_script_file | /*INPUT_DYNAMIC_LIST*/ dynamic_list_file | /*INPUT_DEFSYM*/ defsym_expr ; filename: NAME; defsym_expr: NAME EQ exp ; /* SYNTAX WITHIN AN MRI SCRIPT FILE */ mri_script_file: mri_script_lines ; mri_script_lines: mri_script_lines mri_script_command NEWLINE | ; mri_script_command: CHIP exp | CHIP exp COMMA exp | NAME | LIST | ORDER ordernamelist | ENDWORD | PUBLIC NAME EQ exp | PUBLIC NAME COMMA exp | PUBLIC NAME exp | FORMAT NAME | SECT NAME COMMA exp | SECT NAME exp | SECT NAME EQ exp | ALIGN_K NAME EQ exp | ALIGN_K NAME COMMA exp | ALIGNMOD NAME EQ exp | ALIGNMOD NAME COMMA exp | ABSOLUTE mri_abs_name_list | LOAD mri_load_name_list | NAMEWORD NAME | ALIAS NAME COMMA NAME | ALIAS NAME COMMA INT | BASE exp | TRUNCATE INT | CASE casesymlist | EXTERN extern_name_list | INCLUDE filename mri_script_lines END | START NAME | ; ordernamelist: ordernamelist COMMA NAME | ordernamelist NAME | ; mri_load_name_list: NAME | mri_load_name_list COMMA NAME ; mri_abs_name_list: NAME | mri_abs_name_list COMMA NAME ; casesymlist: /* empty */ | NAME | casesymlist COMMA NAME ; /* Parsed as expressions so that commas separate entries */ extern_name_list: extern_name_list_body ; extern_name_list_body: NAME | extern_name_list_body NAME | extern_name_list_body COMMA NAME ; script_file: ifile_list ; ifile_list: ifile_list ifile_p1 | ; ifile_p1: memory | sections | phdrs | startup | high_level_library | low_level_library | floating_point_support | statement_anywhere | version | SEMICOLON | TARGET_K LPAREN NAME RPAREN | SEARCH_DIR LPAREN filename RPAREN | OUTPUT LPAREN filename RPAREN | OUTPUT_FORMAT LPAREN NAME RPAREN | OUTPUT_FORMAT LPAREN NAME COMMA NAME COMMA NAME RPAREN | OUTPUT_ARCH LPAREN NAME RPAREN | FORCE_COMMON_ALLOCATION | INHIBIT_COMMON_ALLOCATION | INPUT LPAREN input_list RPAREN | GROUP LPAREN input_list RPAREN | MAP LPAREN filename RPAREN | INCLUDE filename ifile_list END | NOCROSSREFS LPAREN nocrossref_list RPAREN | NOCROSSREFS_TO LPAREN nocrossref_list RPAREN | EXTERN LPAREN extern_name_list RPAREN | INSERT_K AFTER NAME | INSERT_K BEFORE NAME | REGION_ALIAS LPAREN NAME COMMA NAME RPAREN | LD_FEATURE LPAREN NAME RPAREN ; input_list: input_list1 ; input_list1: NAME | input_list1 COMMA NAME | input_list1 NAME | LNAME | input_list1 COMMA LNAME | input_list1 LNAME | AS_NEEDED LPAREN | input_list1 COMMA AS_NEEDED LPAREN | input_list1 AS_NEEDED LPAREN ; sections: SECTIONS LBRACE sec_or_group_p1 RBRACE ; sec_or_group_p1: sec_or_group_p1 section | sec_or_group_p1 statement_anywhere | ; statement_anywhere: ENTRY LPAREN NAME RPAREN | assignment end | ASSERT LPAREN exp COMMA string RPAREN ; /* The '*' and '?' cases are there because the lexer returns them as separate tokens rather than as name. */ wildcard_name: NAME | STAR | QUESTION ; // SORT(*) and SORT_BY_NAME(*) both mean the same sort_by_name: SORT | SORT_BY_NAME ; wildcard_spec: wildcard_name | EXCLUDE_FILE LPAREN exclude_name_list RPAREN wildcard_name | sort_by_name LPAREN wildcard_name RPAREN | SORT_BY_ALIGNMENT LPAREN wildcard_name RPAREN | SORT_NONE LPAREN wildcard_name RPAREN | sort_by_name LPAREN SORT_BY_ALIGNMENT LPAREN wildcard_name RPAREN RPAREN | sort_by_name LPAREN sort_by_name LPAREN wildcard_name RPAREN RPAREN | SORT_BY_ALIGNMENT LPAREN sort_by_name LPAREN wildcard_name RPAREN RPAREN | SORT_BY_ALIGNMENT LPAREN SORT_BY_ALIGNMENT LPAREN wildcard_name RPAREN RPAREN | sort_by_name LPAREN EXCLUDE_FILE LPAREN exclude_name_list RPAREN wildcard_name RPAREN | SORT_BY_INIT_PRIORITY LPAREN wildcard_name RPAREN ; sect_flag_list: NAME | sect_flag_list AMPERSAND NAME ; sect_flags: /*not used by antlr: INPUT_SECTION_FLAGS*/ LPAREN sect_flag_list RPAREN ; exclude_name_list: exclude_name_list wildcard_name | wildcard_name ; file_name_list: file_name_list opt_comma wildcard_spec | wildcard_spec ; input_section_spec_no_keep: NAME | sect_flags NAME | LBRACKET file_name_list RBRACKET | sect_flags LBRACKET file_name_list RBRACKET | wildcard_spec LPAREN file_name_list RPAREN | sect_flags wildcard_spec LPAREN file_name_list RPAREN ; input_section_spec: input_section_spec_no_keep | KEEP LPAREN input_section_spec_no_keep RPAREN ; statement: assignment end | CREATE_OBJECT_SYMBOLS | SEMICOLON | CONSTRUCTORS | sort_by_name LPAREN CONSTRUCTORS RPAREN | input_section_spec | length LPAREN mustbe_exp RPAREN | FILL LPAREN fill_exp RPAREN | ASSERT LPAREN exp COMMA string RPAREN end | INCLUDE filename statement_list_opt END ; statement_list: statement_list statement | statement ; statement_list_opt: /* empty */ | statement_list ; length: QUAD | SQUAD | LONG | SHORT | BYTE ; fill_exp: mustbe_exp ; fill_opt: EQ fill_exp | ; assign_op: PLUSEQ | MINUSEQ | MULTEQ | DIVEQ | LSHIFTEQ | RSHIFTEQ | ANDEQ | OREQ ; end: SEMICOLON | COMMA ; assignment: NAME EQ mustbe_exp | NAME assign_op mustbe_exp | HIDDEN_ LPAREN NAME EQ mustbe_exp RPAREN | PROVIDE LPAREN NAME EQ mustbe_exp RPAREN | PROVIDE_HIDDEN LPAREN NAME EQ mustbe_exp RPAREN ; opt_comma: COMMA | ; memory: MEMORY LBRACE memory_spec_list_opt RBRACE ; memory_spec_list_opt: memory_spec_list | ; memory_spec_list: memory_spec_list opt_comma memory_spec | memory_spec ; memory_spec: NAME attributes_opt COLON origin_spec opt_comma length_spec | INCLUDE filename memory_spec_list_opt END ; origin_spec: ORIGIN EQ mustbe_exp ; length_spec: LENGTH EQ mustbe_exp ; attributes_opt: LPAREN attributes_list RPAREN ; attributes_list: attributes_string | attributes_list attributes_string ; attributes_string: NAME # attributeNormal | EXLAMATION NAME # attributeInverted ; /* This would be best but the tokenizer would have to be made context sensitive which is too much work given how easy it is to check the flags after parsing. attributes_string : attribute | '!' attribute # attributeInverted ; attribute: 'r' | 'w' | 'x' | 'a' | 'i' | 'l' ; */ startup: STARTUP LPAREN filename RPAREN ; high_level_library: HLL LPAREN high_level_library_NAME_list RPAREN | HLL LPAREN RPAREN ; high_level_library_NAME_list: high_level_library_NAME_list opt_comma filename | filename ; low_level_library: SYSLIB LPAREN low_level_library_NAME_list RPAREN ; low_level_library_NAME_list: low_level_library_NAME_list opt_comma filename | ; floating_point_support: FLOAT | NOFLOAT ; nocrossref_list: /* empty */ | NAME nocrossref_list | NAME COMMA nocrossref_list ; mustbe_exp: exp ; exp: DASH exp # expNegate // TODO: %prec UNARY | LPAREN exp RPAREN # expParen | NEXT LPAREN exp RPAREN # expNextParen // TODO: %prec UNARY | EXLAMATION exp # expNot // TODO: %prec UNARY | PLUS exp # expPlus // TODO: %prec UNARY | TILDE exp # expInvert // TODO: %prec UNARY | exp STAR exp # expMul | exp SLASH exp # expDiv | exp MOD exp # expMod | exp PLUS exp # expAdd | exp DASH exp # expSub | exp LSHIFT exp # expLshift | exp RSHIFT exp # expRshift | exp EQEQ exp # expEq | exp NE exp # expNe | exp LE exp # expLe | exp GE exp # expGe | exp LT exp # expLt | exp GT exp # expGt | exp AMPERSAND exp # expAnd | exp HAT exp # expXor | exp BAR exp # expOr | exp QUESTION exp COLON exp # expTernary | exp ANDAND exp # expAndand | exp OROR exp # expOror | DEFINED LPAREN NAME RPAREN # expDefined | INT # expInt | SIZEOF_HEADERS # expSizeofHeaders | ALIGNOF LPAREN NAME RPAREN # expAlignof | SIZEOF LPAREN NAME RPAREN # expSizeof | ADDR LPAREN NAME RPAREN # expAddr | LOADADDR LPAREN NAME RPAREN # expLoadaddr | CONSTANT LPAREN NAME RPAREN # expConstant | ABSOLUTE LPAREN exp RPAREN # expAbsolute | ALIGN_K LPAREN exp RPAREN # expAlign | ALIGN_K LPAREN exp COMMA exp RPAREN # expAlignK | DATA_SEGMENT_ALIGN LPAREN exp COMMA exp RPAREN # expDataSegmentAlign | DATA_SEGMENT_RELRO_END LPAREN exp COMMA exp RPAREN # expDataSegmentRelRoEnd | DATA_SEGMENT_END LPAREN exp RPAREN # expDataSegmentEnd | SEGMENT_START LPAREN NAME COMMA exp RPAREN # expSegmentStart | BLOCK LPAREN exp RPAREN # expBlock | NAME # expName | MAX_K LPAREN exp COMMA exp RPAREN # expMax | MIN_K LPAREN exp COMMA exp RPAREN # expMin | ASSERT LPAREN exp COMMA string RPAREN # expAssert | ORIGIN LPAREN NAME RPAREN # expOrigin | LENGTH LPAREN NAME RPAREN # expLengthExp | LOG2CEIL LPAREN exp RPAREN # expLog2ceil ; memspec_at_opt: AT GT NAME | ; opt_at: AT LPAREN exp RPAREN | ; opt_align: ALIGN_K LPAREN exp RPAREN | ; opt_align_with_input: ALIGN_WITH_INPUT | ; opt_subalign: SUBALIGN LPAREN exp RPAREN | ; sect_constraint: ONLY_IF_RO | ONLY_IF_RW | SPECIAL | ; section: NAME opt_exp_with_type opt_at opt_align opt_align_with_input opt_subalign sect_constraint LBRACE statement_list_opt RBRACE memspec_opt memspec_at_opt phdr_opt fill_opt opt_comma {} | OVERLAY opt_exp_without_type opt_nocrossrefs opt_at opt_subalign LBRACE overlay_section RBRACE memspec_opt memspec_at_opt phdr_opt fill_opt opt_comma | /* The GROUP case is just enough to support the gcc svr3.ifile script. It is not intended to be full support. I'm not even sure what GROUP is supposed to mean. */ GROUP opt_exp_with_type LBRACE sec_or_group_p1 RBRACE | INCLUDE filename sec_or_group_p1 END ; type: NOLOAD | DSECT | COPY | INFO | OVERLAY ; atype: LPAREN type RPAREN | /* EMPTY */ | LPAREN RPAREN ; opt_exp_with_type: exp atype COLON | atype COLON | /* The BIND cases are to support the gcc svr3.ifile script. They aren't intended to implement full support for the BIND keyword. I'm not even sure what BIND is supposed to mean. */ BIND LPAREN exp RPAREN atype COLON | BIND LPAREN exp RPAREN BLOCK LPAREN exp RPAREN atype COLON ; opt_exp_without_type: exp COLON | COLON ; opt_nocrossrefs: /* empty */ | NOCROSSREFS ; memspec_opt: GT NAME | ; phdr_opt: /* empty */ | phdr_opt COLON NAME ; overlay_section: /* empty */ | overlay_section NAME LBRACE statement_list_opt RBRACE phdr_opt fill_opt opt_comma ; phdrs: PHDRS LBRACE phdr_list RBRACE ; phdr_list: /* empty */ | phdr_list phdr ; phdr: NAME phdr_type phdr_qualifiers SEMICOLON ; phdr_type: exp ; phdr_qualifiers: /* empty */ | NAME phdr_val phdr_qualifiers | AT LPAREN exp RPAREN phdr_qualifiers ; phdr_val: /* empty */ | LPAREN exp RPAREN ; dynamic_list_file: dynamic_list_nodes ; dynamic_list_nodes: dynamic_list_node | dynamic_list_nodes dynamic_list_node ; dynamic_list_node: LBRACE dynamic_list_tag RBRACE SEMICOLON ; dynamic_list_tag: vers_defns SEMICOLON ; /* This syntax is used within an external version script file. */ version_script_file: vers_nodes ; /* This is used within a normal linker script file. */ version: VERSIONK LBRACE vers_nodes RBRACE ; vers_nodes: vers_node | vers_nodes vers_node ; vers_node: LBRACE vers_tag RBRACE SEMICOLON | VERS_TAG LBRACE vers_tag RBRACE SEMICOLON | VERS_TAG LBRACE vers_tag RBRACE verdep SEMICOLON ; verdep: VERS_TAG | verdep VERS_TAG ; vers_tag: /* empty */ | vers_defns SEMICOLON | GLOBAL COLON vers_defns SEMICOLON | LOCAL COLON vers_defns SEMICOLON | GLOBAL COLON vers_defns SEMICOLON LOCAL COLON vers_defns SEMICOLON ; vers_defns: VERS_IDENTIFIER | NAME | vers_defns SEMICOLON VERS_IDENTIFIER | vers_defns SEMICOLON NAME | vers_defns SEMICOLON EXTERN NAME LBRACE vers_defns opt_semicolon RBRACE | EXTERN NAME LBRACE vers_defns opt_semicolon RBRACE | GLOBAL | vers_defns SEMICOLON GLOBAL | LOCAL | vers_defns SEMICOLON LOCAL | EXTERN | vers_defns SEMICOLON EXTERN ; opt_semicolon: /* empty */ | SEMICOLON ; string: STRING_ANY*;