OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [binutils-2.20.1/] [gold/] [yyscript.y] - Diff between revs 816 and 818

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 816 Rev 818
/* yyscript.y -- linker script grammar for gold.  */
/* yyscript.y -- linker script grammar for gold.  */
/* Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
/* Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
   Written by Ian Lance Taylor .
   Written by Ian Lance Taylor .
   This file is part of gold.
   This file is part of gold.
   This program is free software; you can redistribute it and/or modify
   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
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
   (at your option) any later version.
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */
   MA 02110-1301, USA.  */
/* This is a bison grammar to parse a subset of the original GNU ld
/* This is a bison grammar to parse a subset of the original GNU ld
   linker script language.  */
   linker script language.  */
%{
%{
#include "config.h"
#include "config.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "script-c.h"
#include "script-c.h"
%}
%}
/* We need to use a pure parser because we might be multi-threaded.
/* We need to use a pure parser because we might be multi-threaded.
   We pass some arguments through the parser to the lexer.  */
   We pass some arguments through the parser to the lexer.  */
%pure-parser
%pure-parser
%parse-param {void* closure}
%parse-param {void* closure}
%lex-param {void* closure}
%lex-param {void* closure}
/* Since we require bison anyhow, we take advantage of it.  */
/* Since we require bison anyhow, we take advantage of it.  */
%error-verbose
%error-verbose
/* The values associated with tokens.  */
/* The values associated with tokens.  */
%union {
%union {
  /* A string.  */
  /* A string.  */
  struct Parser_string string;
  struct Parser_string string;
  /* A number.  */
  /* A number.  */
  uint64_t integer;
  uint64_t integer;
  /* An expression.  */
  /* An expression.  */
  Expression_ptr expr;
  Expression_ptr expr;
  /* An output section header.  */
  /* An output section header.  */
  struct Parser_output_section_header output_section_header;
  struct Parser_output_section_header output_section_header;
  /* An output section trailer.  */
  /* An output section trailer.  */
  struct Parser_output_section_trailer output_section_trailer;
  struct Parser_output_section_trailer output_section_trailer;
  /* A section constraint.  */
  /* A section constraint.  */
  enum Section_constraint constraint;
  enum Section_constraint constraint;
  /* A complete input section specification.  */
  /* A complete input section specification.  */
  struct Input_section_spec input_section_spec;
  struct Input_section_spec input_section_spec;
  /* A list of wildcard specifications, with exclusions.  */
  /* A list of wildcard specifications, with exclusions.  */
  struct Wildcard_sections wildcard_sections;
  struct Wildcard_sections wildcard_sections;
  /* A single wildcard specification.  */
  /* A single wildcard specification.  */
  struct Wildcard_section wildcard_section;
  struct Wildcard_section wildcard_section;
  /* A list of strings.  */
  /* A list of strings.  */
  String_list_ptr string_list;
  String_list_ptr string_list;
  /* Information for a program header.  */
  /* Information for a program header.  */
  struct Phdr_info phdr_info;
  struct Phdr_info phdr_info;
  /* Used for version scripts and within VERSION {}.  */
  /* Used for version scripts and within VERSION {}.  */
  struct Version_dependency_list* deplist;
  struct Version_dependency_list* deplist;
  struct Version_expression_list* versyms;
  struct Version_expression_list* versyms;
  struct Version_tree* versnode;
  struct Version_tree* versnode;
}
}
/* Operators, including a precedence table for expressions.  */
/* Operators, including a precedence table for expressions.  */
%right PLUSEQ MINUSEQ MULTEQ DIVEQ '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ
%right PLUSEQ MINUSEQ MULTEQ DIVEQ '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ
%right '?' ':'
%right '?' ':'
%left OROR
%left OROR
%left ANDAND
%left ANDAND
%left '|'
%left '|'
%left '^'
%left '^'
%left '&'
%left '&'
%left EQ NE
%left EQ NE
%left '<' '>' LE GE
%left '<' '>' LE GE
%left LSHIFT RSHIFT
%left LSHIFT RSHIFT
%left '+' '-'
%left '+' '-'
%left '*' '/' '%'
%left '*' '/' '%'
/* A fake operator used to indicate unary operator precedence.  */
/* A fake operator used to indicate unary operator precedence.  */
%right UNARY
%right UNARY
/* Constants.  */
/* Constants.  */
%token  STRING
%token  STRING
%token  QUOTED_STRING
%token  QUOTED_STRING
%token  INTEGER
%token  INTEGER
/* Keywords.  This list is taken from ldgram.y and ldlex.l in the old
/* Keywords.  This list is taken from ldgram.y and ldlex.l in the old
   GNU linker, with the keywords which only appear in MRI mode
   GNU linker, with the keywords which only appear in MRI mode
   removed.  Not all these keywords are actually used in this grammar.
   removed.  Not all these keywords are actually used in this grammar.
   In most cases the keyword is recognized as the token name in upper
   In most cases the keyword is recognized as the token name in upper
   case.  The comments indicate where this is not the case.  */
   case.  The comments indicate where this is not the case.  */
%token ABSOLUTE
%token ABSOLUTE
%token ADDR
%token ADDR
%token ALIGN_K          /* ALIGN */
%token ALIGN_K          /* ALIGN */
%token ALIGNOF
%token ALIGNOF
%token ASSERT_K         /* ASSERT */
%token ASSERT_K         /* ASSERT */
%token AS_NEEDED
%token AS_NEEDED
%token AT
%token AT
%token BIND
%token BIND
%token BLOCK
%token BLOCK
%token BYTE
%token BYTE
%token CONSTANT
%token CONSTANT
%token CONSTRUCTORS
%token CONSTRUCTORS
%token CREATE_OBJECT_SYMBOLS
%token CREATE_OBJECT_SYMBOLS
%token DATA_SEGMENT_ALIGN
%token DATA_SEGMENT_ALIGN
%token DATA_SEGMENT_END
%token DATA_SEGMENT_END
%token DATA_SEGMENT_RELRO_END
%token DATA_SEGMENT_RELRO_END
%token DEFINED
%token DEFINED
%token ENTRY
%token ENTRY
%token EXCLUDE_FILE
%token EXCLUDE_FILE
%token EXTERN
%token EXTERN
%token FILL
%token FILL
%token FLOAT
%token FLOAT
%token FORCE_COMMON_ALLOCATION
%token FORCE_COMMON_ALLOCATION
%token GLOBAL           /* global */
%token GLOBAL           /* global */
%token GROUP
%token GROUP
%token HLL
%token HLL
%token INCLUDE
%token INCLUDE
%token INHIBIT_COMMON_ALLOCATION
%token INHIBIT_COMMON_ALLOCATION
%token INPUT
%token INPUT
%token KEEP
%token KEEP
%token LENGTH           /* LENGTH, l, len */
%token LENGTH           /* LENGTH, l, len */
%token LOADADDR
%token LOADADDR
%token LOCAL            /* local */
%token LOCAL            /* local */
%token LONG
%token LONG
%token MAP
%token MAP
%token MAX_K            /* MAX */
%token MAX_K            /* MAX */
%token MEMORY
%token MEMORY
%token MIN_K            /* MIN */
%token MIN_K            /* MIN */
%token NEXT
%token NEXT
%token NOCROSSREFS
%token NOCROSSREFS
%token NOFLOAT
%token NOFLOAT
%token ONLY_IF_RO
%token ONLY_IF_RO
%token ONLY_IF_RW
%token ONLY_IF_RW
%token ORIGIN           /* ORIGIN, o, org */
%token ORIGIN           /* ORIGIN, o, org */
%token OUTPUT
%token OUTPUT
%token OUTPUT_ARCH
%token OUTPUT_ARCH
%token OUTPUT_FORMAT
%token OUTPUT_FORMAT
%token OVERLAY
%token OVERLAY
%token PHDRS
%token PHDRS
%token PROVIDE
%token PROVIDE
%token PROVIDE_HIDDEN
%token PROVIDE_HIDDEN
%token QUAD
%token QUAD
%token SEARCH_DIR
%token SEARCH_DIR
%token SECTIONS
%token SECTIONS
%token SEGMENT_START
%token SEGMENT_START
%token SHORT
%token SHORT
%token SIZEOF
%token SIZEOF
%token SIZEOF_HEADERS   /* SIZEOF_HEADERS, sizeof_headers */
%token SIZEOF_HEADERS   /* SIZEOF_HEADERS, sizeof_headers */
%token SORT_BY_ALIGNMENT
%token SORT_BY_ALIGNMENT
%token SORT_BY_NAME
%token SORT_BY_NAME
%token SPECIAL
%token SPECIAL
%token SQUAD
%token SQUAD
%token STARTUP
%token STARTUP
%token SUBALIGN
%token SUBALIGN
%token SYSLIB
%token SYSLIB
%token TARGET_K         /* TARGET */
%token TARGET_K         /* TARGET */
%token TRUNCATE
%token TRUNCATE
%token VERSIONK         /* VERSION */
%token VERSIONK         /* VERSION */
/* Keywords, part 2.  These are keywords that are unique to gold,
/* Keywords, part 2.  These are keywords that are unique to gold,
   and not present in the old GNU linker.  As before, unless the
   and not present in the old GNU linker.  As before, unless the
   comments say otherwise, the keyword is recognized as the token
   comments say otherwise, the keyword is recognized as the token
   name in upper case. */
   name in upper case. */
%token OPTION
%token OPTION
/* Special tokens used to tell the grammar what type of tokens we are
/* Special tokens used to tell the grammar what type of tokens we are
   parsing.  The token stream always begins with one of these tokens.
   parsing.  The token stream always begins with one of these tokens.
   We do this because version scripts can appear embedded within
   We do this because version scripts can appear embedded within
   linker scripts, and because --defsym uses the expression
   linker scripts, and because --defsym uses the expression
   parser.  */
   parser.  */
%token PARSING_LINKER_SCRIPT
%token PARSING_LINKER_SCRIPT
%token PARSING_VERSION_SCRIPT
%token PARSING_VERSION_SCRIPT
%token PARSING_DEFSYM
%token PARSING_DEFSYM
%token PARSING_DYNAMIC_LIST
%token PARSING_DYNAMIC_LIST
/* Non-terminal types, where needed.  */
/* Non-terminal types, where needed.  */
%type  parse_exp exp opt_address_and_section_type
%type  parse_exp exp opt_address_and_section_type
%type  opt_at opt_align opt_subalign opt_fill
%type  opt_at opt_align opt_subalign opt_fill
%type  section_header
%type  section_header
%type  section_trailer
%type  section_trailer
%type  opt_constraint
%type  opt_constraint
%type  opt_phdr
%type  opt_phdr
%type  data_length
%type  data_length
%type  input_section_no_keep
%type  input_section_no_keep
%type  wildcard_sections
%type  wildcard_sections
%type  wildcard_file wildcard_section
%type  wildcard_file wildcard_section
%type  exclude_names
%type  exclude_names
%type  wildcard_name
%type  wildcard_name
%type  phdr_type
%type  phdr_type
%type  phdr_info
%type  phdr_info
%type  vers_defns
%type  vers_defns
%type  vers_tag
%type  vers_tag
%type  verdep
%type  verdep
%type  string
%type  string
%%
%%
/* Read the special token to see what to read next.  */
/* Read the special token to see what to read next.  */
top:
top:
          PARSING_LINKER_SCRIPT linker_script
          PARSING_LINKER_SCRIPT linker_script
        | PARSING_VERSION_SCRIPT version_script
        | PARSING_VERSION_SCRIPT version_script
        | PARSING_DEFSYM defsym_expr
        | PARSING_DEFSYM defsym_expr
        | PARSING_DYNAMIC_LIST dynamic_list_expr
        | PARSING_DYNAMIC_LIST dynamic_list_expr
        ;
        ;
/* A file contains a list of commands.  */
/* A file contains a list of commands.  */
linker_script:
linker_script:
          linker_script file_cmd
          linker_script file_cmd
        | /* empty */
        | /* empty */
        ;
        ;
/* A command which may appear at top level of a linker script.  */
/* A command which may appear at top level of a linker script.  */
file_cmd:
file_cmd:
          EXTERN '(' extern_name_list ')'
          EXTERN '(' extern_name_list ')'
        | FORCE_COMMON_ALLOCATION
        | FORCE_COMMON_ALLOCATION
            { script_set_common_allocation(closure, 1); }
            { script_set_common_allocation(closure, 1); }
        | GROUP
        | GROUP
            { script_start_group(closure); }
            { script_start_group(closure); }
          '(' input_list ')'
          '(' input_list ')'
            { script_end_group(closure); }
            { script_end_group(closure); }
        | INHIBIT_COMMON_ALLOCATION
        | INHIBIT_COMMON_ALLOCATION
            { script_set_common_allocation(closure, 0); }
            { script_set_common_allocation(closure, 0); }
        | INPUT '(' input_list ')'
        | INPUT '(' input_list ')'
        | OPTION '(' string ')'
        | OPTION '(' string ')'
            { script_parse_option(closure, $3.value, $3.length); }
            { script_parse_option(closure, $3.value, $3.length); }
        | OUTPUT_FORMAT '(' string ')'
        | OUTPUT_FORMAT '(' string ')'
            {
            {
              if (!script_check_output_format(closure, $3.value, $3.length,
              if (!script_check_output_format(closure, $3.value, $3.length,
                                              NULL, 0, NULL, 0))
                                              NULL, 0, NULL, 0))
                YYABORT;
                YYABORT;
            }
            }
        | OUTPUT_FORMAT '(' string ',' string ',' string ')'
        | OUTPUT_FORMAT '(' string ',' string ',' string ')'
            {
            {
              if (!script_check_output_format(closure, $3.value, $3.length,
              if (!script_check_output_format(closure, $3.value, $3.length,
                                              $5.value, $5.length,
                                              $5.value, $5.length,
                                              $7.value, $7.length))
                                              $7.value, $7.length))
                YYABORT;
                YYABORT;
            }
            }
        | PHDRS '{' phdrs_defs '}'
        | PHDRS '{' phdrs_defs '}'
        | SEARCH_DIR '(' string ')'
        | SEARCH_DIR '(' string ')'
            { script_add_search_dir(closure, $3.value, $3.length); }
            { script_add_search_dir(closure, $3.value, $3.length); }
        | SECTIONS '{'
        | SECTIONS '{'
            { script_start_sections(closure); }
            { script_start_sections(closure); }
          sections_block '}'
          sections_block '}'
            { script_finish_sections(closure); }
            { script_finish_sections(closure); }
        | TARGET_K '(' string ')'
        | TARGET_K '(' string ')'
            { script_set_target(closure, $3.value, $3.length); }
            { script_set_target(closure, $3.value, $3.length); }
        | VERSIONK '{'
        | VERSIONK '{'
            { script_push_lex_into_version_mode(closure); }
            { script_push_lex_into_version_mode(closure); }
          version_script '}'
          version_script '}'
            { script_pop_lex_mode(closure); }
            { script_pop_lex_mode(closure); }
        | file_or_sections_cmd
        | file_or_sections_cmd
        | ignore_cmd
        | ignore_cmd
        | ';'
        | ';'
        ;
        ;
/* Top level commands which we ignore.  The GNU linker uses these to
/* Top level commands which we ignore.  The GNU linker uses these to
   select the output format, but we don't offer a choice.  Ignoring
   select the output format, but we don't offer a choice.  Ignoring
   these is more-or-less OK since most scripts simply explicitly
   these is more-or-less OK since most scripts simply explicitly
   choose the default.  */
   choose the default.  */
ignore_cmd:
ignore_cmd:
          OUTPUT_ARCH '(' string ')'
          OUTPUT_ARCH '(' string ')'
        ;
        ;
/* A list of external undefined symbols.  We put the lexer into
/* A list of external undefined symbols.  We put the lexer into
   expression mode so that commas separate names; this is what the GNU
   expression mode so that commas separate names; this is what the GNU
   linker does.  */
   linker does.  */
extern_name_list:
extern_name_list:
            { script_push_lex_into_expression_mode(closure); }
            { script_push_lex_into_expression_mode(closure); }
          extern_name_list_body
          extern_name_list_body
            { script_pop_lex_mode(closure); }
            { script_pop_lex_mode(closure); }
        ;
        ;
extern_name_list_body:
extern_name_list_body:
          string
          string
            { script_add_extern(closure, $1.value, $1.length); }
            { script_add_extern(closure, $1.value, $1.length); }
        | extern_name_list_body string
        | extern_name_list_body string
            { script_add_extern(closure, $2.value, $2.length); }
            { script_add_extern(closure, $2.value, $2.length); }
        | extern_name_list_body ',' string
        | extern_name_list_body ',' string
            { script_add_extern(closure, $3.value, $3.length); }
            { script_add_extern(closure, $3.value, $3.length); }
        ;
        ;
/* A list of input file names.  */
/* A list of input file names.  */
input_list:
input_list:
          input_list_element
          input_list_element
        | input_list opt_comma input_list_element
        | input_list opt_comma input_list_element
        ;
        ;
/* An input file name.  */
/* An input file name.  */
input_list_element:
input_list_element:
          string
          string
            { script_add_file(closure, $1.value, $1.length); }
            { script_add_file(closure, $1.value, $1.length); }
        | AS_NEEDED
        | AS_NEEDED
            { script_start_as_needed(closure); }
            { script_start_as_needed(closure); }
          '(' input_list ')'
          '(' input_list ')'
            { script_end_as_needed(closure); }
            { script_end_as_needed(closure); }
        ;
        ;
/* Commands in a SECTIONS block.  */
/* Commands in a SECTIONS block.  */
sections_block:
sections_block:
          sections_block section_block_cmd
          sections_block section_block_cmd
        | /* empty */
        | /* empty */
        ;
        ;
/* A command which may appear within a SECTIONS block.  */
/* A command which may appear within a SECTIONS block.  */
section_block_cmd:
section_block_cmd:
          file_or_sections_cmd
          file_or_sections_cmd
        | string section_header
        | string section_header
            { script_start_output_section(closure, $1.value, $1.length, &$2); }
            { script_start_output_section(closure, $1.value, $1.length, &$2); }
          '{' section_cmds '}' section_trailer
          '{' section_cmds '}' section_trailer
            { script_finish_output_section(closure, &$7); }
            { script_finish_output_section(closure, &$7); }
        ;
        ;
/* The header of an output section in a SECTIONS block--everything
/* The header of an output section in a SECTIONS block--everything
   after the name.  */
   after the name.  */
section_header:
section_header:
            { script_push_lex_into_expression_mode(closure); }
            { script_push_lex_into_expression_mode(closure); }
          opt_address_and_section_type opt_at opt_align opt_subalign
          opt_address_and_section_type opt_at opt_align opt_subalign
            { script_pop_lex_mode(closure); }
            { script_pop_lex_mode(closure); }
          opt_constraint
          opt_constraint
            {
            {
              $$.address = $2;
              $$.address = $2;
              $$.load_address = $3;
              $$.load_address = $3;
              $$.align = $4;
              $$.align = $4;
              $$.subalign = $5;
              $$.subalign = $5;
              $$.constraint = $7;
              $$.constraint = $7;
            }
            }
        ;
        ;
/* The optional address followed by the optional section type.  This
/* The optional address followed by the optional section type.  This
   is a separate nonterminal to avoid a shift/reduce conflict on
   is a separate nonterminal to avoid a shift/reduce conflict on
   '(' in section_header.  */
   '(' in section_header.  */
opt_address_and_section_type:
opt_address_and_section_type:
          ':'
          ':'
            { $$ = NULL; }
            { $$ = NULL; }
        | '(' ')' ':'
        | '(' ')' ':'
            { $$ = NULL; }
            { $$ = NULL; }
        | exp ':'
        | exp ':'
            { $$ = $1; }
            { $$ = $1; }
        | exp '(' ')' ':'
        | exp '(' ')' ':'
            { $$ = $1; }
            { $$ = $1; }
        | exp '(' string ')' ':'
        | exp '(' string ')' ':'
            {
            {
              yyerror(closure, "section types are not supported");
              yyerror(closure, "section types are not supported");
              $$ = $1;
              $$ = $1;
            }
            }
        ;
        ;
/* The address at which an output section should be loaded.  */
/* The address at which an output section should be loaded.  */
opt_at:
opt_at:
          /* empty */
          /* empty */
            { $$ = NULL; }
            { $$ = NULL; }
        | AT '(' exp ')'
        | AT '(' exp ')'
            { $$ = $3; }
            { $$ = $3; }
        ;
        ;
/* The alignment of an output section.  */
/* The alignment of an output section.  */
opt_align:
opt_align:
          /* empty */
          /* empty */
            { $$ = NULL; }
            { $$ = NULL; }
        | ALIGN_K '(' exp ')'
        | ALIGN_K '(' exp ')'
            { $$ = $3; }
            { $$ = $3; }
        ;
        ;
/* The input section alignment within an output section.  */
/* The input section alignment within an output section.  */
opt_subalign:
opt_subalign:
          /* empty */
          /* empty */
            { $$ = NULL; }
            { $$ = NULL; }
        | SUBALIGN '(' exp ')'
        | SUBALIGN '(' exp ')'
            { $$ = $3; }
            { $$ = $3; }
        ;
        ;
/* A section constraint.  */
/* A section constraint.  */
opt_constraint:
opt_constraint:
          /* empty */
          /* empty */
            { $$ = CONSTRAINT_NONE; }
            { $$ = CONSTRAINT_NONE; }
        | ONLY_IF_RO
        | ONLY_IF_RO
            { $$ = CONSTRAINT_ONLY_IF_RO; }
            { $$ = CONSTRAINT_ONLY_IF_RO; }
        | ONLY_IF_RW
        | ONLY_IF_RW
            { $$ = CONSTRAINT_ONLY_IF_RW; }
            { $$ = CONSTRAINT_ONLY_IF_RW; }
        | SPECIAL
        | SPECIAL
            { $$ = CONSTRAINT_SPECIAL; }
            { $$ = CONSTRAINT_SPECIAL; }
        ;
        ;
/* The trailer of an output section in a SECTIONS block.  */
/* The trailer of an output section in a SECTIONS block.  */
section_trailer:
section_trailer:
          opt_memspec opt_at_memspec opt_phdr opt_fill opt_comma
          opt_memspec opt_at_memspec opt_phdr opt_fill opt_comma
            {
            {
              $$.fill = $4;
              $$.fill = $4;
              $$.phdrs = $3;
              $$.phdrs = $3;
            }
            }
        ;
        ;
/* A memory specification for an output section.  */
/* A memory specification for an output section.  */
opt_memspec:
opt_memspec:
          '>' string
          '>' string
            { yyerror(closure, "memory regions are not supported"); }
            { yyerror(closure, "memory regions are not supported"); }
        | /* empty */
        | /* empty */
        ;
        ;
/* A memory specification for where to load an output section.  */
/* A memory specification for where to load an output section.  */
opt_at_memspec:
opt_at_memspec:
          AT '>' string
          AT '>' string
            { yyerror(closure, "memory regions are not supported"); }
            { yyerror(closure, "memory regions are not supported"); }
        | /* empty */
        | /* empty */
        ;
        ;
/* The program segment an output section should go into.  */
/* The program segment an output section should go into.  */
opt_phdr:
opt_phdr:
          opt_phdr ':' string
          opt_phdr ':' string
            { $$ = script_string_list_push_back($1, $3.value, $3.length); }
            { $$ = script_string_list_push_back($1, $3.value, $3.length); }
        | /* empty */
        | /* empty */
            { $$ = NULL; }
            { $$ = NULL; }
        ;
        ;
/* The value to use to fill an output section.  FIXME: This does not
/* The value to use to fill an output section.  FIXME: This does not
   handle a string of arbitrary length.  */
   handle a string of arbitrary length.  */
opt_fill:
opt_fill:
          '=' parse_exp
          '=' parse_exp
            { $$ = $2; }
            { $$ = $2; }
        | /* empty */
        | /* empty */
            { $$ = NULL; }
            { $$ = NULL; }
        ;
        ;
/* Commands which may appear within the description of an output
/* Commands which may appear within the description of an output
   section in a SECTIONS block.  */
   section in a SECTIONS block.  */
section_cmds:
section_cmds:
          /* empty */
          /* empty */
        | section_cmds section_cmd
        | section_cmds section_cmd
        ;
        ;
/* A command which may appear within the description of an output
/* A command which may appear within the description of an output
   section in a SECTIONS block.  */
   section in a SECTIONS block.  */
section_cmd:
section_cmd:
          assignment end
          assignment end
        | input_section_spec
        | input_section_spec
        | data_length '(' parse_exp ')'
        | data_length '(' parse_exp ')'
            { script_add_data(closure, $1, $3); }
            { script_add_data(closure, $1, $3); }
        | ASSERT_K '(' parse_exp ',' string ')'
        | ASSERT_K '(' parse_exp ',' string ')'
            { script_add_assertion(closure, $3, $5.value, $5.length); }
            { script_add_assertion(closure, $3, $5.value, $5.length); }
        | FILL '(' parse_exp ')'
        | FILL '(' parse_exp ')'
            { script_add_fill(closure, $3); }
            { script_add_fill(closure, $3); }
        | CONSTRUCTORS
        | CONSTRUCTORS
            {
            {
              /* The GNU linker uses CONSTRUCTORS for the a.out object
              /* The GNU linker uses CONSTRUCTORS for the a.out object
                 file format.  It does nothing when using ELF.  Since
                 file format.  It does nothing when using ELF.  Since
                 some ELF linker scripts use it although it does
                 some ELF linker scripts use it although it does
                 nothing, we accept it and ignore it.  */
                 nothing, we accept it and ignore it.  */
            }
            }
        | SORT_BY_NAME '(' CONSTRUCTORS ')'
        | SORT_BY_NAME '(' CONSTRUCTORS ')'
        | ';'
        | ';'
        ;
        ;
/* The length of data which may appear within the description of an
/* The length of data which may appear within the description of an
   output section in a SECTIONS block.  */
   output section in a SECTIONS block.  */
data_length:
data_length:
          QUAD
          QUAD
            { $$ = QUAD; }
            { $$ = QUAD; }
        | SQUAD
        | SQUAD
            { $$ = SQUAD; }
            { $$ = SQUAD; }
        | LONG
        | LONG
            { $$ = LONG; }
            { $$ = LONG; }
        | SHORT
        | SHORT
            { $$ = SHORT; }
            { $$ = SHORT; }
        | BYTE
        | BYTE
            { $$ = BYTE; }
            { $$ = BYTE; }
        ;
        ;
/* An input section specification.  This may appear within the
/* An input section specification.  This may appear within the
   description of an output section in a SECTIONS block.  */
   description of an output section in a SECTIONS block.  */
input_section_spec:
input_section_spec:
          input_section_no_keep
          input_section_no_keep
            { script_add_input_section(closure, &$1, 0); }
            { script_add_input_section(closure, &$1, 0); }
        | KEEP '(' input_section_no_keep ')'
        | KEEP '(' input_section_no_keep ')'
            { script_add_input_section(closure, &$3, 1); }
            { script_add_input_section(closure, &$3, 1); }
        ;
        ;
/* An input section specification within a KEEP clause.  */
/* An input section specification within a KEEP clause.  */
input_section_no_keep:
input_section_no_keep:
          string
          string
            {
            {
              $$.file.name = $1;
              $$.file.name = $1;
              $$.file.sort = SORT_WILDCARD_NONE;
              $$.file.sort = SORT_WILDCARD_NONE;
              $$.input_sections.sections = NULL;
              $$.input_sections.sections = NULL;
              $$.input_sections.exclude = NULL;
              $$.input_sections.exclude = NULL;
            }
            }
        | wildcard_file '(' wildcard_sections ')'
        | wildcard_file '(' wildcard_sections ')'
            {
            {
              $$.file = $1;
              $$.file = $1;
              $$.input_sections = $3;
              $$.input_sections = $3;
            }
            }
        ;
        ;
/* A wildcard file specification.  */
/* A wildcard file specification.  */
wildcard_file:
wildcard_file:
          wildcard_name
          wildcard_name
            {
            {
              $$.name = $1;
              $$.name = $1;
              $$.sort = SORT_WILDCARD_NONE;
              $$.sort = SORT_WILDCARD_NONE;
            }
            }
        | SORT_BY_NAME '(' wildcard_name ')'
        | SORT_BY_NAME '(' wildcard_name ')'
            {
            {
              $$.name = $3;
              $$.name = $3;
              $$.sort = SORT_WILDCARD_BY_NAME;
              $$.sort = SORT_WILDCARD_BY_NAME;
            }
            }
        ;
        ;
/* A list of wild card section specifications.  */
/* A list of wild card section specifications.  */
wildcard_sections:
wildcard_sections:
          wildcard_sections opt_comma wildcard_section
          wildcard_sections opt_comma wildcard_section
            {
            {
              $$.sections = script_string_sort_list_add($1.sections, &$3);
              $$.sections = script_string_sort_list_add($1.sections, &$3);
              $$.exclude = $1.exclude;
              $$.exclude = $1.exclude;
            }
            }
        | wildcard_section
        | wildcard_section
            {
            {
              $$.sections = script_new_string_sort_list(&$1);
              $$.sections = script_new_string_sort_list(&$1);
              $$.exclude = NULL;
              $$.exclude = NULL;
            }
            }
        | wildcard_sections opt_comma EXCLUDE_FILE '(' exclude_names ')'
        | wildcard_sections opt_comma EXCLUDE_FILE '(' exclude_names ')'
            {
            {
              $$.sections = $1.sections;
              $$.sections = $1.sections;
              $$.exclude = script_string_list_append($1.exclude, $5);
              $$.exclude = script_string_list_append($1.exclude, $5);
            }
            }
        | EXCLUDE_FILE '(' exclude_names ')'
        | EXCLUDE_FILE '(' exclude_names ')'
            {
            {
              $$.sections = NULL;
              $$.sections = NULL;
              $$.exclude = $3;
              $$.exclude = $3;
            }
            }
        ;
        ;
/* A single wild card specification.  */
/* A single wild card specification.  */
wildcard_section:
wildcard_section:
          wildcard_name
          wildcard_name
            {
            {
              $$.name = $1;
              $$.name = $1;
              $$.sort = SORT_WILDCARD_NONE;
              $$.sort = SORT_WILDCARD_NONE;
            }
            }
        | SORT_BY_NAME '(' wildcard_section ')'
        | SORT_BY_NAME '(' wildcard_section ')'
            {
            {
              $$.name = $3.name;
              $$.name = $3.name;
              switch ($3.sort)
              switch ($3.sort)
                {
                {
                case SORT_WILDCARD_NONE:
                case SORT_WILDCARD_NONE:
                  $$.sort = SORT_WILDCARD_BY_NAME;
                  $$.sort = SORT_WILDCARD_BY_NAME;
                  break;
                  break;
                case SORT_WILDCARD_BY_NAME:
                case SORT_WILDCARD_BY_NAME:
                case SORT_WILDCARD_BY_NAME_BY_ALIGNMENT:
                case SORT_WILDCARD_BY_NAME_BY_ALIGNMENT:
                  break;
                  break;
                case SORT_WILDCARD_BY_ALIGNMENT:
                case SORT_WILDCARD_BY_ALIGNMENT:
                case SORT_WILDCARD_BY_ALIGNMENT_BY_NAME:
                case SORT_WILDCARD_BY_ALIGNMENT_BY_NAME:
                  $$.sort = SORT_WILDCARD_BY_NAME_BY_ALIGNMENT;
                  $$.sort = SORT_WILDCARD_BY_NAME_BY_ALIGNMENT;
                  break;
                  break;
                default:
                default:
                  abort();
                  abort();
                }
                }
            }
            }
        | SORT_BY_ALIGNMENT '(' wildcard_section ')'
        | SORT_BY_ALIGNMENT '(' wildcard_section ')'
            {
            {
              $$.name = $3.name;
              $$.name = $3.name;
              switch ($3.sort)
              switch ($3.sort)
                {
                {
                case SORT_WILDCARD_NONE:
                case SORT_WILDCARD_NONE:
                  $$.sort = SORT_WILDCARD_BY_ALIGNMENT;
                  $$.sort = SORT_WILDCARD_BY_ALIGNMENT;
                  break;
                  break;
                case SORT_WILDCARD_BY_ALIGNMENT:
                case SORT_WILDCARD_BY_ALIGNMENT:
                case SORT_WILDCARD_BY_ALIGNMENT_BY_NAME:
                case SORT_WILDCARD_BY_ALIGNMENT_BY_NAME:
                  break;
                  break;
                case SORT_WILDCARD_BY_NAME:
                case SORT_WILDCARD_BY_NAME:
                case SORT_WILDCARD_BY_NAME_BY_ALIGNMENT:
                case SORT_WILDCARD_BY_NAME_BY_ALIGNMENT:
                  $$.sort = SORT_WILDCARD_BY_ALIGNMENT_BY_NAME;
                  $$.sort = SORT_WILDCARD_BY_ALIGNMENT_BY_NAME;
                  break;
                  break;
                default:
                default:
                  abort();
                  abort();
                }
                }
            }
            }
        ;
        ;
/* A list of file names to exclude.  */
/* A list of file names to exclude.  */
exclude_names:
exclude_names:
          exclude_names opt_comma wildcard_name
          exclude_names opt_comma wildcard_name
            { $$ = script_string_list_push_back($1, $3.value, $3.length); }
            { $$ = script_string_list_push_back($1, $3.value, $3.length); }
        | wildcard_name
        | wildcard_name
            { $$ = script_new_string_list($1.value, $1.length); }
            { $$ = script_new_string_list($1.value, $1.length); }
        ;
        ;
/* A single wildcard name.  We recognize '*' and '?' specially since
/* A single wildcard name.  We recognize '*' and '?' specially since
   they are expression tokens.  */
   they are expression tokens.  */
wildcard_name:
wildcard_name:
          string
          string
            { $$ = $1; }
            { $$ = $1; }
        | '*'
        | '*'
            {
            {
              $$.value = "*";
              $$.value = "*";
              $$.length = 1;
              $$.length = 1;
            }
            }
        | '?'
        | '?'
            {
            {
              $$.value = "?";
              $$.value = "?";
              $$.length = 1;
              $$.length = 1;
            }
            }
        ;
        ;
/* A command which may appear at the top level of a linker script, or
/* A command which may appear at the top level of a linker script, or
   within a SECTIONS block.  */
   within a SECTIONS block.  */
file_or_sections_cmd:
file_or_sections_cmd:
          ENTRY '(' string ')'
          ENTRY '(' string ')'
            { script_set_entry(closure, $3.value, $3.length); }
            { script_set_entry(closure, $3.value, $3.length); }
        | assignment end
        | assignment end
        | ASSERT_K '(' parse_exp ',' string ')'
        | ASSERT_K '(' parse_exp ',' string ')'
            { script_add_assertion(closure, $3, $5.value, $5.length); }
            { script_add_assertion(closure, $3, $5.value, $5.length); }
        ;
        ;
/* A list of program header definitions.  */
/* A list of program header definitions.  */
phdrs_defs:
phdrs_defs:
          phdrs_defs phdr_def
          phdrs_defs phdr_def
        | /* empty */
        | /* empty */
        ;
        ;
/* A program header definition.  */
/* A program header definition.  */
phdr_def:
phdr_def:
          string phdr_type phdr_info ';'
          string phdr_type phdr_info ';'
            { script_add_phdr(closure, $1.value, $1.length, $2, &$3); }
            { script_add_phdr(closure, $1.value, $1.length, $2, &$3); }
        ;
        ;
/* A program header type.  The GNU linker accepts a general expression
/* A program header type.  The GNU linker accepts a general expression
   here, but that would be a pain because we would have to dig into
   here, but that would be a pain because we would have to dig into
   the expression structure.  It's unlikely that anybody uses anything
   the expression structure.  It's unlikely that anybody uses anything
   other than a string or a number here, so that is all we expect.  */
   other than a string or a number here, so that is all we expect.  */
phdr_type:
phdr_type:
          string
          string
            { $$ = script_phdr_string_to_type(closure, $1.value, $1.length); }
            { $$ = script_phdr_string_to_type(closure, $1.value, $1.length); }
        | INTEGER
        | INTEGER
            { $$ = $1; }
            { $$ = $1; }
        ;
        ;
/* Additional information for a program header.  */
/* Additional information for a program header.  */
phdr_info:
phdr_info:
          /* empty */
          /* empty */
            { memset(&$$, 0, sizeof(struct Phdr_info)); }
            { memset(&$$, 0, sizeof(struct Phdr_info)); }
        | string phdr_info
        | string phdr_info
            {
            {
              $$ = $2;
              $$ = $2;
              if ($1.length == 7 && strncmp($1.value, "FILEHDR", 7) == 0)
              if ($1.length == 7 && strncmp($1.value, "FILEHDR", 7) == 0)
                $$.includes_filehdr = 1;
                $$.includes_filehdr = 1;
              else
              else
                yyerror(closure, "PHDRS syntax error");
                yyerror(closure, "PHDRS syntax error");
            }
            }
        | PHDRS phdr_info
        | PHDRS phdr_info
            {
            {
              $$ = $2;
              $$ = $2;
              $$.includes_phdrs = 1;
              $$.includes_phdrs = 1;
            }
            }
        | string '(' INTEGER ')' phdr_info
        | string '(' INTEGER ')' phdr_info
            {
            {
              $$ = $5;
              $$ = $5;
              if ($1.length == 5 && strncmp($1.value, "FLAGS", 5) == 0)
              if ($1.length == 5 && strncmp($1.value, "FLAGS", 5) == 0)
                {
                {
                  $$.is_flags_valid = 1;
                  $$.is_flags_valid = 1;
                  $$.flags = $3;
                  $$.flags = $3;
                }
                }
              else
              else
                yyerror(closure, "PHDRS syntax error");
                yyerror(closure, "PHDRS syntax error");
            }
            }
        | AT '(' parse_exp ')' phdr_info
        | AT '(' parse_exp ')' phdr_info
            {
            {
              $$ = $5;
              $$ = $5;
              $$.load_address = $3;
              $$.load_address = $3;
            }
            }
        ;
        ;
/* Set a symbol to a value.  */
/* Set a symbol to a value.  */
assignment:
assignment:
          string '=' parse_exp
          string '=' parse_exp
            { script_set_symbol(closure, $1.value, $1.length, $3, 0, 0); }
            { script_set_symbol(closure, $1.value, $1.length, $3, 0, 0); }
        | string PLUSEQ parse_exp
        | string PLUSEQ parse_exp
            {
            {
              Expression_ptr s = script_exp_string($1.value, $1.length);
              Expression_ptr s = script_exp_string($1.value, $1.length);
              Expression_ptr e = script_exp_binary_add(s, $3);
              Expression_ptr e = script_exp_binary_add(s, $3);
              script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
              script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
            }
            }
        | string MINUSEQ parse_exp
        | string MINUSEQ parse_exp
            {
            {
              Expression_ptr s = script_exp_string($1.value, $1.length);
              Expression_ptr s = script_exp_string($1.value, $1.length);
              Expression_ptr e = script_exp_binary_sub(s, $3);
              Expression_ptr e = script_exp_binary_sub(s, $3);
              script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
              script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
            }
            }
        | string MULTEQ parse_exp
        | string MULTEQ parse_exp
            {
            {
              Expression_ptr s = script_exp_string($1.value, $1.length);
              Expression_ptr s = script_exp_string($1.value, $1.length);
              Expression_ptr e = script_exp_binary_mult(s, $3);
              Expression_ptr e = script_exp_binary_mult(s, $3);
              script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
              script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
            }
            }
        | string DIVEQ parse_exp
        | string DIVEQ parse_exp
            {
            {
              Expression_ptr s = script_exp_string($1.value, $1.length);
              Expression_ptr s = script_exp_string($1.value, $1.length);
              Expression_ptr e = script_exp_binary_div(s, $3);
              Expression_ptr e = script_exp_binary_div(s, $3);
              script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
              script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
            }
            }
        | string LSHIFTEQ parse_exp
        | string LSHIFTEQ parse_exp
            {
            {
              Expression_ptr s = script_exp_string($1.value, $1.length);
              Expression_ptr s = script_exp_string($1.value, $1.length);
              Expression_ptr e = script_exp_binary_lshift(s, $3);
              Expression_ptr e = script_exp_binary_lshift(s, $3);
              script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
              script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
            }
            }
        | string RSHIFTEQ parse_exp
        | string RSHIFTEQ parse_exp
            {
            {
              Expression_ptr s = script_exp_string($1.value, $1.length);
              Expression_ptr s = script_exp_string($1.value, $1.length);
              Expression_ptr e = script_exp_binary_rshift(s, $3);
              Expression_ptr e = script_exp_binary_rshift(s, $3);
              script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
              script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
            }
            }
        | string ANDEQ parse_exp
        | string ANDEQ parse_exp
            {
            {
              Expression_ptr s = script_exp_string($1.value, $1.length);
              Expression_ptr s = script_exp_string($1.value, $1.length);
              Expression_ptr e = script_exp_binary_bitwise_and(s, $3);
              Expression_ptr e = script_exp_binary_bitwise_and(s, $3);
              script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
              script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
            }
            }
        | string OREQ parse_exp
        | string OREQ parse_exp
            {
            {
              Expression_ptr s = script_exp_string($1.value, $1.length);
              Expression_ptr s = script_exp_string($1.value, $1.length);
              Expression_ptr e = script_exp_binary_bitwise_or(s, $3);
              Expression_ptr e = script_exp_binary_bitwise_or(s, $3);
              script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
              script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
            }
            }
        | PROVIDE '(' string '=' parse_exp ')'
        | PROVIDE '(' string '=' parse_exp ')'
            { script_set_symbol(closure, $3.value, $3.length, $5, 1, 0); }
            { script_set_symbol(closure, $3.value, $3.length, $5, 1, 0); }
        | PROVIDE_HIDDEN '(' string '=' parse_exp ')'
        | PROVIDE_HIDDEN '(' string '=' parse_exp ')'
            { script_set_symbol(closure, $3.value, $3.length, $5, 1, 1); }
            { script_set_symbol(closure, $3.value, $3.length, $5, 1, 1); }
        ;
        ;
/* Parse an expression, putting the lexer into the right mode.  */
/* Parse an expression, putting the lexer into the right mode.  */
parse_exp:
parse_exp:
            { script_push_lex_into_expression_mode(closure); }
            { script_push_lex_into_expression_mode(closure); }
          exp
          exp
            {
            {
              script_pop_lex_mode(closure);
              script_pop_lex_mode(closure);
              $$ = $2;
              $$ = $2;
            }
            }
        ;
        ;
/* An expression.  */
/* An expression.  */
exp:
exp:
          '(' exp ')'
          '(' exp ')'
            { $$ = $2; }
            { $$ = $2; }
        | '-' exp %prec UNARY
        | '-' exp %prec UNARY
            { $$ = script_exp_unary_minus($2); }
            { $$ = script_exp_unary_minus($2); }
        | '!' exp %prec UNARY
        | '!' exp %prec UNARY
            { $$ = script_exp_unary_logical_not($2); }
            { $$ = script_exp_unary_logical_not($2); }
        | '~' exp %prec UNARY
        | '~' exp %prec UNARY
            { $$ = script_exp_unary_bitwise_not($2); }
            { $$ = script_exp_unary_bitwise_not($2); }
        | '+' exp %prec UNARY
        | '+' exp %prec UNARY
            { $$ = $2; }
            { $$ = $2; }
        | exp '*' exp
        | exp '*' exp
            { $$ = script_exp_binary_mult($1, $3); }
            { $$ = script_exp_binary_mult($1, $3); }
        | exp '/' exp
        | exp '/' exp
            { $$ = script_exp_binary_div($1, $3); }
            { $$ = script_exp_binary_div($1, $3); }
        | exp '%' exp
        | exp '%' exp
            { $$ = script_exp_binary_mod($1, $3); }
            { $$ = script_exp_binary_mod($1, $3); }
        | exp '+' exp
        | exp '+' exp
            { $$ = script_exp_binary_add($1, $3); }
            { $$ = script_exp_binary_add($1, $3); }
        | exp '-' exp
        | exp '-' exp
            { $$ = script_exp_binary_sub($1, $3); }
            { $$ = script_exp_binary_sub($1, $3); }
        | exp LSHIFT exp
        | exp LSHIFT exp
            { $$ = script_exp_binary_lshift($1, $3); }
            { $$ = script_exp_binary_lshift($1, $3); }
        | exp RSHIFT exp
        | exp RSHIFT exp
            { $$ = script_exp_binary_rshift($1, $3); }
            { $$ = script_exp_binary_rshift($1, $3); }
        | exp EQ exp
        | exp EQ exp
            { $$ = script_exp_binary_eq($1, $3); }
            { $$ = script_exp_binary_eq($1, $3); }
        | exp NE exp
        | exp NE exp
            { $$ = script_exp_binary_ne($1, $3); }
            { $$ = script_exp_binary_ne($1, $3); }
        | exp LE exp
        | exp LE exp
            { $$ = script_exp_binary_le($1, $3); }
            { $$ = script_exp_binary_le($1, $3); }
        | exp GE exp
        | exp GE exp
            { $$ = script_exp_binary_ge($1, $3); }
            { $$ = script_exp_binary_ge($1, $3); }
        | exp '<' exp
        | exp '<' exp
            { $$ = script_exp_binary_lt($1, $3); }
            { $$ = script_exp_binary_lt($1, $3); }
        | exp '>' exp
        | exp '>' exp
            { $$ = script_exp_binary_gt($1, $3); }
            { $$ = script_exp_binary_gt($1, $3); }
        | exp '&' exp
        | exp '&' exp
            { $$ = script_exp_binary_bitwise_and($1, $3); }
            { $$ = script_exp_binary_bitwise_and($1, $3); }
        | exp '^' exp
        | exp '^' exp
            { $$ = script_exp_binary_bitwise_xor($1, $3); }
            { $$ = script_exp_binary_bitwise_xor($1, $3); }
        | exp '|' exp
        | exp '|' exp
            { $$ = script_exp_binary_bitwise_or($1, $3); }
            { $$ = script_exp_binary_bitwise_or($1, $3); }
        | exp ANDAND exp
        | exp ANDAND exp
            { $$ = script_exp_binary_logical_and($1, $3); }
            { $$ = script_exp_binary_logical_and($1, $3); }
        | exp OROR exp
        | exp OROR exp
            { $$ = script_exp_binary_logical_or($1, $3); }
            { $$ = script_exp_binary_logical_or($1, $3); }
        | exp '?' exp ':' exp
        | exp '?' exp ':' exp
            { $$ = script_exp_trinary_cond($1, $3, $5); }
            { $$ = script_exp_trinary_cond($1, $3, $5); }
        | INTEGER
        | INTEGER
            { $$ = script_exp_integer($1); }
            { $$ = script_exp_integer($1); }
        | string
        | string
            { $$ = script_exp_string($1.value, $1.length); }
            { $$ = script_exp_string($1.value, $1.length); }
        | MAX_K '(' exp ',' exp ')'
        | MAX_K '(' exp ',' exp ')'
            { $$ = script_exp_function_max($3, $5); }
            { $$ = script_exp_function_max($3, $5); }
        | MIN_K '(' exp ',' exp ')'
        | MIN_K '(' exp ',' exp ')'
            { $$ = script_exp_function_min($3, $5); }
            { $$ = script_exp_function_min($3, $5); }
        | DEFINED '(' string ')'
        | DEFINED '(' string ')'
            { $$ = script_exp_function_defined($3.value, $3.length); }
            { $$ = script_exp_function_defined($3.value, $3.length); }
        | SIZEOF_HEADERS
        | SIZEOF_HEADERS
            { $$ = script_exp_function_sizeof_headers(); }
            { $$ = script_exp_function_sizeof_headers(); }
        | ALIGNOF '(' string ')'
        | ALIGNOF '(' string ')'
            { $$ = script_exp_function_alignof($3.value, $3.length); }
            { $$ = script_exp_function_alignof($3.value, $3.length); }
        | SIZEOF '(' string ')'
        | SIZEOF '(' string ')'
            { $$ = script_exp_function_sizeof($3.value, $3.length); }
            { $$ = script_exp_function_sizeof($3.value, $3.length); }
        | ADDR '(' string ')'
        | ADDR '(' string ')'
            { $$ = script_exp_function_addr($3.value, $3.length); }
            { $$ = script_exp_function_addr($3.value, $3.length); }
        | LOADADDR '(' string ')'
        | LOADADDR '(' string ')'
            { $$ = script_exp_function_loadaddr($3.value, $3.length); }
            { $$ = script_exp_function_loadaddr($3.value, $3.length); }
        | ORIGIN '(' string ')'
        | ORIGIN '(' string ')'
            { $$ = script_exp_function_origin($3.value, $3.length); }
            { $$ = script_exp_function_origin($3.value, $3.length); }
        | LENGTH '(' string ')'
        | LENGTH '(' string ')'
            { $$ = script_exp_function_length($3.value, $3.length); }
            { $$ = script_exp_function_length($3.value, $3.length); }
        | CONSTANT '(' string ')'
        | CONSTANT '(' string ')'
            { $$ = script_exp_function_constant($3.value, $3.length); }
            { $$ = script_exp_function_constant($3.value, $3.length); }
        | ABSOLUTE '(' exp ')'
        | ABSOLUTE '(' exp ')'
            { $$ = script_exp_function_absolute($3); }
            { $$ = script_exp_function_absolute($3); }
        | ALIGN_K '(' exp ')'
        | ALIGN_K '(' exp ')'
            { $$ = script_exp_function_align(script_exp_string(".", 1), $3); }
            { $$ = script_exp_function_align(script_exp_string(".", 1), $3); }
        | ALIGN_K '(' exp ',' exp ')'
        | ALIGN_K '(' exp ',' exp ')'
            { $$ = script_exp_function_align($3, $5); }
            { $$ = script_exp_function_align($3, $5); }
        | BLOCK '(' exp ')'
        | BLOCK '(' exp ')'
            { $$ = script_exp_function_align(script_exp_string(".", 1), $3); }
            { $$ = script_exp_function_align(script_exp_string(".", 1), $3); }
        | DATA_SEGMENT_ALIGN '(' exp ',' exp ')'
        | DATA_SEGMENT_ALIGN '(' exp ',' exp ')'
            {
            {
              script_data_segment_align(closure);
              script_data_segment_align(closure);
              $$ = script_exp_function_data_segment_align($3, $5);
              $$ = script_exp_function_data_segment_align($3, $5);
            }
            }
        | DATA_SEGMENT_RELRO_END '(' exp ',' exp ')'
        | DATA_SEGMENT_RELRO_END '(' exp ',' exp ')'
            {
            {
              script_data_segment_relro_end(closure);
              script_data_segment_relro_end(closure);
              $$ = script_exp_function_data_segment_relro_end($3, $5);
              $$ = script_exp_function_data_segment_relro_end($3, $5);
            }
            }
        | DATA_SEGMENT_END '(' exp ')'
        | DATA_SEGMENT_END '(' exp ')'
            { $$ = script_exp_function_data_segment_end($3); }
            { $$ = script_exp_function_data_segment_end($3); }
        | SEGMENT_START '(' string ',' exp ')'
        | SEGMENT_START '(' string ',' exp ')'
            {
            {
              $$ = script_exp_function_segment_start($3.value, $3.length, $5);
              $$ = script_exp_function_segment_start($3.value, $3.length, $5);
            }
            }
        | ASSERT_K '(' exp ',' string ')'
        | ASSERT_K '(' exp ',' string ')'
            { $$ = script_exp_function_assert($3, $5.value, $5.length); }
            { $$ = script_exp_function_assert($3, $5.value, $5.length); }
        ;
        ;
/* Handle the --defsym option.  */
/* Handle the --defsym option.  */
defsym_expr:
defsym_expr:
          string '=' parse_exp
          string '=' parse_exp
            { script_set_symbol(closure, $1.value, $1.length, $3, 0, 0); }
            { script_set_symbol(closure, $1.value, $1.length, $3, 0, 0); }
        ;
        ;
/* Handle the --dynamic-list option.  A dynamic list has the format
/* Handle the --dynamic-list option.  A dynamic list has the format
   { sym1; sym2; extern "C++" { namespace::sym3 }; };
   { sym1; sym2; extern "C++" { namespace::sym3 }; };
   We store the symbol we see in the "local" list; that is where
   We store the symbol we see in the "local" list; that is where
   Command_line::in_dynamic_list() will look to do its check.
   Command_line::in_dynamic_list() will look to do its check.
   TODO(csilvers): More than one of these brace-lists can appear, and
   TODO(csilvers): More than one of these brace-lists can appear, and
   should just be merged and treated as a single list.  */
   should just be merged and treated as a single list.  */
dynamic_list_expr: dynamic_list_nodes ;
dynamic_list_expr: dynamic_list_nodes ;
dynamic_list_nodes:
dynamic_list_nodes:
          dynamic_list_node
          dynamic_list_node
        | dynamic_list_nodes dynamic_list_node
        | dynamic_list_nodes dynamic_list_node
        ;
        ;
dynamic_list_node:
dynamic_list_node:
          '{' vers_defns ';' '}' ';'
          '{' vers_defns ';' '}' ';'
            { script_new_vers_node (closure, NULL, $2); }
            { script_new_vers_node (closure, NULL, $2); }
        ;
        ;
/* A version script.  */
/* A version script.  */
version_script:
version_script:
          vers_nodes
          vers_nodes
        ;
        ;
vers_nodes:
vers_nodes:
          vers_node
          vers_node
        | vers_nodes vers_node
        | vers_nodes vers_node
        ;
        ;
vers_node:
vers_node:
          '{' vers_tag '}' ';'
          '{' vers_tag '}' ';'
            {
            {
              script_register_vers_node (closure, NULL, 0, $2, NULL);
              script_register_vers_node (closure, NULL, 0, $2, NULL);
            }
            }
        | string '{' vers_tag '}' ';'
        | string '{' vers_tag '}' ';'
            {
            {
              script_register_vers_node (closure, $1.value, $1.length, $3,
              script_register_vers_node (closure, $1.value, $1.length, $3,
                                         NULL);
                                         NULL);
            }
            }
        | string '{' vers_tag '}' verdep ';'
        | string '{' vers_tag '}' verdep ';'
            {
            {
              script_register_vers_node (closure, $1.value, $1.length, $3, $5);
              script_register_vers_node (closure, $1.value, $1.length, $3, $5);
            }
            }
        ;
        ;
verdep:
verdep:
          string
          string
            {
            {
              $$ = script_add_vers_depend (closure, NULL, $1.value, $1.length);
              $$ = script_add_vers_depend (closure, NULL, $1.value, $1.length);
            }
            }
        | verdep string
        | verdep string
            {
            {
              $$ = script_add_vers_depend (closure, $1, $2.value, $2.length);
              $$ = script_add_vers_depend (closure, $1, $2.value, $2.length);
            }
            }
        ;
        ;
vers_tag:
vers_tag:
          /* empty */
          /* empty */
            { $$ = script_new_vers_node (closure, NULL, NULL); }
            { $$ = script_new_vers_node (closure, NULL, NULL); }
        | vers_defns ';'
        | vers_defns ';'
            { $$ = script_new_vers_node (closure, $1, NULL); }
            { $$ = script_new_vers_node (closure, $1, NULL); }
        | GLOBAL ':' vers_defns ';'
        | GLOBAL ':' vers_defns ';'
            { $$ = script_new_vers_node (closure, $3, NULL); }
            { $$ = script_new_vers_node (closure, $3, NULL); }
        | LOCAL ':' vers_defns ';'
        | LOCAL ':' vers_defns ';'
            { $$ = script_new_vers_node (closure, NULL, $3); }
            { $$ = script_new_vers_node (closure, NULL, $3); }
        | GLOBAL ':' vers_defns ';' LOCAL ':' vers_defns ';'
        | GLOBAL ':' vers_defns ';' LOCAL ':' vers_defns ';'
            { $$ = script_new_vers_node (closure, $3, $7); }
            { $$ = script_new_vers_node (closure, $3, $7); }
        ;
        ;
/* Here is one of the rare places we care about the distinction
/* Here is one of the rare places we care about the distinction
   between STRING and QUOTED_STRING.  For QUOTED_STRING, we do exact
   between STRING and QUOTED_STRING.  For QUOTED_STRING, we do exact
   matching on the pattern, so we pass in true for the exact_match
   matching on the pattern, so we pass in true for the exact_match
   parameter.  For STRING, we do glob matching and pass in false.  */
   parameter.  For STRING, we do glob matching and pass in false.  */
vers_defns:
vers_defns:
          STRING
          STRING
            {
            {
              $$ = script_new_vers_pattern (closure, NULL, $1.value,
              $$ = script_new_vers_pattern (closure, NULL, $1.value,
                                            $1.length, 0);
                                            $1.length, 0);
            }
            }
        | QUOTED_STRING
        | QUOTED_STRING
            {
            {
              $$ = script_new_vers_pattern (closure, NULL, $1.value,
              $$ = script_new_vers_pattern (closure, NULL, $1.value,
                                            $1.length, 1);
                                            $1.length, 1);
            }
            }
        | vers_defns ';' STRING
        | vers_defns ';' STRING
            {
            {
              $$ = script_new_vers_pattern (closure, $1, $3.value,
              $$ = script_new_vers_pattern (closure, $1, $3.value,
                                            $3.length, 0);
                                            $3.length, 0);
            }
            }
        | vers_defns ';' QUOTED_STRING
        | vers_defns ';' QUOTED_STRING
            {
            {
              $$ = script_new_vers_pattern (closure, $1, $3.value,
              $$ = script_new_vers_pattern (closure, $1, $3.value,
                                            $3.length, 1);
                                            $3.length, 1);
            }
            }
        | /* Push string on the language stack. */
        | /* Push string on the language stack. */
          EXTERN string '{'
          EXTERN string '{'
            { version_script_push_lang (closure, $2.value, $2.length); }
            { version_script_push_lang (closure, $2.value, $2.length); }
          vers_defns opt_semicolon '}'
          vers_defns opt_semicolon '}'
            {
            {
              $$ = $5;
              $$ = $5;
              version_script_pop_lang(closure);
              version_script_pop_lang(closure);
            }
            }
        | /* Push string on the language stack.  This is more complicated
        | /* Push string on the language stack.  This is more complicated
             than the other cases because we need to merge the linked-list
             than the other cases because we need to merge the linked-list
             state from the pre-EXTERN defns and the post-EXTERN defns.  */
             state from the pre-EXTERN defns and the post-EXTERN defns.  */
          vers_defns ';' EXTERN string '{'
          vers_defns ';' EXTERN string '{'
            { version_script_push_lang (closure, $4.value, $4.length); }
            { version_script_push_lang (closure, $4.value, $4.length); }
          vers_defns opt_semicolon '}'
          vers_defns opt_semicolon '}'
            {
            {
              $$ = script_merge_expressions ($1, $7);
              $$ = script_merge_expressions ($1, $7);
              version_script_pop_lang(closure);
              version_script_pop_lang(closure);
            }
            }
        | EXTERN  // "extern" as a symbol name
        | EXTERN  // "extern" as a symbol name
            {
            {
              $$ = script_new_vers_pattern (closure, NULL, "extern",
              $$ = script_new_vers_pattern (closure, NULL, "extern",
                                            sizeof("extern") - 1, 1);
                                            sizeof("extern") - 1, 1);
            }
            }
        | vers_defns ';' EXTERN
        | vers_defns ';' EXTERN
            {
            {
              $$ = script_new_vers_pattern (closure, $1, "extern",
              $$ = script_new_vers_pattern (closure, $1, "extern",
                                            sizeof("extern") - 1, 1);
                                            sizeof("extern") - 1, 1);
            }
            }
        ;
        ;
/* A string can be either a STRING or a QUOTED_STRING.  Almost all the
/* A string can be either a STRING or a QUOTED_STRING.  Almost all the
   time we don't care, and we use this rule.  */
   time we don't care, and we use this rule.  */
string:
string:
          STRING
          STRING
            { $$ = $1; }
            { $$ = $1; }
        | QUOTED_STRING
        | QUOTED_STRING
            { $$ = $1; }
            { $$ = $1; }
        ;
        ;
/* Some statements require a terminator, which may be a semicolon or a
/* Some statements require a terminator, which may be a semicolon or a
   comma.  */
   comma.  */
end:
end:
          ';'
          ';'
        | ','
        | ','
        ;
        ;
/* An optional semicolon.  */
/* An optional semicolon.  */
opt_semicolon:
opt_semicolon:
          ';'
          ';'
        |  /* empty */
        |  /* empty */
        ;
        ;
/* An optional comma.  */
/* An optional comma.  */
opt_comma:
opt_comma:
          ','
          ','
        | /* empty */
        | /* empty */
        ;
        ;
%%
%%
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.