diff options
Diffstat (limited to 'support/splint/examples/ld')
-rw-r--r-- | support/splint/examples/ld/Makefile | 118 | ||||
-rw-r--r-- | support/splint/examples/ld/ldfrontmatter.sty | 2 | ||||
-rw-r--r-- | support/splint/examples/ld/ldgram.w | 1083 | ||||
-rw-r--r-- | support/splint/examples/ld/ldgramo.w | 1645 | ||||
-rw-r--r-- | support/splint/examples/ld/ldint.sty | 259 | ||||
-rw-r--r-- | support/splint/examples/ld/ldlex.w | 550 | ||||
-rw-r--r-- | support/splint/examples/ld/ldlexo.w | 763 | ||||
-rw-r--r-- | support/splint/examples/ld/ldman.w | 572 | ||||
-rw-r--r-- | support/splint/examples/ld/ldnp.w | 362 | ||||
-rw-r--r-- | support/splint/examples/ld/ldnump.w | 306 | ||||
-rw-r--r-- | support/splint/examples/ld/ldunion.sty | 351 | ||||
-rw-r--r-- | support/splint/examples/ld/lstokenset.sty | 23 | ||||
-rw-r--r-- | support/splint/examples/ld/ltokenset.sty | 91 |
13 files changed, 6125 insertions, 0 deletions
diff --git a/support/splint/examples/ld/Makefile b/support/splint/examples/ld/Makefile new file mode 100644 index 0000000000..a23f191b9c --- /dev/null +++ b/support/splint/examples/ld/Makefile @@ -0,0 +1,118 @@ +# this Makefile uses a flat directory structure for demonstration +# purposes; the main directory (../..) contains a slightly more +# modular organization. + +SPLINT_ROOT = $(shell pwd)/../.. + +PARSER = ldp +LEXER = ldl +MANUAL = ldman + +LD_CORE_PREREQS = ${SPLINT_XTEXSTYLES} ${SPLINT_XPTABLES} ${SPLINT_XLTABLES} ${SPLINT_ROOT}/cweb/bo.tok +LD_DOC_PREREQS = %.tex %.sty ${PARSER}.tok ldunion.sty ldint.sty ldfrontmatter.sty ${LD_CORE_PREREQS} ptab.tex ltab.tex ld_small_tab.tex +LD_DOC_PREREQS += ld_small_dfa.tex ltokenset.sty lstokenset.sty +LD_DOC_PREREQS_XREF = ${LD_DOC_PREREQS} %.scn %.idx + +include ${SPLINT_ROOT}/makefile.inc +include ${SPLINT_ROOT}/makefile.loc + +# rules specific to this example + +ptabout: ${SPLINT_ROOT}/cweb/mkeparser.c ${PARSER}.c + ${CC} -DPARSER_FILE=\"../examples/ld/$(lastword $^)\" -DYYPARSE_PARAMETERS= -o $@ $< + +ptab.tex: ptabout + $< --optimize-actions --optimize-tables $@ + +ltabout: ${SPLINT_ROOT}/cweb/mkscanner.c ldl_states.h ${LEXER}.c + ${CC} -DLEXER_FILE=\"../examples/ld/$(lastword $^)\" -o $@ $< + +ltab.tex: ltabout + $< --optimize-actions --optimize-tables $@ + +${LEXER}.c: ${LEXER}.l + ${FLEX} -o $@ $< + +${PARSER}.yy : ldgram.x + @${CTANGLE} $< + +${LEXER}.ll: ldlex.x + @${CTANGLE} $< + +${MANUAL}.stx: ${MANUAL}.x ldgram.x ldlex.x ldlexo.x ldgramo.x ldnp.x + @${CTANGLE} $< + +# term name parser for ld grammar + +ldsmallp_out: ${SPLINT_ROOT}/cweb/mkeparser.c ld_small_parser.c + ${CC} ${BISON_STATE} -DPARSER_FILE=\"../examples/ld/$(lastword $^)\" -DYYPARSE_PARAMETERS= -o $@ $< + +ldsmalll_out: ${SPLINT_ROOT}/cweb/mkscanner.c ld_small_lexer.c + ${CC} -DLEXER_FILE=\"../examples/ld/$(lastword $^)\" -o $@ $< + +ld_small_tab.tex: ldsmallp_out + $< --optimize-actions --optimize-tables $@ + +ld_small_dfa.tex: ldsmalll_out + $< --optimize-actions --optimize-tables $@ + +ld_small_parser.yy \ +ld_small_lexer.ll: ldnp.x + @${CTANGLE} $< + +# numeric parser for ld grammar + +ldnump_out: ${SPLINT_ROOT}/cweb/mkeparser.c ld_num_parser.c + ${CC} ${BISON_STATE} -DPARSER_FILE=\"../examples/ld/$(lastword $^)\" -DYYPARSE_PARAMETERS= -o $@ $< + +ldnuml_out: ${SPLINT_ROOT}/cweb/mkscanner.c ld_num_lexer.c + ${CC} -DLEXER_FILE=\"../examples/ld/$(lastword $^)\" -o $@ $< + +ld_num_tab.tex: ldnump_out + $< --optimize-actions --optimize-tables $@ + +ld_num_dfa.tex: ldnuml_out + $< --optimize-actions --optimize-tables $@ + +ld_num_parser.yy \ +ld_num_lexer.ll: ldnump.x + @${CTANGLE} $< + +${MANUAL}.tex: ${MANUAL}.x ldgram.x ldlex.x ldlexo.x ldgramo.x ldnp.x + ${CWEAVE} $< + +${MANUAL}.sty: ${MANUAL}.stx + ${UNLINE} $< $@ + +${MANUAL}.gdx: %.gdx: ${LD_DOC_PREREQS_XREF} ${PARSER}.tok + @echo "Making the bison and TeX indices ..." + ${TEX} $*.tex + +${MANUAL}.pdf: %.pdf: ${LD_DOC_PREREQS_XREF} %.gdy + ${PDFTEX} $< && touch $*.gdy && touch $*.pdf + +#${PARSER}.tok \ +#ldl_states.h: ${MANUAL}.tex ${MANUAL}.sty ${LD_CORE_PREREQS} +# ${TEX} ${MODEBOOTSTRAP} \\input $< + +${PARSER}.tok: ldgram.tex ${MANUAL}.sty ${LD_CORE_PREREQS} + ${TEX} ${MODEBOOTSTRAP} \\input $< + +ldl_states.h: ldlex.tex ${MANUAL}.sty ${LD_CORE_PREREQS} + ${TEX} ${MODEBOOTSTRAP} \\input $< + +ldgram.tex ldlex.tex: \ +%.tex: %.x + ${CWEAVE} -x $< + +docs: ${MANUAL}.pdf + +mostlyclean: clean_temp + -rm -f ptabout ltabout ldsmalll_out ldsmallp_out ldnump_out ldnuml_out ${MANUAL}.c + +clean: clean_core + -rm -f ptabout ltabout ldsmalll_out ldsmallp_out ldnump_out ldnuml_out *.stx ldman.sty + +distclean: clean + cd ${SPLINT_ROOT} && ${MAKE} clean + diff --git a/support/splint/examples/ld/ldfrontmatter.sty b/support/splint/examples/ld/ldfrontmatter.sty new file mode 100644 index 0000000000..e4fd94bcf2 --- /dev/null +++ b/support/splint/examples/ld/ldfrontmatter.sty @@ -0,0 +1,2 @@ +% this file is left blank on purpose to avoid referencing non-free fonts +% it would contain the \TeX\ macros that generate the cover page for \ld\ parser manual diff --git a/support/splint/examples/ld/ldgram.w b/support/splint/examples/ld/ldgram.w new file mode 100644 index 0000000000..4fb9a9a876 --- /dev/null +++ b/support/splint/examples/ld/ldgram.w @@ -0,0 +1,1083 @@ +@q Copyright 2012-2015 Alexander Shibakov@> +@q Copyright 2002-2014 Free Software Foundation, Inc.@> +@q This file is part of SPLinT@> + +@q SPLinT is free software: you can redistribute it and/or modify@> +@q it under the terms of the GNU General Public License as published by@> +@q the Free Software Foundation, either version 3 of the License, or@> +@q (at your option) any later version.@> + +@q SPLinT is distributed in the hope that it will be useful,@> +@q but WITHOUT ANY WARRANTY; without even the implied warranty of@> +@q MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the@> +@q GNU General Public License for more details.@> + +@q You should have received a copy of the GNU General Public License@> +@q along with SPLinT. If not, see <http://www.gnu.org/licenses/>.@> + +@** The parser. +\ifx\parsernamespace\UNDEFINED + \def\tokendeffile{ldp.tok}% + \input ldman.sty + \input limbo.sty + \input dcols.sty + \setupfootnotes + \def\MRI{} + \def\ld{} +\fi +\immediate\openout\exampletable=\jobname.exl\relax% +The outline of the grammar file below does not reveal anything unusual +in the general layout of \ld\ grammar. The first section lists all the +token definitions, \prodstyle{\%union} styles, and some \Cee\ +code. The original comments that come with the grammar file of the +linker have been mostly left intact. They are typeset in {\it +italics\/} to make them easy to recognize. + +@s TeX_ TeX +@s TeXa TeX +@s TeXb TeX +@s TeXf TeX +@s TeXfo TeX +@s TeXao TeX + +@(ldp.yy@>= +@G Switch to generic mode. +%{@> @<\ld\ parser \Cee\ preamble@> @=%} + @> @<\ld\ parser \bison\ options@> @= +%union {@> @<Union of grammar parser types@> @=} +%{@> @<\ld\ parser \Cee\ postamble@> @=%} + @> @<Token and type declarations@> @= +%% + @> @<\ld\ parser productions@> @= +%% +@g + +@ Among the options listed in this section, \prodstyle{\%token-table} +is the most critical for the proper operation of the parser and must be enabled +to supply the token information to the lexer (the traditional way +of passing this information along is to use a \Cee\ header file with +the appropriate definitions). The start symbol does not have to be +given explicitly and can be indicated by listing the appropriate rules +at the beginning. + +Most other sections of the grammar file, with the exception of the +rules are either empty or hold placeholder values. The functionality +provided by the code in these sections in the case of a \Cee\ parser +is supplied by the \TeX\ macros in \.{ldman.sty}. +@<\ld\ parser \bison\ options@>= +@G +%token-table +%debug +%start script_file +@g + +@ @<\ld\ parser \Cee\ preamble@>= + +@ @<Union of grammar parser types@>= + +@ @<\ld\ parser \Cee\ postamble@>= +#define YYPRINT(file, type, value) yyprint (file, type, value) + static void yyprint (FILE *file, int type, YYSTYPE value){} + +@ @<\ld\ parser productions@>= + @<\GNU\ \ld\ script rules@>@; + @<Grammar rules@>@; + +@ The tokens are declared first. This section is also used to supply +numerical token values to the lexer by the original parser, as well as +the bootstrapping phase of the typesetting parser. Unlike the native (\Cee) parser for +\ld\ the typesetting parser has no need for the type of each token +(rather, the type consistency is based on the weak dynamic type system +coded in \.{yyunion.sty} and \.{ldunion.sy}). Thus all the tokens used +by the \ld\ parser are put in a single list. +@<Token and type declarations@>= +@G +%token INT +%token NAME LNAME +%token END +%token ALIGN_K BLOCK BIND QUAD SQUAD LONG SHORT BYTE +%token SECTIONS PHDRS INSERT_K AFTER BEFORE +%token DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END DATA_SEGMENT_END +%token SORT_BY_NAME SORT_BY_ALIGNMENT SORT_NONE +%token SORT_BY_INIT_PRIORITY +%token '{' '}' +%token SIZEOF_HEADERS OUTPUT_FORMAT FORCE_COMMON_ALLOCATION OUTPUT_ARCH +%token INHIBIT_COMMON_ALLOCATION +%token SEGMENT_START +%token INCLUDE +%token MEMORY +%token REGION_ALIAS +%token LD_FEATURE +%token NOLOAD DSECT COPY INFO OVERLAY +%token DEFINED TARGET_K SEARCH_DIR MAP ENTRY +%token NEXT +%token SIZEOF ALIGNOF ADDR LOADADDR MAX_K MIN_K +%token STARTUP HLL SYSLIB FLOAT NOFLOAT NOCROSSREFS +%token ORIGIN FILL +%token LENGTH CREATE_OBJECT_SYMBOLS INPUT GROUP OUTPUT CONSTRUCTORS +%token ALIGNMOD AT SUBALIGN HIDDEN PROVIDE PROVIDE_HIDDEN AS_NEEDED +%token CHIP LIST SECT ABSOLUTE LOAD NEWLINE ENDWORD ORDER NAMEWORD ASSERT_K +%token LOG2CEIL FORMAT PUBLIC DEFSYMEND BASE ALIAS TRUNCATE REL +%token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM CASE EXTERN START +%token VERS_TAG VERS_IDENTIFIER +%token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT +%token KEEP ONLY_IF_RO ONLY_IF_RW SPECIAL INPUT_SECTION_FLAGS ALIGN_WITH_INPUT +%token EXCLUDE_FILE +%token CONSTANT +%token INPUT_DYNAMIC_LIST +%right PLUSEQ MINUSEQ MULTEQ DIVEQ '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ '?' ':' UNARY +%left OROR ANDAND '|' '^' '&' EQ NE '<' '>' LE GE LSHIFT RSHIFT '+' '-' '*' '/' '%' '(' +@g + +@*1 Grammar rules, an overview. +The first natural step in transforming an existing parser into a +`parser stack' for pretty printing is to understand the `anatomy' of +the grammar. Not every grammar is suitable for such a transformation +and in almost every case, some modifications are needed. The +parser and lexer implementation for \ld\ is not terrible although it does +have some idiosynchasies that could have been eliminated by a careful +grammar redesign. Instead of invasive rewriting of significant +portions of the grammar, the approach taken here merely omits some +rules and partitions the grammar into several subsets, each of which +is supposed to handle a well defined logical section of an \ld\ script +file. + +One example of a trick used by the \ld\ parser that is not appropriate for a +pretty printing grammar implements a way of handling the choice of the +format of an input file. After a command line option that selects the +input format has been read (or the format has been determined using +some other method), the first token output by the lexer branches the +parser to the appropriate portion of the full grammar. + +Since the token never appears as part of the input file there is no +need to include this part of the main grammar for the purposes of +typesetting. +\traceparserstatestrue +\tracestackstrue +\tracerulestrue +\traceactionstrue +\tracelookaheadtrue +\traceparseresultstrue +\tracebadcharstrue +\yyflexdebugtrue +%\checktabletrue +% +\traceparserstatesfalse +\tracestacksfalse +\tracerulesfalse +\traceactionsfalse +\tracelookaheadfalse +\traceparseresultsfalse +\tracebadcharsfalse +\yyflexdebugfalse +\checktablefalse +% +\saveparseoutputfalse +@<Ignored grammar rules@>= +@G +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 +; +@g + +@ @<Grammar rules@>= +@G +@t}\vb{\inline\flatten}{@> +filename: + NAME {@>@[TeX_( "/yy0{/noexpand/ldfilename{/the/yy(1)}}" );@]@=} +; +@g + +@ The simplest parser subset is intended to parse symbol definitions +given in the command line that invokes the linker. Creating a parser +for it involves almost no extra effort so we leave it in. + +Note that the simpliciy is somewhat deceptive as the syntax of +\prodstyle{exp} is rather complex. That part of the grammar is needed +elsewhere, however, so symbol definitions parsing costs almost nothing +on top of the already required effort. The only practical use for this +part of the \ld\ grammar is presenting examples in text. + +The\namedspot{pingpong} \TeX\ macro \.{\\ldlex@@defsym} switches the lexer state to +\.{DEFSYMEXP} (see \locallink{stateswitchers}all the state switching +macros\endlink\ in the chapter about the lexer implementation +below). Switching lexer states from the parser presents some +difficulties which can be overcome by careful design. For example, the +state switching macros can be invoked before the lexer is called and +initialized (when the parser performs a {\it default action\/}). +@<Inline symbol definitions@>= +@G +defsym_expr: + {@>@[TeX_( "/ldlex@@defsym" );@]@=} + NAME '=' exp {@>@[TeX_( "/ldlex@@popstate" );@]@=} + ; +@g + +@ {\it Syntax within an \MRI\ script file}\footnote{As explained at the +beginning of this chapter, the text in {\it italics\/} was taken from +the original comments by \ld\ parser and lexer programmers.}. The parser for typesetting +is only intended to process \GNU\ \ld\ scripts and does not concern +itself with any additional compatibility modes. For this reason, all +support for \MRI\ style scripts has been omitted. One use for the +section below is a small demonstration of the formatting tools that +change the output of the \bison\ parser. +@<\MRI\ style script rules@>= +@G +@t}\vb{\inline\flatten}{@> +mri_script_file: + {@>@[TeX_( "/ldlex@@mri@@script" );@]@=} + mri_script_lines {@>@[TeX_( "/ldlex@@popstate" );@]@=} + ; + +mri_script_lines: + mri_script_lines mri_script_command NEWLINE + | + ; +@t}\vb{\resetf}{@> +mri_script_command: + CHIP exp + | CHIP exp ',' exp + | NAME {} + | LIST {} + | ORDER ordernamelist {} + | ENDWORD {} +@t}\vb{\flatten}{@> + | PUBLIC NAME '=' exp {} + | PUBLIC NAME ',' exp {} + | PUBLIC NAME exp +@t}\vb{\resetf}{@> + {} + | FORMAT NAME {} +@t}\vb{\flatten}{@> + | SECT NAME ',' exp {} + | SECT NAME exp {} + | SECT NAME '=' exp +@t}\vb{\resetf}{@> + {} +@t}\vb{\flatten}{@> + | ALIGN_K NAME '=' exp {} + | ALIGN_K NAME ',' exp +@t}\vb{\resetf}{@> + {} +@t}\vb{\flatten}{@> + | ALIGNMOD NAME '=' exp {} + | ALIGNMOD NAME ',' exp {} +@t}\vb{\resetf}{@> + {} + | ABSOLUTE mri_abs_name_list + | LOAD mri_load_name_list + | NAMEWORD NAME {} +@t}\vb{\flatten}{@> + | ALIAS NAME ',' NAME {} + | ALIAS NAME ',' INT {} +@t}\vb{\resetf}{@> + {} + | BASE exp {} + | TRUNCATE INT {} + | CASE casesymlist + | EXTERN extern_name_list +@t}\vb{\flatten}{@> + | INCLUDE filename {@>@<Peek at a file@>@=} + mri_script_lines END +@t}\vb{\resetf}{@> + {@>@<Close the file@>@=} + | START NAME {} + | + ; +@t}\vb{\inline\flatten}{@> +ordernamelist: + ordernamelist ',' NAME {} + | ordernamelist NAME {} + | + ; + +mri_load_name_list: + NAME {} + | mri_load_name_list ',' NAME {} + ; + +mri_abs_name_list: + NAME {} + | mri_abs_name_list ',' NAME {} + ; + +casesymlist: + {} + | NAME + | casesymlist ',' NAME + ; +@g + +@ {\it Parsed as expressions so that commas separate entries.} The +core of the parser consists of productions describing \GNU\ \ld\ linker +scripts. The first rule is common to both \MRI\ and \GNU\ formats. +@<\GNU\ \ld\ script rules@>= +@G +extern_name_list: + {@>@[TeX_( "/ldlex@@expression" );@]@=} + extern_name_list_body {@>@[TeX_( "/ldlex@@popstate" );@]@=} + ; + +extern_name_list_body: + NAME {} + | extern_name_list_body NAME {} + | extern_name_list_body ',' NAME {} + ; + +@ The top level productions simply define a script file as a list of +script commands. +@<\GNU\ \ld\ script rules@>= +@G +script_file: + {@>@[TeX_( "/ldlex@@both" );@]@=} + ifile_list {@>@[TeX_( "/getsecond{/yy(2)}/to/ldcmds/ldlex@@popstate" );@]@=} + ; + +ifile_list: + ifile_list ifile_p1 {@>@<Add the next command@>@=} + | {@>@[TeX_( "/yy0{{}{}}" );@]@=} + ; +@g + +@ @<Add the next command@>= + @[TeX_( "/getfirst{/yy(1)}/to/toksa/getsecond{/yy(1)}/to/toksb" );@]@; + @[TeX_( "/getfirst{/yy(2)}/to/toksc/getsecond{/yy(2)}/to/toksd" );@]@; + @[TeXb( "/yytoksempty{/toksb}{/yy0{/the/yy(2)}}" );@]@; + @[TeXao( "{/yy0{{/the/toksc}{/the/toksb/noexpand/ldcommandseparator{/the/toksa}{/the/toksc}/the/toksd}}}" );@]@; + +@*1 Script internals. +There are a number of different commands. For typesetting purposes, +the handling of most of these can be significantly +simplified. In the \prodstyle{GROUP} command there is no need to +perform any actions upon entering the group, for +instance. \prodstyle{INCLUDE} presents a special challenge. In +the original grammar this command is followed by a general list of script +commands (the contents of the included file) terminated by +\prodstyle{END}. The `magic' of opening the file and inserting its +contents into the stream being parsed is performed by the lexer and +the parser in the +background. The typesetting parser, on the other hand, only has to +typeset the \prodstyle{INCLUDE} command itself and has no need for +opening and parsing the file being included. We can simply change the +grammar rule to omit the follow up script commands but that would +require altering the existing grammar. \namedspot{pretendbuffersw}Since the command list +(\prodstyle{ifile\_list}) is allowed to be empty, +we simply \locallink{pretendbufferswlex}fake\endlink\ the +inclusion of the file in the lexer by immediately outputting +\prodstyle{END} upon entering the appropriate lexer state. One +advantage in using this approach is the ability, when desired, to +examine the included file for possible cross-referencing information. + +Each command is packaged with a qualifier that records its type for +the rule that adds the fragment to the script file. +@<\GNU\ \ld\ script rules@>= +@G +ifile_p1: + memory {@>@[TeX_( "/yy0{{mem}{/the/yy(1)}}" );@]@=} + | sections {@>@[TeX_( "/yy0{{sect}{/the/yy(1)}}" );@]@=} + | phdrs + | startup + | high_level_library + | low_level_library + | floating_point_support + | statement_anywhere {@>@[TeX_( "/yy0{{stmt}{/noexpand/ldstatement{/the/yy(1)}}}" );@]@=} + | version + | ';' {@>@[TeX_( "/yy0{{none}{}}" );@]@=} + | TARGET_K '(' NAME ')' {} + | SEARCH_DIR '(' filename ')' {} + | OUTPUT '(' filename ')' {} + | OUTPUT_FORMAT '(' NAME ')' {} + | OUTPUT_FORMAT '(' NAME ',' + NAME ',' NAME ')' {} + | OUTPUT_ARCH '(' NAME ')' {} + | FORCE_COMMON_ALLOCATION {} + | INHIBIT_COMMON_ALLOCATION {} + | INPUT '(' input_list ')' + | GROUP {} + '(' input_list ')' {} + | MAP '(' filename ')' {} + | INCLUDE filename {@>@<Peek at a file@>@=} + ifile_list END {@>@<Add an \prodstyle{INCLUDE} statement@>@=} + | NOCROSSREFS '(' + nocrossref_list ')' {} + | EXTERN '(' extern_name_list ')' + | INSERT_K AFTER NAME {} + | INSERT_K BEFORE NAME {} + | REGION_ALIAS '(' NAME ',' NAME ')' {} + | LD_FEATURE '(' NAME ')' {} + ; + +input_list: + NAME {} + | input_list ',' NAME {} + | input_list NAME {} + | LNAME {} + | input_list ',' LNAME {} + | input_list LNAME {} + | AS_NEEDED '(' {} + input_list ')' {} + | input_list ',' AS_NEEDED '(' {} + input_list ')' {} + | input_list AS_NEEDED '(' {} + input_list ')' {} + ; + +sections: + SECTIONS '{' sec_or_group_p1 '}' {@>@[TeX_( "/yy0{/noexpand/ldsections{/the/yy(3)}}" );@]@=} + ; + +sec_or_group_p1: + sec_or_group_p1 section {@>@<Add the next section@>@=} + | sec_or_group_p1 statement_anywhere {@>@<Add the next statement@>@=} + | {@>@[TeX_( "/yy0{}" );@]@=} + ; + +statement_anywhere: + ENTRY '(' NAME ')' {} + | assignment end {@>@<Carry on@>@=} + | ASSERT_K {@>@[TeX_( "/ldlex@@expression" );@]@=} + '(' exp ',' NAME ')' {@>@[TeX_( "/ldlex@@popstate" );@]@=} + ; +@g + +@ @<Add the next section@>= + @[TeXb( "/yytoksempty{/yy(1)}{/yy0{/the/yy(2)}}" );@]@; + @[TeXao( "{/yy0{/the/yy(1)/noexpand/ldsectionseparator/the/yy(2)}}" );@]@; + +@ @<Add the next statement@>= + @[TeXb( "/yytoksempty{/yy(1)}{/yy0{/the/yy(2)}}" );@]@; + @[TeXao( "{/yy0{/the/yy(1)/noexpand/ldsectionseparator/ldstatement{/the/yy(2)}}}" );@]@; + +@ This is the default action performed by the parser when the parser +writer does not supply one. For a minor gain in efficiency, this +definition can be made empty. +@<Carry on@>= + @[TeX_( "/yy0{/the/yy(1)}" );@]@; + +@ @<Peek at a file@>= + @[TeX_( "/ldlex@@script" );@]@; + @[TeX_( "/ldfile@@open@@command@@file{/yy(2)}" );@]@; + +@ @<Close the file@>= + @[TeX_( "/yy0{/noexpand/ldinclude{/the/yy(2)}}/ldlex@@popstate" );@]@; + +@ @<Add an \prodstyle{INCLUDE} statement@>= + @[TeX_( "/yy0{{inc}{/noexpand/ldinclude{/the/yy(2)}}}/ldlex@@popstate" );@]@; + +@ \tracebadcharstrue +{\it The \prodstyle{'*'} and \prodstyle{'?'} cases are there because the lexer returns them as +separate tokens rather than as \prodstyle{NAME}.} +\tracebadcharsfalse +@<Grammar rules@>= +@G +wildcard_name: + NAME {@>@<Carry on@>@=} + | '*' {@>@[TeX_( "/yy0{{*}{*}}" );@]@=} + | '?' {@>@[TeX_( "/yy0{{?}{?}}" );@]@=} + ; +@g + +@ @<Grammar rules@>= +@G +wildcard_spec: + wildcard_name {} + | EXCLUDE_FILE '(' exclude_name_list ')' wildcard_name + {} + | SORT_BY_NAME '(' wildcard_name ')' {} + | SORT_BY_ALIGNMENT '(' wildcard_name ')' + {} + | SORT_NONE '(' wildcard_name ')' + {} + | SORT_BY_NAME '(' SORT_BY_ALIGNMENT '(' wildcard_name ')' ')' + {} + | SORT_BY_NAME '(' SORT_BY_NAME '(' wildcard_name ')' ')' + {} + | SORT_BY_ALIGNMENT '(' SORT_BY_NAME '(' wildcard_name ')' ')' + {} + | SORT_BY_ALIGNMENT +@t}\vb{\breakline}{@> + '(' SORT_BY_ALIGNMENT '(' wildcard_name ')' ')' + {} + | SORT_BY_NAME +@t}\vb{\breakline}{@> + '(' EXCLUDE_FILE '(' exclude_name_list ')' wildcard_name ')' + {} + | SORT_BY_INIT_PRIORITY '(' wildcard_name ')' + {} + ; + +sect_flag_list: + NAME {} + | sect_flag_list '&' NAME {} + ; + +sect_flags: + INPUT_SECTION_FLAGS '(' sect_flag_list ')' {} + ; + +exclude_name_list: + exclude_name_list wildcard_name {} + | wildcard_name {} + ; + +file_NAME_list: + file_NAME_list opt_comma wildcard_spec {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/ldspace/noexpand/ldregexp{/the/yy(2)}}" );@]@=} + | wildcard_spec {@>@[TeX_( "/yy0{/noexpand/ldregexp{/the/yy(1)}}" );@]@=} + ; + +input_section_spec_no_keep: + NAME {} + | sect_flags NAME {} + | '[' file_NAME_list ']' {} + | sect_flags '[' file_NAME_list ']' {} + | wildcard_spec '(' file_NAME_list ')' {@>@[TeX_( "/yy0{/noexpand/ldregexp{/the/yy(1)}(/the/yy(3))}" );@]@=} + | sect_flags wildcard_spec '(' file_NAME_list ')' + {} + ; +@g + +@ @<Grammar rules@>= +@G +input_section_spec: + input_section_spec_no_keep {@>@<Carry on@>@=} + | KEEP '(' {} + input_section_spec_no_keep ')' {@>@[TeX_( "/yy0{/mathop{/hbox{/noexpand/ttl keep}(/the/yy(4))}}" );@]@=} + ; + +statement: + assignment end + | CREATE_OBJECT_SYMBOLS {} + | ';' {@>@[TeX_( "/yy0{}" );@]@=} + | CONSTRUCTORS {} + | SORT_BY_NAME '(' CONSTRUCTORS ')' {} + | input_section_spec + | length '(' mustbe_exp ')' {} + | FILL '(' fill_exp ')' {} + | ASSERT_K {@>@[TeX_( "/ldlex@@expression" );@]@=} + '(' exp ',' NAME ')' end {@>@[TeX_( "/ldlex@@popstate" );@]@=} + | INCLUDE filename {@>@<Peek at a file@>@=} + statement_list_opt END {@>@<Close the file@>@=} + ; + +statement_list: + statement_list statement {@>@<Attach a statement to a statement list@>@=} + | statement {@>@<Start a statement list with a statement@>@=} + ; + +statement_list_opt: + {@>@[TeX_( "/yy0{}" );@]@=} + | statement_list {@>@<Carry on@>@=} + ; +@g + +@ @<Attach a statement to a statement list@>= + @[TeX_( "/yy0{/the/yy(1)/yytoksempty{/yy(2)}{}{/yytoksempty{/yy(1)}{}{/noexpand/ldor}{/the/yy(2)}}}" );@] + +@ @<Start a statement list with a statement@>= + @[TeX_( "/yy0{/yytoksempty{/yy(1)}{}{{/the/yy(1)}}}" );@] + +@ @<Grammar rules@>= +@G +@t}\vb{\inline\flatten}{@> +length: + QUAD {} + | SQUAD {} + | LONG {} + | SHORT {} + | BYTE {} + ; + +fill_exp: + mustbe_exp {@>@<Carry on@>@=} + ; + +fill_opt: + '=' fill_exp {@>@[TeX_( "/yy0{/noexpand/ldfill{/the/yy(2)}}" );@]@=} + | {@>@[TeX_( "/yy0{}" );@]@=} + ; + +@t}\vb{\resetf}{@> +assign_op: + PLUSEQ {@>@[TeX_( "/yy(0)={/MRL{+{/K}}}" );@]@=} + | MINUSEQ {@>@[TeX_( "/yy(0)={/MRL{-{/K}}}" );@]@=} +@t}\vb{\inline\flatten}{@> + | MULTEQ {@>@[TeX_( "/yy(0)={/MRL*{/K}}" );@]@=} + | DIVEQ {@>@[TeX_( "/yy(0)={/MRL{{/div}{/K}}}" );@]@=} + | LSHIFTEQ {@>@[TeX_( "/yy(0)={/MRL{{/ll}{/K}}}" );@]@=} + | RSHIFTEQ {@>@[TeX_( "/yy(0)={/MRL{{/gg}{/K}}}" );@]@=} + | ANDEQ {@>@[TeX_( "/yy(0)={/Xandxeq}" );@]@=} + | OREQ {@>@[TeX_( "/yy(0)={/Xorxeq}" );@]@=} + ; + +end: ';' | ',' + ; + +opt_comma: ',' | + ; +@t}\vb{\resetf}{@> +@g + +@ Assignments are not expressions as in \Cee. +@<Grammar rules@>= +@G +assignment: + NAME '=' mustbe_exp {@>@<Process simple assignment@>@=} + | NAME assign_op mustbe_exp {@>@<Process compound assignment@>@=} + | HIDDEN '(' NAME '=' mustbe_exp ')' {} + | PROVIDE '(' NAME '=' mustbe_exp ')' {} + | PROVIDE_HIDDEN '(' NAME '=' mustbe_exp ')' {} + ; +@g + +@ @<Process simple assignment@>= + @[TeX_( "/yy0{/noexpand/ldassignment{/noexpand/ldregexp{/the/yy(1)}}{/K}{/the/yy(3)}}" );@] + +@ @<Process compound assignment@>= + @[TeX_( "/yy0{/noexpand/ldassignment{/noexpand/ldregexp{/the/yy(1)}}{/the/yy(2)}{/the/yy(3)}}" );@] + +@ @<Grammar rules@>= +@G +memory: + MEMORY '{' memory_spec_list_opt '}' {@>@[TeX_( "/yy0{/noexpand/ldmemory{/the/yy(3)}}" );@]@=} + ; + +memory_spec_list_opt: + memory_spec_list {@>@<Carry on@>@=} + | {@>@[TeX_( "/yy0{}" );@]@=} + ; + +memory_spec_list: + memory_spec_list opt_comma memory_spec {@>@[TeX_( "/yy0{/the/yy(1)/the/yy(3)}" );@]@=} + | memory_spec {@>@[TeX_( "/yy0{/the/yy(1)}" );@]@=} + ; + + +memory_spec: + NAME {} + attributes_opt ':' + origin_spec +@t}\vb{\breakline}{@> + opt_comma length_spec {@>@[TeX_( "/yy0{/noexpand/ldmemoryspec{/the/yy(1)}{/the/yy(3)}{/the/yy(5)}{/the/yy(7)}}" );@]@=} + | INCLUDE filename {@>@<Peek at a file@>@=} + memory_spec_list_opt END {@>@<Close the file@>@=} + ; +@g + +@ @<Grammar rules@>= +@G +origin_spec: + ORIGIN '=' mustbe_exp {@>@[TeX_( "/yy0{/noexpand/ldoriginspec{/the/yy(3)}}" );@]@=} + ; + +length_spec: + LENGTH '=' mustbe_exp {@>@[TeX_( "/yy0{/noexpand/ldlengthspec{/the/yy(3)}}" );@]@=} + ; + +attributes_opt: + + {@>@[TeX_( "/yy0{}" );@]@=} + | '(' attributes_list ')' {@>@[TeX_( "/yy0{/the/yy(2)}" );@]@=} + ; + +attributes_list: + attributes_string {@>@[TeX_( "/yy0{/the/yy(1)}" );@]@=} + | attributes_list attributes_string {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/ldspace/the/yy(2)}" );@]@=} + ; + +attributes_string: + NAME {@>@[TeX_( "/yy0{/noexpand/ldattributes{/the/yy(1)}}" );@]@=} + | '!' NAME {@>@[TeX_( "/yy0{/noexpand/ldattributesneg{/the/yy(2)}}" );@]@=} + ; + +startup: + STARTUP '(' filename ')' {} + ; + +high_level_library: + HLL '(' high_level_library_NAME_list ')' + | HLL '(' ')' {} + ; + +high_level_library_NAME_list: + high_level_library_NAME_list opt_comma filename + {} + | filename {} + ; + +low_level_library: + SYSLIB '(' low_level_library_NAME_list ')' {} + ; + +low_level_library_NAME_list: + low_level_library_NAME_list opt_comma filename + {} + | {} + ; + +floating_point_support: + FLOAT {} + | NOFLOAT {} + ; + +nocrossref_list: + {} + | NAME nocrossref_list {} + | NAME ',' nocrossref_list {} + ; + +mustbe_exp: + {@>@[TeX_( "/ldlex@@expression" );@]@=} + exp {@>@[TeX_( "/ldlex@@popstate/yy0{/the/yy(2)}" );@]@=} + ; +@g + +@*1 {\ifheader\ninepoint\fi\prodstyle{SECTIONS}} and expressions. +The linker supports an extensive range of expressions. The precedence +mechanism provided by \bison\ is used to present the composition of +expressions out of simpler chunks and basic building blocks tied +together by algebraic operations. +@<Grammar rules@>= +@G +exp : + '-' exp %prec UNARY {@>@[TeX_( "/yy0{{-/the/yy(2)}}" );@]@=} + | '(' exp ')' {@>@[TeX_( "/yy0{(/the/yy(2))}" );@]@=} + | NEXT '(' exp ')' %prec UNARY {@>@[TeX_( "/yy0{/hbox{/nx/ssf next}(/the/yy(3))}" );@]@=} + | '!' exp %prec UNARY {@>@[TeX_( "/yy0{{/noexpand/CM/the/yy(2)}}" );@]@=} + | '+' exp %prec UNARY {@>@[TeX_( "/yy0{{+/the/yy(2)}}" );@]@=} + | '~' exp %prec UNARY {@>@[TeX_( "/yy0{{/noexpand/R/the/yy(2)}}" );@]@=} + | exp '*' exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/times/the/yy(3)}" );@]@=} + | exp '/' exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand///the/yy(3)}" );@]@=} + | exp '%' exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/div/the/yy(3)}" );@]@=} + | exp '+' exp {@>@[TeX_( "/yy0{/the/yy(1)+/the/yy(3)}" );@]@=} + | exp '-' exp {@>@[TeX_( "/yy0{/the/yy(1)-/the/yy(3)}" );@]@=} + | exp LSHIFT exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/ll/the/yy(3)}" );@]@=} + | exp RSHIFT exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/gg/the/yy(3)}" );@]@=} + | exp EQ exp {@>@[TeX_( "/yy0{/the/yy(1)=/the/yy(3)}" );@]@=} + | exp NE exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/not=/the/yy(3)}" );@]@=} + | exp LE exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/leq/the/yy(3)}" );@]@=} + | exp GE exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/geq/the/yy(3)}" );@]@=} + | exp '<' exp {@>@[TeX_( "/yy0{/the/yy(1)</the/yy(3)}" );@]@=} + | exp '>' exp {@>@[TeX_( "/yy0{/the/yy(1)>/the/yy(3)}" );@]@=} + | exp '&' exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/AND/the/yy(3)}" );@]@=} + | exp '^' exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/XOR/the/yy(3)}" );@]@=} + | exp '|' exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/OR/the/yy(3)}" );@]@=} + | exp '?' exp ':' exp {@>@<Process a primitive conditional@>@=} + | exp ANDAND exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/V/the/yy(3)}" );@]@=} + | exp OROR exp {@>@[TeX_( "/yy0{/the/yy(1)/noexpand/W/the/yy(3)}" );@]@=} +@g + +@ More atomic expression types specific to the linker's function. +@<Grammar rules@>= +@G +exp : + DEFINED '(' NAME ')' {} + | INT {} + | SIZEOF_HEADERS {} + | ALIGNOF '(' NAME ')' {} + | SIZEOF '(' NAME ')' {} + | ADDR '(' NAME ')' {} + | LOADADDR '(' NAME ')' {} + | CONSTANT '(' NAME ')' {} + | ABSOLUTE '(' exp ')' {} + | ALIGN_K '(' exp ')' {@>@[TeX_( "/yy0{/nx/mathop{/hbox{/nx/ssf align}}(/the/yy(3))}" );@]@=} + | ALIGN_K '(' exp ',' exp ')' {} + | DATA_SEGMENT_ALIGN '(' exp ',' exp ')' {} + | DATA_SEGMENT_RELRO_END '(' exp ',' exp ')' {} + | DATA_SEGMENT_END '(' exp ')' {} + | SEGMENT_START '(' NAME ',' exp ')' {} + | BLOCK '(' exp ')' {} + | NAME {@>@[TeX_( "/yy0{/noexpand/ldregexp{/the/yy(1)}}" );@]@=} + | MAX_K '(' exp ',' exp ')' {} + | MIN_K '(' exp ',' exp ')' {} + | ASSERT_K '(' exp ',' NAME ')' {} + | ORIGIN '(' NAME ')' {} + | LENGTH '(' NAME ')' {} + | LOG2CEIL '(' exp ')' {} + ; +@g + +@ @<Process a primitive conditional@>= +@q TeX_( "/yy0{/hbox{/nx/ttl let }/nx/xi(0)=/the/yy(5): /nx/xi(/nx/CM0)=/the/yy(3)/hbox{ /nx/ttl do }/xi(/the/yy(1))}" );@> +@[TeX_( "/yy0{/hbox{/nx/ttl do }/xi(/the/yy(1))/hbox{ /nx/ttl where }" );@> +@[TeX_( " {/let/nx/{/nx/bigbracedel/nx/xi(x)=/nx/cases{/the/yy(5)& if /inmath{x=0}/cr/the/yy(3)& if /inmath{x/nx/not=0}}}}" );@] + +@ @<Grammar rules@>= +@G +memspec_at_opt: + AT '>' NAME {@>@[TeX_( "/yy0{/the/yy(3)}" );@]@=} + | {@>@[TeX_( "/yy0{}" );@]@=} + ; + +opt_at: + AT '(' exp ')' {@>@[TeX_( "/yy0{/the/yy(3)}" );@]@=} + | {@>@[TeX_( "/yy0{}" );@]@=} + ; + +opt_align: + ALIGN_K '(' exp ')' {@>@[TeX_( "/yy0{/the/yy(3)}" );@]@=} + | {@>@[TeX_( "/yy0{}" );@]@=} + ; + +opt_align_with_input: + ALIGN_WITH_INPUT {@>@[TeX_( "/yy0{align with input}" );@]@=} + | {@>@[TeX_( "/yy0{}" );@]@=} + ; + +opt_subalign: + SUBALIGN '(' exp ')' {@>@[TeX_( "/yy0{/the/yy(3)}" );@]@=} + | {@>@[TeX_( "/yy0{}" );@]@=} + ; + +sect_constraint: + ONLY_IF_RO {@>@[TeX_( "/yy0{only/_if/_ro}" );@]@=} + | ONLY_IF_RW {@>@[TeX_( "/yy0{only/_if/_rw}" );@]@=} + | SPECIAL {@>@[TeX_( "/yy0{special}" );@]@=} + | {@>@[TeX_( "/yy0{}" );@]@=} + ; + +@g + +@ {\it The \prodstyle{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 \prodstyle{GROUP} is supposed to mean.} A careful +analysis of the productions below reveals some +pitfalls in the parser/lexer interaction setup that uses the state switching +macros (or functions in the case of the original parser). The switch +to the \.{EXPRESSION} state at the end of the production for +\prodstyle{section} is invoked before \prodstyle{opt\_comma} which can +be empty. This means that the next (lookahead) token (which could be a +\prodstyle{NAME} in a different context) might be read before the +lexer is in the appropriate state. In practice, the names of the sections +and other \prodstyle{NAME}s are usually pretty straightforward so this +parser idiosynchrasy is unlikely to lead to a genuine problem. Since +the goal was to keep the original grammar intact as much as possible, +it was decided to leave this production unchanged. +@<Grammar rules@>= +@G +section: + NAME {@>@[TeX_( "/ldlex@@expression" );@]@=} + opt_exp_with_type opt_at opt_align opt_align_with_input +@t}\vb{\breakline}{@> + opt_subalign {@>@[TeX_( "/ldlex@@popstate/ldlex@@script" );@]@=} + sect_constraint + '{' {} + statement_list_opt + '}' {@>@[TeX_( "/ldlex@@popstate/ldlex@@expression" );@]@=} + memspec_opt memspec_at_opt phdr_opt fill_opt + {@>@[TeX_( "/ldlex@@popstate" );@]@=} + opt_comma {@>@<Record a named section@>@=} + | OVERLAY {@>@[TeX_( "/ldlex@@expression" );@]@=} + opt_exp_without_type opt_nocrossrefs opt_at opt_subalign + {@>@[TeX_( "/ldlex@@popstate/ldlex@@script" );@]@=} + '{' {} + overlay_section '}' {@>@[TeX_( "/ldlex@@popstate/ldlex@@expression" );@]@=} + memspec_opt memspec_at_opt phdr_opt fill_opt + {@>@[TeX_( "/ldlex@@popstate" );@]@=} + opt_comma {@>@<Record an overlay section@>@=} + | GROUP {@>@[TeX_( "/ldlex@@expression" );@]@=} + opt_exp_with_type {@>@[TeX_( "/ldlex@@popstate" );@]@=} + '{' sec_or_group_p1 '}' + | INCLUDE filename {@>@<Peek at a file@>@=} + sec_or_group_p1 END + {@>@<Close the file@>@=} + ; +@g + +@ @<Record a named section@>= + @[TeXb( "/yy0{/nx/ldnamedsection{/the/yy(1)}{/the/yy(3)}{/the/yy(4)}" );@]@; + @[TeXf( " {{/the/yy(5)}{/the/yy(6)}{/the/yy(7)}}" );@]@;/* alignment */ + @[TeXf( " {/the/yy(9)}{/the/yy(12)}" );@]@; + @[TeXfo( " {{/the/yy(15)}{/the/yy(16)}{/the/yy(17)}{/the/yy(18)}}}" );@]@; /*memory specifiers */ + +@ @<Record an overlay section@>= + +@ @<Grammar rules@>= +@G +type: + NOLOAD {@>@[TeX_( "/yy0{noload}" );@]@=} + | DSECT {@>@[TeX_( "/yy0{dsect}" );@]@=} + | COPY {@>@[TeX_( "/yy0{copy}" );@]@=} + | INFO {@>@[TeX_( "/yy0{info}" );@]@=} + | OVERLAY {@>@[TeX_( "/yy0{overlay}" );@]@=} + ; + +atype: + '(' type ')' {@>@[TeX_( "/yy0{/noexpand/ldtype{/the/yy(2)}}" );@]@=} + | '(' ')' {@>@[TeX_( "/yy0{/noexpand/ldtype{}}" );@]@=} + | {@>@[TeX_( "/yy0{}" );@]@=} + ; +@g + +@ {\it The \prodstyle{BIND} cases are to support the \gcc\ |svr3.ifile| +script. They aren't intended to implement full support for the +\prodstyle{BIND} keyword. I'm not even sure what \prodstyle{BIND} +is supposed to mean.} +@<Grammar rules@>= +@G +opt_exp_with_type: + exp atype ':' {@>@[TeX_( "/yy0{{}{/the/yy(1)}{}{}{/the/yy(2)}}" );@]@=} + | atype ':' {@>@[TeX_( "/yy0{{}{}{}{}{/the/yy(1)}}" );@]@=} + | BIND '(' exp ')' atype ':' {@>@[TeX_( "/yy0{{bind}{/the/yy(3)}{}{}{/the/yy(5)}}" );@]@=} + | BIND '(' exp ')' BLOCK '(' exp ')' atype ':' + {@>@[TeX_( "/yy0{{bind}{/the/yy(3)}{block}{/the/yy(7)}{/the/yy(9)}}" );@]@=} + ; + +opt_exp_without_type: + exp ':' {} + | ':' {} + ; + +opt_nocrossrefs: + {} + | NOCROSSREFS {} + ; + +memspec_opt: + '>' NAME {@>@[TeX_( "/yy0{/the/yy(2)}" );@]@=} + | {@>@[TeX_( "/yy0{}" );@]@=} + ; + +phdr_opt: + {@>@[TeX_( "/yy0{}" );@]@=} + | phdr_opt ':' NAME {@>@<Add another pheader@>@=} + ; + +overlay_section: + + | overlay_section + NAME {@>@[TeX_( "/ldlex@@script" );@]@=} + '{' statement_list_opt '}' {@>@[TeX_( "/ldlex@@popstate/ldlex@@expression" );@]@=} + phdr_opt fill_opt {@>@[TeX_( "/ldlex@@popstate" );@]@=} + opt_comma + ; +@g + +@ @<Add another pheader@>= + @[TeXb( "/yytoksempty{/yy(1)}{/yy0{{/the/yy(3)}}}" );@]@; + @[TeXao( "{/yy0{/the/yy(1)/noexpand/ldor{/the/yy(3)}}}" );@]@; + +@ @<Grammar rules@>= +@G +phdrs: + PHDRS '{' phdr_list '}' + ; + +phdr_list: + + | phdr_list phdr + ; + +phdr: + NAME {@>@[TeX_( "/ldlex@@expression" );@]@=} + phdr_type phdr_qualifiers {@>@[TeX_( "/ldlex@@popstate" );@]@=} + ';' {} + ; + +phdr_type: + exp {} + ; + +phdr_qualifiers: + {} + | NAME phdr_val phdr_qualifiers {} + | AT '(' exp ')' phdr_qualifiers {} + ; + +phdr_val: + {} + | '(' exp ')' {} + ; +@g + +@*1 Other types of script files. At present time other script types +are ignored, although some of the rules are used in linker scripts +that are processed by the parser. +@<Dynamic list file rules@>= +@G +dynamic_list_file: + {@>@[TeX_( "/ldlex@@version@@file" );@]@=} + dynamic_list_nodes {@>@[TeX_( "/ldlex@@popstate" );@]@=} + ; + +dynamic_list_nodes: + dynamic_list_node + | dynamic_list_nodes dynamic_list_node + ; + +dynamic_list_node: + '{' dynamic_list_tag '}' ';' + ; + +dynamic_list_tag: + vers_defns ';' {} + ; +@g + +@ {\it This syntax is used within an external version script file.} +@<Version file rules@>= +@G +version_script_file: + {@>@[TeX_( "/ldlex@@version@@file" );@]@=} + vers_nodes {@>@[TeX_( "/ldlex@@popstate" );@]@=} + ; +@g + +@ {\it This is used within a normal linker script file.} +@<Grammar rules@>= +@G +version: + {@>@[TeX_( "/ldlex@@version@@script" );@]@=} + VERSIONK '{' vers_nodes '}' {@>@[TeX_( "/ldlex@@popstate" );@]@=} + ; + +vers_nodes: + vers_node + | vers_nodes vers_node + ; + +vers_node: + '{' vers_tag '}' ';' {} + | VERS_TAG '{' vers_tag '}' ';' {} + | VERS_TAG '{' vers_tag '}' verdep ';' {} + ; + +verdep: + VERS_TAG {} + | verdep VERS_TAG {} + ; + +vers_tag: + {} + | vers_defns ';' {} + | GLOBAL ':' vers_defns ';' {} + | LOCAL ':' vers_defns ';' {} + | GLOBAL ':' vers_defns ';' LOCAL ':' vers_defns ';' + {} + ; + +vers_defns: + VERS_IDENTIFIER {} + | NAME {} + | vers_defns ';' VERS_IDENTIFIER {} + | vers_defns ';' NAME {} + | vers_defns ';' EXTERN NAME '{' {} + vers_defns opt_semicolon '}' {} + | EXTERN NAME '{' {} + vers_defns opt_semicolon '}' {} + | GLOBAL {} + | vers_defns ';' GLOBAL {} + | LOCAL {} + | vers_defns ';' LOCAL {} + | EXTERN {} + | vers_defns ';' EXTERN {} + ; +@t}\vb{\inline\flatten}{@> +opt_semicolon: + + | ';' + ; +@g diff --git a/support/splint/examples/ld/ldgramo.w b/support/splint/examples/ld/ldgramo.w new file mode 100644 index 0000000000..3069bb71eb --- /dev/null +++ b/support/splint/examples/ld/ldgramo.w @@ -0,0 +1,1645 @@ +@q Copyright 2015 Alexander Shibakov@> +@q Copyright 2002-2015 Free Software Foundation, Inc.@> +@q This file is part of SPLinT@> + +@q SPLinT is free software: you can redistribute it and/or modify@> +@q it under the terms of the GNU General Public License as published by@> +@q the Free Software Foundation, either version 3 of the License, or@> +@q (at your option) any later version.@> + +@q SPLinT is distributed in the hope that it will be useful,@> +@q but WITHOUT ANY WARRANTY; without even the implied warranty of@> +@q MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the@> +@q GNU General Public License for more details.@> + +@q You should have received a copy of the GNU General Public License@> +@q along with SPLinT. If not, see <http://www.gnu.org/licenses/>.@> + +@*1 The original parser. {\it Here we present the full grammar of \ld, including some actions. +The grammar is split into sections but otherwise is reproduced exactly. +In addition to improving readability, such splitting allows \CWEB\ to process the code in +manageable increments. An observant reader will notice the difficulty +\CWEAVE\ is having with typesetting the structure tags that have the same +name as the structure variables of the appropriate type. This is a well-known +defect in \CWEAVE's design (see the requisite documentation) left +uncorrected to discourage the poor programming practice.} + +@s bfd_boolean int +@s bfd_vma int +@s fill_type int +@s lang_nocrossref int +@s lang_output_section_phdr_list int +@s bfd_elf_version_deps int +@s bfd_elf_version_expr int +@s bfd_elf_version_tree int +@s etree_union int +@s wildcard_spec int +@s section_type int +@s lang_memory_region_type int + +@<The original \ld\ parser@>= +@G +%{ + @>@<\Cee\ setup for \ld\ grammar@>@; +%} +%union { +@O + bfd_vma integer; + struct big_int + { + bfd_vma integer; + char *str; + } bigint; + fill_type *fill; + char *name; + const char *cname; + struct wildcard_spec wildcard; + struct wildcard_list *wildcard_list; + struct name_list *name_list; + struct flag_info_list *flag_info_list; + struct flag_info *flag_info; + int token; + union etree_union *etree; + struct phdr_info + { + bfd_boolean filehdr; + bfd_boolean phdrs; + union etree_union *at; + union etree_union *flags; + } phdr; + struct lang_nocrossref *nocrossref; + struct lang_output_section_phdr_list *section_phdr; + struct bfd_elf_version_deps *deflist; + struct bfd_elf_version_expr *versyms; + struct bfd_elf_version_tree *versnode; +@o + } + @>@<Token definitions for the \ld\ grammar@>@; +%% + @>@<Original \ld\ grammar rules@>@; +%% +@g + +@ {\it The \Cee\ code is left mostly intact (with the exception of a few +comments) although it does not show up in the final output. The parts +that {\it are\/} typeset represent the semantics that is reproduced in +the typesetting parser. This includes all the state switching, as well +as some other actions that affect the parser-lexer interaction (such +as opening a new input buffer). The only exception to this rule is the +code for the \MRI\ script section of the grammar. It is reproduced +mostly as an example of a pretty printed grammar, since otherwise, +\MRI\ scripts are completely ignored by the typeseting parser.} +\def\initbootstrap{\restorecslist{parser-prototypes}\yyunion}% + +@<\Cee\ setup for \ld\ grammar@>= +#define DONTDECLARE_MALLOC + +#include "sysdep.h" +#include "bfd.h" +#include "bfdlink.h" +#include "ld.h" +#include "ldexp.h" +#include "ldver.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" +#include "ldmisc.h" +#include "ldmain.h" +#include "mri.h" +#include "ldctor.h" +#include "ldlex.h" + +#ifndef YYDEBUG +#define YYDEBUG 1 +#endif + +static enum section_type sectype; +static lang_memory_region_type *region; + +bfd_boolean ldgram_had_keep = FALSE; +char *ldgram_vers_current_lang = NULL; + +#define ERROR_NAME_MAX 20 +static char *error_names[ERROR_NAME_MAX]; +static int error_index; +#define PUSH_ERROR(x) if (error_index < ERROR_NAME_MAX) error_names[error_index] = x; error_index++; +#define POP_ERROR() @[error_index--;@] + +@ {\it The token definitions and the corresponding \prodstyle{\%union} +styles are intermixed, which makes sense in the traditional style of a +\bison\ script. When \CWEB\ is used, however, it helps to introduce the +code in small, manageable sections and take advantage of \CWEB's crossreferencing +facilities to provide cues on the relationships between various parts +of the code.} +@<Token definitions for the \ld\ grammar@>= +@G +%type <etree> exp opt_exp_with_type mustbe_exp opt_at phdr_type phdr_val +%type <etree> opt_exp_without_type opt_subalign opt_align +%type <fill> fill_opt fill_exp +%type <name_list> exclude_name_list +%type <wildcard_list> file_NAME_list +%type <flag_info_list> sect_flag_list +%type <flag_info> sect_flags +%type <name> memspec_opt casesymlist +%type <name> memspec_at_opt +%type <cname> wildcard_name +%type <wildcard> wildcard_spec +%token <bigint> INT +%token <name> NAME LNAME +%type <integer> length +%type <phdr> phdr_qualifiers +%type <nocrossref> nocrossref_list +%type <section_phdr> phdr_opt +%type <integer> opt_nocrossrefs + +%right <token> PLUSEQ MINUSEQ MULTEQ DIVEQ '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ +%right <token> '?' ':' +%left <token> OROR +%left <token> ANDAND +%left <token> '|' +%left <token> '^' +%left <token> '&' +%left <token> EQ NE +%left <token> '<' '>' LE GE +%left <token> LSHIFT RSHIFT + +%left <token> '+' '-' +%left <token> '*' '/' '%' + +%right UNARY +%token END +%left <token> '(' +%token <token> ALIGN_K BLOCK BIND QUAD SQUAD LONG SHORT BYTE +%token SECTIONS PHDRS INSERT_K AFTER BEFORE +%token DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END DATA_SEGMENT_END +%token SORT_BY_NAME SORT_BY_ALIGNMENT SORT_NONE +%token SORT_BY_INIT_PRIORITY +%token '{' '}' +%token SIZEOF_HEADERS OUTPUT_FORMAT FORCE_COMMON_ALLOCATION OUTPUT_ARCH +%token INHIBIT_COMMON_ALLOCATION +%token SEGMENT_START +%token INCLUDE +%token MEMORY +%token REGION_ALIAS +%token LD_FEATURE +%token NOLOAD DSECT COPY INFO OVERLAY +%token DEFINED TARGET_K SEARCH_DIR MAP ENTRY +%token <integer> NEXT +%token SIZEOF ALIGNOF ADDR LOADADDR MAX_K MIN_K +%token STARTUP HLL SYSLIB FLOAT NOFLOAT NOCROSSREFS +%token ORIGIN FILL +%token LENGTH CREATE_OBJECT_SYMBOLS INPUT GROUP OUTPUT CONSTRUCTORS +%token ALIGNMOD AT SUBALIGN HIDDEN PROVIDE PROVIDE_HIDDEN AS_NEEDED +%type <token> assign_op atype attributes_opt sect_constraint opt_align_with_input +%type <name> filename +%token CHIP LIST SECT ABSOLUTE LOAD NEWLINE ENDWORD ORDER NAMEWORD ASSERT_K +%token LOG2CEIL FORMAT PUBLIC DEFSYMEND BASE ALIAS TRUNCATE REL +%token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM CASE EXTERN START +%token <name> VERS_TAG VERS_IDENTIFIER +%token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT +%token KEEP ONLY_IF_RO ONLY_IF_RW SPECIAL INPUT_SECTION_FLAGS ALIGN_WITH_INPUT +%token EXCLUDE_FILE +%token CONSTANT +%type <versyms> vers_defns +%type <versnode> vers_tag +%type <deflist> verdep +%token INPUT_DYNAMIC_LIST +@g + +@ {\it The original \Cee\ code has been preserved and presented along with +the grammar rules in the next two sections (the \Cee\ code has not +been deleted in the subsequent sections either, it is just not +typeset).} +\saveparseoutputfalse +@<Original \ld\ grammar rules@>= +@G +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: + { @> ldlex_defsym(); @=} + NAME '=' exp + { +@O + ldlex_popstate(); +@o + lang_add_assignment (exp_defsym ($2, $4)); + } + ; + +@g + +@ Syntax within an \MRI\ script file. +@<Original \ld\ grammar rules@>= +@G +mri_script_file: + { +@O + @[ldlex_mri_script ();@] +@o + PUSH_ERROR (_("MRI style script")); + } + mri_script_lines + { +@O + ldlex_popstate (); +@o + mri_draw_tree (); + POP_ERROR (); + } + ; + +mri_script_lines: + mri_script_lines mri_script_command NEWLINE + | + ; + +@g + +@ @<Original \ld\ grammar rules@>= +@G +mri_script_command: + CHIP exp + | CHIP exp ',' exp + | NAME { @> @<Flag an unrecognized keyword@> @=} + | LIST { @> config.map_filename = "-"; @=} + | ORDER ordernamelist + | ENDWORD + | PUBLIC NAME '=' exp + { @> mri_public($2, $4); @=} + | PUBLIC NAME ',' exp + { @> mri_public($2, $4); @=} + | PUBLIC NAME exp + { @> mri_public($2, $3); @=} + | FORMAT NAME + { @> mri_format($2); @=} + | SECT NAME ',' exp + { @> mri_output_section($2, $4); @=} + | SECT NAME exp + { @> mri_output_section($2, $3); @=} + | SECT NAME '=' exp + { @> mri_output_section($2, $4); @=} + | ALIGN_K NAME '=' exp + { @> mri_align($2,$4); @=} + | ALIGN_K NAME ',' exp + { @> mri_align($2,$4); @=} + | ALIGNMOD NAME '=' exp + { @> mri_alignmod($2,$4); @=} + | ALIGNMOD NAME ',' exp + { @> mri_alignmod($2,$4); @=} + | ABSOLUTE mri_abs_name_list + | LOAD mri_load_name_list + | NAMEWORD NAME + { @> mri_name($2); @=} + | ALIAS NAME ',' NAME + { @> mri_alias($2,$4,0); @=} + | ALIAS NAME ',' INT + { @> mri_alias ($2, 0, (int) $4.integer); @=} + | BASE exp + { @> mri_base($2); @=} + | TRUNCATE INT + { @> mri_truncate ((unsigned int) $2.integer); @=} + | CASE casesymlist + | EXTERN extern_name_list + | INCLUDE filename + { @> ldlex_script (); ldfile_open_command_file($2); @=} + mri_script_lines END + { @> ldlex_popstate (); @=} + | START NAME + { @> lang_add_entry ($2, FALSE); @=} + | + ; + +ordernamelist: + ordernamelist ',' NAME { @> mri_order($3); @=} + | ordernamelist NAME { @> mri_order($2); @=} + | + ; + +mri_load_name_list: + NAME { @> mri_load($1); @=} + | mri_load_name_list ',' NAME { @> mri_load($3); @=} + ; + +mri_abs_name_list: + NAME { @> mri_only_load($1); @=} + | mri_abs_name_list ',' NAME { @> mri_only_load($3); @=} + ; + +casesymlist: + { @> $$ = NULL; @=} + | NAME + | casesymlist ',' NAME + ; + +@g + +@ {\it Here is one way to deal with code that is too long to fit in an action.} +@<Flag an unrecognized keyword@>= + einfo(_("%P%F: unrecognised keyword in MRI style script '%s'\n"),$1); + +@ Parsed as expressions so that commas separate entries. +@<Original \ld\ grammar rules@>= +@G +extern_name_list: + {@> @[ldlex_expression ();@]@=} + extern_name_list_body + {@> @[ldlex_popstate ();@]@=} + +extern_name_list_body: + NAME + { ldlang_add_undef ($1, FALSE); } + | extern_name_list_body NAME + { ldlang_add_undef ($2, FALSE); } + | extern_name_list_body ',' NAME + { ldlang_add_undef ($3, FALSE); } + ; + +script_file: + {@> @[ldlex_both();@]@=} + ifile_list + {@> @[ldlex_popstate();@]@=} + ; + +ifile_list: + ifile_list ifile_p1 + | + ; + +@g + +@ {\it All the commands that can appear in a standard linker script.}% +@<Original \ld\ grammar rules@>= +@G +ifile_p1: + memory + | sections + | phdrs + | startup + | high_level_library + | low_level_library + | floating_point_support + | statement_anywhere + | version + | ';' + | TARGET_K '(' NAME ')' + { lang_add_target($3); } + | SEARCH_DIR '(' filename ')' + { ldfile_add_library_path ($3, FALSE); } + | OUTPUT '(' filename ')' + { lang_add_output($3, 1); } + | OUTPUT_FORMAT '(' NAME ')' + { lang_add_output_format ($3, (char *) NULL, + (char *) NULL, 1); } + | OUTPUT_FORMAT '(' NAME ',' NAME ',' NAME ')' + { lang_add_output_format ($3, $5, $7, 1); } + | OUTPUT_ARCH '(' NAME ')' + { ldfile_set_output_arch ($3, bfd_arch_unknown); } + | FORCE_COMMON_ALLOCATION + { command_line.force_common_definition = TRUE ; } + | INHIBIT_COMMON_ALLOCATION + { command_line.inhibit_common_definition = TRUE ; } + | INPUT '(' input_list ')' + | GROUP + { lang_enter_group (); } + '(' input_list ')' + { lang_leave_group (); } + | MAP '(' filename ')' + { lang_add_map($3); } + | INCLUDE filename + { +@O + ldlex_script (); ldfile_open_command_file($2); +@o + } + ifile_list END + {@> @[ldlex_popstate ();@]@=} + | NOCROSSREFS '(' nocrossref_list ')' + { + lang_add_nocrossref ($3); + } + | EXTERN '(' extern_name_list ')' + | INSERT_K AFTER NAME + { lang_add_insert ($3, 0); } + | INSERT_K BEFORE NAME + { lang_add_insert ($3, 1); } + | REGION_ALIAS '(' NAME ',' NAME ')' + { lang_memory_region_alias ($3, $5); } + | LD_FEATURE '(' NAME ')' + { lang_ld_feature ($3); } + ; + +@g + +@ @<Original \ld\ grammar rules@>= +@G +input_list: + NAME + { lang_add_input_file($1,lang_input_file_is_search_file_enum, + (char *)NULL); } + | input_list ',' NAME + { lang_add_input_file($3,lang_input_file_is_search_file_enum, + (char *)NULL); } + | input_list NAME + { lang_add_input_file($2,lang_input_file_is_search_file_enum, + (char *)NULL); } + | LNAME + { lang_add_input_file($1,lang_input_file_is_l_enum, + (char *)NULL); } + | input_list ',' LNAME + { lang_add_input_file($3,lang_input_file_is_l_enum, + (char *)NULL); } + | input_list LNAME + { lang_add_input_file($2,lang_input_file_is_l_enum, + (char *)NULL); } + | AS_NEEDED '(' + { $<integer>$ = input_flags.add_DT_NEEDED_for_regular; + input_flags.add_DT_NEEDED_for_regular = TRUE; } + input_list ')' + { input_flags.add_DT_NEEDED_for_regular = $<integer>3; } + | input_list ',' AS_NEEDED '(' + { $<integer>$ = input_flags.add_DT_NEEDED_for_regular; + input_flags.add_DT_NEEDED_for_regular = TRUE; } + input_list ')' + { input_flags.add_DT_NEEDED_for_regular = $<integer>5; } + | input_list AS_NEEDED '(' + { $<integer>$ = input_flags.add_DT_NEEDED_for_regular; + input_flags.add_DT_NEEDED_for_regular = TRUE; } + input_list ')' + { input_flags.add_DT_NEEDED_for_regular = $<integer>4; } + ; + +sections: + SECTIONS '{' sec_or_group_p1 '}' + ; + +sec_or_group_p1: + sec_or_group_p1 section + | sec_or_group_p1 statement_anywhere + | + ; + +statement_anywhere: + ENTRY '(' NAME ')' + { lang_add_entry ($3, FALSE); } + | assignment end + | ASSERT_K {@>@[ldlex_expression ();@>@=} '(' exp ',' NAME ')' + { +@O + ldlex_popstate (); +@o + lang_add_assignment (exp_assert ($4, $6)); + } + ; + +@g + +@ \tracebadcharstrue +The \prodstyle{'*'} and \prodstyle{'?'} cases are there because the lexer returns them as +separate tokens rather than as \prodstyle{NAME}. +\tracebadcharsfalse +@<Original \ld\ grammar rules@>= +@G +wildcard_name: + NAME + { + $$ = $1; + } + | '*' + { + $$ = "*"; + } + | '?' + { + $$ = "?"; + } + ; + +@g + +@ @<Original \ld\ grammar rules@>= +@G +wildcard_spec: + wildcard_name + { + $$.name = $1; + $$.sorted = none; + $$.exclude_name_list = NULL; + $$.section_flag_list = NULL; + } + | EXCLUDE_FILE '(' exclude_name_list ')' wildcard_name + { + $$.name = $5; + $$.sorted = none; + $$.exclude_name_list = $3; + $$.section_flag_list = NULL; + } + | SORT_BY_NAME '(' wildcard_name ')' + { + $$.name = $3; + $$.sorted = by_name; + $$.exclude_name_list = NULL; + $$.section_flag_list = NULL; + } + | SORT_BY_ALIGNMENT '(' wildcard_name ')' + { + $$.name = $3; + $$.sorted = by_alignment; + $$.exclude_name_list = NULL; + $$.section_flag_list = NULL; + } + | SORT_NONE '(' wildcard_name ')' + { + $$.name = $3; + $$.sorted = by_none; + $$.exclude_name_list = NULL; + $$.section_flag_list = NULL; + } + | SORT_BY_NAME '(' SORT_BY_ALIGNMENT '(' wildcard_name ')' ')' + { + $$.name = $5; + $$.sorted = by_name_alignment; + $$.exclude_name_list = NULL; + $$.section_flag_list = NULL; + } + | SORT_BY_NAME '(' SORT_BY_NAME '(' wildcard_name ')' ')' + { + $$.name = $5; + $$.sorted = by_name; + $$.exclude_name_list = NULL; + $$.section_flag_list = NULL; + } + | SORT_BY_ALIGNMENT '(' SORT_BY_NAME '(' wildcard_name ')' ')' + { + $$.name = $5; + $$.sorted = by_alignment_name; + $$.exclude_name_list = NULL; + $$.section_flag_list = NULL; + } + | SORT_BY_ALIGNMENT '(' SORT_BY_ALIGNMENT '(' wildcard_name ')' ')' + { + $$.name = $5; + $$.sorted = by_alignment; + $$.exclude_name_list = NULL; + $$.section_flag_list = NULL; + } + | SORT_BY_NAME '(' EXCLUDE_FILE '(' exclude_name_list ')' wildcard_name ')' + { + $$.name = $7; + $$.sorted = by_name; + $$.exclude_name_list = $5; + $$.section_flag_list = NULL; + } + | SORT_BY_INIT_PRIORITY '(' wildcard_name ')' + { + $$.name = $3; + $$.sorted = by_init_priority; + $$.exclude_name_list = NULL; + $$.section_flag_list = NULL; + } + ; + +sect_flag_list: NAME + { + struct flag_info_list *n; + n = ((struct flag_info_list *) xmalloc (sizeof *n)); + if ($1[0] == '!') + { + n->with = without_flags; + n->name = &$1[1]; + } + else + { + n->with = with_flags; + n->name = $1; + } + n->valid = FALSE; + n->next = NULL; + $$ = n; + } + | sect_flag_list '&' NAME + { + struct flag_info_list *n; + n = ((struct flag_info_list *) xmalloc (sizeof *n)); + if ($3[0] == '!') + { + n->with = without_flags; + n->name = &$3[1]; + } + else + { + n->with = with_flags; + n->name = $3; + } + n->valid = FALSE; + n->next = $1; + $$ = n; + } + ; + +sect_flags: + INPUT_SECTION_FLAGS '(' sect_flag_list ')' + { + struct flag_info *n; + n = ((struct flag_info *) xmalloc (sizeof *n)); + n->flag_list = $3; + n->flags_initialized = FALSE; + n->not_with_flags = 0; + n->only_with_flags = 0; + $$ = n; + } + ; + +exclude_name_list: + exclude_name_list wildcard_name + { + struct name_list *tmp; + tmp = (struct name_list *) xmalloc (sizeof *tmp); + tmp->name = $2; + tmp->next = $1; + $$ = tmp; + } + | + wildcard_name + { + struct name_list *tmp; + tmp = (struct name_list *) xmalloc (sizeof *tmp); + tmp->name = $1; + tmp->next = NULL; + $$ = tmp; + } + ; + +file_NAME_list: + file_NAME_list opt_comma wildcard_spec + { + struct wildcard_list *tmp; + tmp = (struct wildcard_list *) xmalloc (sizeof *tmp); + tmp->next = $1; + tmp->spec = $3; + $$ = tmp; + } + | + wildcard_spec + { + struct wildcard_list *tmp; + tmp = (struct wildcard_list *) xmalloc (sizeof *tmp); + tmp->next = NULL; + tmp->spec = $1; + $$ = tmp; + } + ; + +input_section_spec_no_keep: + NAME + { + struct wildcard_spec tmp; + tmp.name = $1; + tmp.exclude_name_list = NULL; + tmp.sorted = none; + tmp.section_flag_list = NULL; + lang_add_wild (&tmp, NULL, ldgram_had_keep); + } + | sect_flags NAME + { + struct wildcard_spec tmp; + tmp.name = $2; + tmp.exclude_name_list = NULL; + tmp.sorted = none; + tmp.section_flag_list = $1; + lang_add_wild (&tmp, NULL, ldgram_had_keep); + } + | '[' file_NAME_list ']' + { + lang_add_wild (NULL, $2, ldgram_had_keep); + } + | sect_flags '[' file_NAME_list ']' + { + struct wildcard_spec tmp; + tmp.name = NULL; + tmp.exclude_name_list = NULL; + tmp.sorted = none; + tmp.section_flag_list = $1; + lang_add_wild (&tmp, $3, ldgram_had_keep); + } + | wildcard_spec '(' file_NAME_list ')' + { + lang_add_wild (&$1, $3, ldgram_had_keep); + } + | sect_flags wildcard_spec '(' file_NAME_list ')' + { + $2.section_flag_list = $1; + lang_add_wild (&$2, $4, ldgram_had_keep); + } + ; +@g + +@ @<Original \ld\ grammar rules@>= +@G +input_section_spec: + input_section_spec_no_keep + | KEEP '(' + { ldgram_had_keep = TRUE; } + input_section_spec_no_keep ')' + { ldgram_had_keep = FALSE; } + ; + +statement: + assignment end + | CREATE_OBJECT_SYMBOLS + { + lang_add_attribute(lang_object_symbols_statement_enum); + } + | ';' + | CONSTRUCTORS + { + + lang_add_attribute(lang_constructors_statement_enum); + } + | SORT_BY_NAME '(' CONSTRUCTORS ')' + { + constructors_sorted = TRUE; + lang_add_attribute (lang_constructors_statement_enum); + } + | input_section_spec + | length '(' mustbe_exp ')' + { + lang_add_data ((int) $1, $3); + } + + | FILL '(' fill_exp ')' + { + lang_add_fill ($3); + } + | ASSERT_K {@>@[ldlex_expression ();@]@=} '(' exp ',' NAME ')' end + { +@O + ldlex_popstate (); +@o + lang_add_assignment (exp_assert ($4, $6)); + } + | INCLUDE filename + {@> @[ldlex_script (); ldfile_open_command_file($2);@]@=} + statement_list_opt END + {@> @[ldlex_popstate ();@]@=} + ; +@t}\vb{\flatten\inline\squashtermstrue}{@> +statement_list: + statement_list statement + | statement + ; + +statement_list_opt: + + | statement_list + ; + +length: + QUAD + { $$ = $1; } + | SQUAD + { $$ = $1; } + | LONG + { $$ = $1; } + | SHORT + { $$ = $1; } + | BYTE + { $$ = $1; } + ; + +fill_exp: + mustbe_exp + { + $$ = exp_get_fill ($1, 0, "fill value"); + } + ; + +fill_opt: + '=' fill_exp + { $$ = $2; } + | { $$ = (fill_type *) 0; } + ; + +assign_op: + PLUSEQ + { $$ = '+'; } + | MINUSEQ + { $$ = '-'; } + | MULTEQ + { $$ = '*'; } + | DIVEQ + { $$ = '/'; } + | LSHIFTEQ + { $$ = LSHIFT; } + | RSHIFTEQ + { $$ = RSHIFT; } + | ANDEQ + { $$ = '&'; } + | OREQ + { $$ = '|'; } + + ; +end: ';' | ',' + ; +@t}\vb{\resetf}{@> + +assignment: + NAME '=' mustbe_exp + { + lang_add_assignment (exp_assign ($1, $3, FALSE)); + } + | NAME assign_op mustbe_exp + { + lang_add_assignment (exp_assign ($1, + exp_binop ($2, + exp_nameop (NAME, + $1), + $3), FALSE)); + } + | HIDDEN '(' NAME '=' mustbe_exp ')' + { + lang_add_assignment (exp_assign ($3, $5, TRUE)); + } + | PROVIDE '(' NAME '=' mustbe_exp ')' + { + lang_add_assignment (exp_provide ($3, $5, FALSE)); + } + | PROVIDE_HIDDEN '(' NAME '=' mustbe_exp ')' + { + lang_add_assignment (exp_provide ($3, $5, TRUE)); + } + ; + +@t}\vb{\inline\flatten}{@> +opt_comma: + ',' | ; +@t}\vb{\resetf}{@> +memory: + MEMORY '{' memory_spec_list_opt '}' + ; + +memory_spec_list_opt: memory_spec_list | ; + +memory_spec_list: + memory_spec_list opt_comma memory_spec + | memory_spec + ; + + +memory_spec: NAME + { region = lang_memory_region_lookup ($1, TRUE); } + attributes_opt ':' + origin_spec opt_comma length_spec + {} + | INCLUDE filename + {@> @[ldlex_script (); ldfile_open_command_file($2);@]@=} + memory_spec_list_opt END + {@> @[ldlex_popstate ();@]@=} + ; +@g + +@ @<Original \ld\ grammar rules@>= +@G +origin_spec: + ORIGIN '=' mustbe_exp + { + region->origin = exp_get_vma ($3, 0, "origin"); + region->current = region->origin; + } + ; + +length_spec: + LENGTH '=' mustbe_exp + { + region->length = exp_get_vma ($3, -1, "length"); + } + ; + +attributes_opt: + + { /* dummy action to avoid bison 1.25 error message */ } + | '(' attributes_list ')' + ; + +attributes_list: + attributes_string + | attributes_list attributes_string + ; + +attributes_string: + NAME + { lang_set_flags (region, $1, 0); } + | '!' NAME + { lang_set_flags (region, $2, 1); } + ; + +startup: + STARTUP '(' filename ')' + { lang_startup($3); } + ; + +high_level_library: + HLL '(' high_level_library_NAME_list ')' + | HLL '(' ')' + { ldemul_hll((char *)NULL); } + ; + +high_level_library_NAME_list: + high_level_library_NAME_list opt_comma filename + { ldemul_hll($3); } + | filename + { ldemul_hll($1); } + + ; + +low_level_library: + SYSLIB '(' low_level_library_NAME_list ')' + ; low_level_library_NAME_list: + low_level_library_NAME_list opt_comma filename + { ldemul_syslib($3); } + | + ; + +floating_point_support: + FLOAT + { lang_float(TRUE); } + | NOFLOAT + { lang_float(FALSE); } + ; + +nocrossref_list: + + { + $$ = NULL; + } + | NAME nocrossref_list + { + struct lang_nocrossref *n; + + n = (struct lang_nocrossref *) xmalloc (sizeof *n); + n->name = $1; + n->next = $2; + $$ = n; + } + | NAME ',' nocrossref_list + { + struct lang_nocrossref *n; + + n = (struct lang_nocrossref *) xmalloc (sizeof *n); + n->name = $1; + n->next = $3; + $$ = n; + } + ; + +mustbe_exp: {@> @[ldlex_expression ();@]@=} + exp + {@> @[ldlex_popstate ();@]@= $$=$2;} + ; + +@g + +@ {\it Rich expression syntax reproducing the one in \Cee.} +@<Original \ld\ grammar rules@>= +@G +exp : + '-' exp %prec UNARY + { $$ = exp_unop ('-', $2); } + | '(' exp ')' + { $$ = $2; } + | NEXT '(' exp ')' %prec UNARY + { $$ = exp_unop ((int) $1,$3); } + | '!' exp %prec UNARY + { $$ = exp_unop ('!', $2); } + | '+' exp %prec UNARY + { $$ = $2; } + | '~' exp %prec UNARY + { $$ = exp_unop ('~', $2);} +@t}\vb{\flatten\inline}{@> + | exp '*' exp + { $$ = exp_binop ('*', $1, $3); } + | exp '/' exp + { $$ = exp_binop ('/', $1, $3); } + | exp '%' exp + { $$ = exp_binop ('%', $1, $3); } + | exp '+' exp + { $$ = exp_binop ('+', $1, $3); } + | exp '-' exp +@t}\vb{\resetf}{@> + { $$ = exp_binop ('-' , $1, $3); } +@t}\vb{\flatten\inline}{@> + | exp LSHIFT exp + { $$ = exp_binop (LSHIFT , $1, $3); } + | exp RSHIFT exp + { $$ = exp_binop (RSHIFT , $1, $3); } + | exp EQ exp + { $$ = exp_binop (EQ , $1, $3); } + | exp NE exp + { $$ = exp_binop (NE , $1, $3); } + | exp LE exp +@t}\vb{\resetf}{@> + { $$ = exp_binop (LE , $1, $3); } +@t}\vb{\flatten\inline}{@> + | exp GE exp + { $$ = exp_binop (GE , $1, $3); } + | exp '<' exp + { $$ = exp_binop ('<' , $1, $3); } + | exp '>' exp + { $$ = exp_binop ('>' , $1, $3); } + | exp '&' exp + { $$ = exp_binop ('&' , $1, $3); } + | exp '^' exp +@t}\vb{\resetf}{@> + { $$ = exp_binop ('^' , $1, $3); } +@t}\vb{\flatten\inline}{@> + | exp '|' exp + { $$ = exp_binop ('|' , $1, $3); } + | exp '?' exp ':' exp + { $$ = exp_trinop ('?' , $1, $3, $5); } + | exp ANDAND exp + { $$ = exp_binop (ANDAND , $1, $3); } + | exp OROR exp +@t}\vb{\resetf}{@> + { $$ = exp_binop (OROR , $1, $3); } +@t}\vb{\flatten\inline}{@> + | DEFINED '(' NAME ')' + { $$ = exp_nameop (DEFINED, $3); } + | INT + { $$ = exp_bigintop ($1.integer, $1.str); } + | SIZEOF_HEADERS +@t}\vb{\resetf}{@> + { $$ = exp_nameop (SIZEOF_HEADERS,0); } +@t}\vb{\flatten\inline}{@> + | ALIGNOF '(' NAME ')' + { $$ = exp_nameop (ALIGNOF,$3); } + | SIZEOF '(' NAME ')' +@t}\vb{\resetf}{@> + { $$ = exp_nameop (SIZEOF,$3); } +@t}\vb{\flatten\inline}{@> + | ADDR '(' NAME ')' + { $$ = exp_nameop (ADDR,$3); } + | LOADADDR '(' NAME ')' +@t}\vb{\resetf}{@> + { $$ = exp_nameop (LOADADDR,$3); } +@t}\vb{\flatten\inline}{@> + | CONSTANT '(' NAME ')' + { $$ = exp_nameop (CONSTANT,$3); } + | ABSOLUTE '(' exp ')' + { $$ = exp_unop (ABSOLUTE, $3); } + | ALIGN_K '(' exp ')' +@t}\vb{\resetf}{@> + { $$ = exp_unop (ALIGN_K,$3); } +@t}\vb{\flatten\inline}{@> + | ALIGN_K '(' exp ',' exp ')' + { $$ = exp_binop (ALIGN_K,$3,$5); } + | DATA_SEGMENT_ALIGN '(' exp ',' exp ')' +@t}\vb{\resetf}{@> + { $$ = exp_binop (DATA_SEGMENT_ALIGN, $3, $5); } + | DATA_SEGMENT_RELRO_END '(' exp ',' exp ')' + { $$ = exp_binop (DATA_SEGMENT_RELRO_END, $5, $3); } + | DATA_SEGMENT_END '(' exp ')' + { $$ = exp_unop (DATA_SEGMENT_END, $3); } + | SEGMENT_START '(' NAME ',' exp ')' + { $$ = exp_binop (SEGMENT_START, + $5, + exp_nameop (NAME, $3)); } + | BLOCK '(' exp ')' + { $$ = exp_unop (ALIGN_K,$3); } + | NAME + { $$ = exp_nameop (NAME,$1); } + | MAX_K '(' exp ',' exp ')' + { $$ = exp_binop (MAX_K, $3, $5 ); } + | MIN_K '(' exp ',' exp ')' + { $$ = exp_binop (MIN_K, $3, $5 ); } + | ASSERT_K '(' exp ',' NAME ')' + { $$ = exp_assert ($3, $5); } + | ORIGIN '(' NAME ')' + { $$ = exp_nameop (ORIGIN, $3); } + | LENGTH '(' NAME ')' + { $$ = exp_nameop (LENGTH, $3); } + | LOG2CEIL '(' exp ')' + { $$ = exp_unop (LOG2CEIL, $3); } + ; + +@g + +@ @<Original \ld\ grammar rules@>= +@G +memspec_at_opt: + AT '>' NAME { $$ = $3; } + | { $$ = 0; } + ; + +opt_at: + AT '(' exp ')' { $$ = $3; } + | { $$ = 0; } + ; + +opt_align: + ALIGN_K '(' exp ')' { $$ = $3; } + | { $$ = 0; } + ; + +opt_align_with_input: + ALIGN_WITH_INPUT { $$ = ALIGN_WITH_INPUT; } + | { $$ = 0; } + ; + +opt_subalign: + SUBALIGN '(' exp ')' { $$ = $3; } + | { $$ = 0; } + ; + +sect_constraint: + ONLY_IF_RO { $$ = ONLY_IF_RO; } + | ONLY_IF_RW { $$ = ONLY_IF_RW; } + | SPECIAL { $$ = SPECIAL; } + | { $$ = 0; } + ; + +@g + +@ The \prodstyle{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 \prodstyle{GROUP} is supposed +to mean. +@<Original \ld\ grammar rules@>= +@G +section: NAME {@> @[ldlex_expression();@]@=} + opt_exp_with_type + opt_at + opt_align +@t}\vb{\breakline}{@> + opt_align_with_input + opt_subalign {@> @[ldlex_popstate (); ldlex_script ();@]@=} + sect_constraint + '{' + { + lang_enter_output_section_statement($1, $3, + sectype, + $5, $7, $4, $9, $6); + } + statement_list_opt + '}' {@> @[ldlex_popstate (); ldlex_expression ();@]@=} + memspec_opt memspec_at_opt phdr_opt fill_opt + { +@O + ldlex_popstate (); +@o + lang_leave_output_section_statement ($18, $15, $17, $16); + } + opt_comma + {} + | OVERLAY + {@> @[ldlex_expression ();@]@=} + opt_exp_without_type opt_nocrossrefs +@t}\vb{\breakline}{@> + opt_at opt_subalign + {@> @[ldlex_popstate (); ldlex_script ();@]@=} + '{' + { + lang_enter_overlay ($3, $6); + } + overlay_section + '}' + {@> @[ldlex_popstate (); ldlex_expression ();@]@=} + memspec_opt memspec_at_opt phdr_opt fill_opt + { +@O + ldlex_popstate (); +@o + lang_leave_overlay ($5, (int) $4, + $16, $13, $15, $14); + } + opt_comma + | GROUP {@> @[ldlex_expression ();@]@=} + opt_exp_with_type + { +@O + ldlex_popstate (); +@o + lang_add_assignment (exp_assign (".", $3, FALSE)); + } + '{' sec_or_group_p1 '}' + | INCLUDE filename + {@> @[ldlex_script (); ldfile_open_command_file($2);@]@=} + sec_or_group_p1 END + {@> @[ldlex_popstate ();@]@=} + ; +@t}\vb{\flatten\inline}{@> +type: + NOLOAD { sectype = noload_section; } + | DSECT { sectype = noalloc_section; } + | COPY { sectype = noalloc_section; } + | INFO { sectype = noalloc_section; } + | OVERLAY { sectype = noalloc_section; } + ; + +atype: + '(' type ')' + | { sectype = normal_section; } + | '(' ')' { sectype = normal_section; } + ; + +@g + +@ The \prodstyle{BIND} cases are to support the \gcc\ |svr3.ifile| +script. They aren't intended to implement full +support for the \prodstyle{BIND} keyword. I'm not even sure +what \prodstyle{BIND} is supposed to mean. +@<Original \ld\ grammar rules@>= +@G + +opt_exp_with_type: + exp atype ':' { $$ = $1; } + | atype ':' { $$ = (etree_type *)NULL; } + | BIND '(' exp ')' atype ':' { $$ = $3; } + | BIND '(' exp ')' BLOCK '(' exp ')' atype ':' + { $$ = $3; } + ; + +opt_exp_without_type: + exp ':' { $$ = $1; } + | ':' { $$ = (etree_type *) NULL; } + ; + +opt_nocrossrefs: + + { $$ = 0; } + | NOCROSSREFS + { $$ = 1; } + ; + +memspec_opt: + '>' NAME + { $$ = $2; } + | { $$ = DEFAULT_MEMORY_REGION; } + ; + +phdr_opt: + + { + $$ = NULL; + } + | phdr_opt ':' NAME + { + struct lang_output_section_phdr_list *n; + + n = ((struct lang_output_section_phdr_list *) + xmalloc (sizeof *n)); + n->name = $3; + n->used = FALSE; + n->next = $1; + $$ = n; + } + ; + +overlay_section: + + | overlay_section + NAME + { +@O + ldlex_script (); +@o + lang_enter_overlay_section ($2); + } + '{' statement_list_opt '}' + {@> @[ldlex_popstate (); ldlex_expression ();@]@=} + phdr_opt fill_opt + { +@O + ldlex_popstate (); +@o + lang_leave_overlay_section ($9, $8); + } + opt_comma + ; +@g + +@ @<Original \ld\ grammar rules@>= +@G +phdrs: + PHDRS '{' phdr_list '}' + ; + +phdr_list: + + | phdr_list phdr + ; + +phdr: + NAME {@> @[ldlex_expression ();@]@=} + phdr_type phdr_qualifiers {@> @[ldlex_popstate ();@]@=} + ';' + { + lang_new_phdr ($1, $3, $4.filehdr, $4.phdrs, $4.at, + $4.flags); + } + ; + +phdr_type: + exp + { + $$ = $1; + + if ($1->type.node_class == etree_name + && $1->type.node_code == NAME) + { + const char *s; + unsigned int i; + static const char * const phdr_types[] = + { + "PT_NULL", "PT_LOAD", "PT_DYNAMIC", + "PT_INTERP", "PT_NOTE", "PT_SHLIB", + "PT_PHDR", "PT_TLS" + }; + + s = $1->name.name; + for (i = 0; + i < sizeof phdr_types / sizeof phdr_types[0]; + i++) + if (strcmp (s, phdr_types[i]) == 0) + { + $$ = exp_intop (i); + break; + } + if (i == sizeof phdr_types / sizeof phdr_types[0]) + { + if (strcmp (s, "PT_GNU_EH_FRAME") == 0) + $$ = exp_intop (0x6474e550); + else if (strcmp (s, "PT_GNU_STACK") == 0) + $$ = exp_intop (0x6474e551); + else + { + einfo (_("\ +%X%P:%S: unknown phdr type `%s' (try integer literal)\n"), + NULL, s); + $$ = exp_intop (0); + } + } + } + } + ; + +phdr_qualifiers: + + { + memset (&$$, 0, sizeof (struct phdr_info)); + } + | NAME phdr_val phdr_qualifiers + { + $$ = $3; + if (strcmp ($1, "FILEHDR") == 0 && $2 == NULL) + $$.filehdr = TRUE; + else if (strcmp ($1, "PHDRS") == 0 && $2 == NULL) + $$.phdrs = TRUE; + else if (strcmp ($1, "FLAGS") == 0 && $2 != NULL) + $$.flags = $2; + else + einfo (_("%X%P:%S: PHDRS syntax error at `%s'\n"), + NULL, $1); + } + | AT '(' exp ')' phdr_qualifiers + { + $$ = $5; + $$.at = $3; + } + ; + +phdr_val: + + { + $$ = NULL; + } + | '(' exp ')' + { + $$ = $2; + } + ; + +dynamic_list_file: + { +@O + ldlex_version_file (); +@o + PUSH_ERROR (_("dynamic list")); + } + dynamic_list_nodes + { +@O + ldlex_popstate (); +@o + POP_ERROR (); + } + ; + +dynamic_list_nodes: + dynamic_list_node + | dynamic_list_nodes dynamic_list_node + ; + +dynamic_list_node: + '{' dynamic_list_tag '}' ';' + ; + +dynamic_list_tag: + vers_defns ';' + { + lang_append_dynamic_list ($1); + } + ; + +@g + +@ This syntax is used within an external version script file. +@<Original \ld\ grammar rules@>= +@G + +version_script_file: + { +@O + ldlex_version_file (); +@o + PUSH_ERROR (_("VERSION script")); + } + vers_nodes + { +@O + ldlex_popstate (); +@o + POP_ERROR (); + } + ; +@g + +@ This is used within a normal linker script file. +@<Original \ld\ grammar rules@>= +@G +version: + { +@O + ldlex_version_script (); +@o + } + VERSIONK '{' vers_nodes '}' + { +@O + ldlex_popstate (); +@o + } + ; + +vers_nodes: + vers_node + | vers_nodes vers_node + ; + +vers_node: + '{' vers_tag '}' ';' + { + lang_register_vers_node (NULL, $2, NULL); + } + | VERS_TAG '{' vers_tag '}' ';' + { + lang_register_vers_node ($1, $3, NULL); + } + | VERS_TAG '{' vers_tag '}' verdep ';' + { + lang_register_vers_node ($1, $3, $5); + } + ; + +verdep: + VERS_TAG + { + $$ = lang_add_vers_depend (NULL, $1); + } + | verdep VERS_TAG + { + $$ = lang_add_vers_depend ($1, $2); + } + ; + +vers_tag: + + { + $$ = lang_new_vers_node (NULL, NULL); + } + | vers_defns ';' + { + $$ = lang_new_vers_node ($1, NULL); + } + | GLOBAL ':' vers_defns ';' + { + $$ = lang_new_vers_node ($3, NULL); + } + | LOCAL ':' vers_defns ';' + { + $$ = lang_new_vers_node (NULL, $3); + } + | GLOBAL ':' vers_defns ';' LOCAL ':' vers_defns ';' + { + $$ = lang_new_vers_node ($3, $7); + } + ; + +vers_defns: + VERS_IDENTIFIER + { + $$ = lang_new_vers_pattern (NULL, $1, ldgram_vers_current_lang, FALSE); + } + | NAME + { + $$ = lang_new_vers_pattern (NULL, $1, ldgram_vers_current_lang, TRUE); + } + | vers_defns ';' VERS_IDENTIFIER + { + $$ = lang_new_vers_pattern ($1, $3, ldgram_vers_current_lang, FALSE); + } + | vers_defns ';' NAME + { + $$ = lang_new_vers_pattern ($1, $3, ldgram_vers_current_lang, TRUE); + } + | vers_defns ';' EXTERN NAME '{' + { + $<name>$ = ldgram_vers_current_lang; + ldgram_vers_current_lang = $4; + } + vers_defns opt_semicolon '}' + { + struct bfd_elf_version_expr *pat; + for (pat = $7; pat->next != NULL; pat = pat->next); + pat->next = $1; + $$ = $7; + ldgram_vers_current_lang = $<name>6; + } + | EXTERN NAME '{' + { + $<name>$ = ldgram_vers_current_lang; + ldgram_vers_current_lang = $2; + } + vers_defns opt_semicolon '}' + { + $$ = $5; + ldgram_vers_current_lang = $<name>4; + } + | GLOBAL + { + $$ = lang_new_vers_pattern (NULL, "global", ldgram_vers_current_lang, FALSE); + } + | vers_defns ';' GLOBAL + { + $$ = lang_new_vers_pattern ($1, "global", ldgram_vers_current_lang, FALSE); + } + | LOCAL + { + $$ = lang_new_vers_pattern (NULL, "local", ldgram_vers_current_lang, FALSE); + } + | vers_defns ';' LOCAL + { + $$ = lang_new_vers_pattern ($1, "local", ldgram_vers_current_lang, FALSE); + } + | EXTERN + { + $$ = lang_new_vers_pattern (NULL, "extern", ldgram_vers_current_lang, FALSE); + } + | vers_defns ';' EXTERN + { + $$ = lang_new_vers_pattern ($1, "extern", ldgram_vers_current_lang, FALSE); + } + ; +@t}\vb{\inline\flatten}{@> +opt_semicolon: + + | ';' + ; + +@g + +@q%%@> + +@ \Cee\ sugar. +@c +void +yyerror(arg) + const char *arg; +{ + if (ldfile_assumed_script) + einfo (_("%P:%s: file format not recognized; treating as linker script\n"), + ldlex_filename ()); + if (error_index > 0 && error_index < ERROR_NAME_MAX) + einfo ("%P%F:%S: %s in %s\n", NULL, arg, error_names[error_index - 1]); + else + einfo ("%P%F:%S: %s\n", NULL, arg); +} + diff --git a/support/splint/examples/ld/ldint.sty b/support/splint/examples/ld/ldint.sty new file mode 100644 index 0000000000..478bdef17d --- /dev/null +++ b/support/splint/examples/ld/ldint.sty @@ -0,0 +1,259 @@ +% Copyright 2012-2015, Alexander Shibakov +% This file is part of SPLinT +% +% SPLinT 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. +% +% SPLinT 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 SPLinT. If not, see <http://www.gnu.org/licenses/>. + +% Simple integer parsing macros to display various styles of integers +% used in ld scripts. Instead of creating a dedicated parser for this +% task, it was decided to implement it as a set of expandable +% macros. The degree of complexity of both implementations would +% probably be about the same, and a true parser approach will be more +% flexible. The choice was made in favor of a macro implementation to +% ensure expandability and speed. + +\def\ldintiterator#1#2#3#4#5#6#7#8{% + % #1 a control sequence to insert at the end + % #2 first divisor + % #3 second divisor + % #4 first remainder + % #5 second remainder + % #6 read digits + % #7 last read digit + % #8 current digit + \ifcat\noexpand#8\relax + \yybreak{#1{#2}{#3}{#4}{#5}{#6}{#7}}% + \else + \yybreak{\expandafter\lditeratormodone\expandafter{\number\incrementmod{#4}{#2}}{#5}{#3}{#1}{#2}{#3}{#6#7}{#8}}% + \yycontinue +} + +\def\incrementmod#1#2{% + \expandafter\incr@mentmod\expandafter{\number\xincrement{#1}}{#2}% +} + +\def\incr@mentmod#1#2{% + \ifnum#1=#2 + \yybreak{0}% + \else + \yybreak{#1}% + \yycontinue +} + +\def\decrementmod#1#2{% + \ifnum#1=\z@ + \yybreak{\xdecrement{#2}}% + \else + \yybreak{\xdecrement{#1}}% + \yycontinue +} + +\def\lditeratormodone#1#2#3{% + \expandafter\lditeratormodtwo\expandafter{\number\incrementmod{#2}{#3}}{#1}% +} + +\def\lditeratormodtwo#1#2#3#4#5{% + \ldintiterator{#3}{#4}{#5}{#2}{#1}% +} + +\def\ldintegerspacingmodone#1#2#3#4#5#6#7#8#9{% + % #1 control sequence to insert at the end + % #2 first divisor + % #3 second divisor + % #4 number of digits mod #2 + % #5 number of digits mod #3 + % #6 digits read + % #7 separator + % #8 last digit + % #9 current digit + \ifcat\noexpand#9\relax + \yybreak{#1{#2}{#3}{#4}{#5}{#6}{#8}}% + \else + \yybreak{\ldintegerspacingmodon@{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}}% + \yycontinue +} + +\def\ldintegerspacingmodon@#1#2#3#4#5#6#7#8#9{% + \ifnum#4=\z@ + \yybreak{% + \yystringempty{#8}{% + \expandafter\ldintegerspacingmod@n@\expandafter{\number\decrementmod{#4}{#2}}{#1}{#2}{#3}{#5}{}{#7}{#9}% + }{% + \expandafter\ldintegerspacingmod@n@\expandafter{\number\decrementmod{#4}{#2}}{#1}{#2}{#3}{#5}{#6#8#7}{#7}{#9}% + }% + }% + \else + \yybreak{% + \expandafter\ldintegerspacingmod@n@\expandafter{\number\decrementmod{#4}{#2}}{#1}{#2}{#3}{#5}{#6#8}{#7}{#9}% + }% + \yycontinue +} + +\def\ldintegerspacingmod@n@#1#2#3#4#5#6#7#8{% + \ldintegerspacingmodone{#2}{#3}{#4}{#1}{#5}{#6}{#7}{#8}% +} + +\def\showiteratorresults#1#2#3#4#5#6{% + \errmessage{mod #1: #3, mod #2: #4, digits: #5, last digit: #6}% +} + +\def\showseparatorresults#1#2#3#4#5#6#7{% + \errmessage{digits after separation: \yystringempty{#1}{}{[#1]}#6.#7}% +} + +\def\ldseparatemodone#1#2#3#4#5#6#7{% + \expandafter\yystringempty\expandafter{\romannumeral-"0#7}{% + \ldintegerspacingmodone{#1{}}{#2}{#3}{#4}{#5}{}{\ldintsep}{}#6#7\end + }{% + \ldseparatewithsuffix{#1}{#2}{#3}{#4}{#5}{#6}{#7}% + }% +} + +\def\ldseparatewithsuffix#1#2#3#4#5#6#7{% + \ifcase\csname ldsuffix#7\endcsname\space + \expandafter\ldseparatewiths@ffix\expandafter{\number\decrementmod{#4}{#2}}{#1}{#2}{#3}{#5}{#6}{#7}% + \or + \expandafter\ldseparatewiths@ffix\expandafter{\number\decrementmod{#5}{#3}}{#1}{#3}{#2}{#4}{#6}{#7}% + \else + \fi +} + +\def\ldseparatewiths@ffix#1#2#3#4#5#6#7{% + \ldintegerspacingmodone{#2{#7}}{#3}{#4}{#1}{#5}{}{\ldintsep}{}#6\end +} + +\def\ldsuffixD{0} +\def\ldsuffixO{0} +\def\ldsuffixB{1} +\def\ldsuffixH{1} +\def\ldsuffixX{1} +% +\def\ldradixD{} +\def\ldradixO{8} +\def\ldradixB{01} +\def\ldradixH{16} +\def\ldradixX{16} +% +\def\ldsuffixK{0} +\def\ldsuffixM{0} +\def\ldsuffixG{0} + +\let\ldintsep\relax + +\def\intprefix#1{% analyzing the prefix of an integer + \intpr@fix#1..\end +} + +\def\intpr@fix#1#2#3\end{% + \if#10% + \if#2X% prefix 0X + 1% hex number + \else + \if#2.% + 4% zero + \else + 3% octal number + \fi + \fi + \else + \if#1$% + 2% hex number + \else + 0% decimal number (no prefix) + \fi + \fi +} + +\def\ldsciinteger#1{% + \ifcase\intprefix{#1} + % decimal number (no prefix) + \lddecsplitws{#1}{}% + \or % hex number (0X) + \expandafter\ldhexsplitws\expandafter{\eattwo#1}{16}% + \or % hex number ($) + \expandafter\ldhexsplitws\expandafter{\eatone#1}{16}% + \or % octal number + \lddecsplitws{#1}{8}% + \or % zero + 0% + \else + \fi +} + +\def\ldhexsplitws#1#2{% + \ldintiterator{\ldseparatemodone{\displayinteger{#2}}}{4}{4}{0}{0}{}{}#1\end +} + +\def\lddecsplitws#1#2{% + \ldintiterator{\ldseparatemodone{\displayinteger{#2}}}{3}{3}{0}{0}{}{}#1\end +} + +\def\ldbasedinteger#1{% + \ldintiterator{\ldseparatewithsuffix{\displayintegerws}}{3}{4}{0}{0}{}{}#1\end +} + +\def\displayinteger#1#2#3#4#5#6#7#8{% + {\def\ldintsep{$\,$}\hbox{\tt#7#8${}_{#1}\yystringempty{#2}{}{\,\hbox{\tt#2}}$}}% +} + +\def\displayintegerws#1#2#3#4#5#6#7{% + {\def\ldintsep{$\,$}\hbox{\tt#6#7${}_{\yystringempty{#1}{}{\csname ldradix#1\endcsname}}$}}% +} + +% typeseting examples in text + +\def\beginldprod{% +% \par + \begingroup + \b@ginldprod +} + +\long\def\b@ginldprod#1\endprod{% + \setldproduction{#1}% + \endgroup +% \par +} + +\long\def\setldproduction#1{% + \def\termidxrank{5}% + \def\headeridxrank{4}% + \def\defidxrank{3}% + \def\texcsidxrank{5}% + \ninepoint + \let\returnexplicitspace\splitexplicitspace + \let\acharswitch\texcharadjust + \let\onecharswitch\texcsadjust + \let\yyinputgroup\yyinputldgroup + \toldparser + \ldparserinit + \yyparse#1\yyeof\yyeof\endparseinput\endparse + \ifyyparsefail % revert to generic macros if parsing failed + \yybreak{\toks0{#1}\errmessage{failed to parse: \the\toks0}}% + \else % Stage three, process the parsed table + \yybreak{% + {% + \restorecslist{ld-display}\ldunion + \the\ldcmds +% \par + \the\lddisplay + }% + }% + \yycontinue +} + +% to make it possible to write {...} without changes + +\def\yyinputldgroup#1{% + \yyinput\{#1\}% +} + diff --git a/support/splint/examples/ld/ldlex.w b/support/splint/examples/ld/ldlex.w new file mode 100644 index 0000000000..9d1c256e62 --- /dev/null +++ b/support/splint/examples/ld/ldlex.w @@ -0,0 +1,550 @@ +@q Copyright 2012-2015 Alexander Shibakov@> +@q Copyright 2002-2014 Free Software Foundation, Inc.@> +@q This file is part of SPLinT@> + +@q SPLinT is free software: you can redistribute it and/or modify@> +@q it under the terms of the GNU General Public License as published by@> +@q the Free Software Foundation, either version 3 of the License, or@> +@q (at your option) any later version.@> + +@q SPLinT is distributed in the hope that it will be useful,@> +@q but WITHOUT ANY WARRANTY; without even the implied warranty of@> +@q MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the@> +@q GNU General Public License for more details.@> + +@q You should have received a copy of the GNU General Public License@> +@q along with SPLinT. If not, see <http://www.gnu.org/licenses/>.@> + +@** The lexer. +\ifx\parsernamespace\UNDEFINED + \input ldman.sty + \input limbo.sty + \input dcols.sty + \setupfootnotes + \def\MRI{} + \def\ld{} +\fi +The lexer used by \ld\ is almost straightforward. There are a few +facilities (\Cee\ header files, some output functions) needed by the +lexer that are conviniently coded into the \Cee\ code run by the +driver routines that make the lexer more complex than it should have +been but the function of each such facility can be easily clarified +using this documentation and occasionally referring to the manual for +the \bison\ parser which is part of this distribution. +@(ldl.ll@>= +@G + @> @<\ld\ lexer definitions@> @= +%{@> @<\ld\ lexer \Cee\ preamble@> @=%} + @> @<\ld\ lexer options@> @= +%% + @> @<\ld\ token regular expressions@> @= +%% +@O +void define_all_states( void ) { + @<Collect state definitions for the \ld\ lexer@>@; +} +@o +@g + +@ @<\ld\ lexer options@>= +@G +%option bison-bridge +%option noyywrap nounput noinput reentrant +%option noyy_top_state +%option debug +%option stack +%option outfile="ldl.c" +@g + +@ @<\ld\ lexer \Cee\ preamble@>= +#include <stdint.h> +#include <stdbool.h> + +@ @<Collect state definitions for the \ld\ lexer@>= +#define _register_name( name ) @[Define_State( #name, name )@] +#include "ldl_states.h" +#undef _register_name + +@ \yyskipparsetrue The character classes used by the scanner as well as +lexer state declarations have been put in the definitions section of +the input file. No attempt has been made to clean up the definitions +of the character classes. +@<\ld\ lexer definitions@>= +@<\ld\ lexer states@>@; +@G +CMDFILENAMECHAR [_a-zA-Z0-9\/\.\\_\+\$\:\[\]\\\,\=\&\!\<\>\-\~] +CMDFILENAMECHAR1 [_a-zA-Z0-9\/\.\\_\+\$\:\[\]\\\,\=\&\!\<\>\~] +FILENAMECHAR1 [_a-zA-Z\/\.\\\$\_\~] +SYMBOLCHARN [_a-zA-Z\/\.\\\$\_\~0-9] +FILENAMECHAR [_a-zA-Z0-9\/\.\-\_\+\=\$\:\[\]\\\,\~] +WILDCHAR [_a-zA-Z0-9\/\.\-\_\+\=\$\:\[\]\\\,\~\?\*\^\!] +WHITE [ \t\n\r]+ +NOCFILENAMECHAR [_a-zA-Z0-9\/\.\-\_\+\$\:\[\]\\\~] +V_TAG [.$_a-zA-Z][._a-zA-Z0-9]* +V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)* +@g + +@ The lexer uses different sets of rules depending on the context and the current state. +These can be changed from the lexer itself or externally by the parser +(as is the case in \ld\ +implementation). \locallink{stateswitchers}Later\endlink, a number of +helper macros implement state switching so that the state names are +very rarely used explicitly. Keeping all the state declarations in the +same section simplifies the job of the +\locallink{bootstrapstates}bootstrap parser\endlink, as well. +\ifbootstrapmode\immediate\openout\stlist=ldl_states.h\fi +\yyskipparsefalse +@<\ld\ lexer states@>= +@G +%s SCRIPT +%s EXPRESSION +%s BOTH +%s DEFSYMEXP +%s MRI +%s VERS_START +%s VERS_SCRIPT +%s VERS_NODE +@g + +@*1 Macros for lexer functions. +The \locallink{pingpong}state switching\endlink\ `ping-pong' between the lexer and the parser aside, +the \ld\ lexer is very traditional. One implementation choice +deserving some attenion is the treatment of comments by the lexer. The +difficulty of implementing \Cee\ style comment lexing using regular +expressions is well-known so an often used alternative is a +special function that simply skips to the end of the comment. This is +exactly what the \ld\ lexer does with an aptly named |comment()| +function. The typesetting parser uses the \.{\\ldcomment} macro for +the same purpose. For the curious, here is a \flex\ style regular +expression defining \Cee\ comments\footnote{Taken from W.~McKeeman's site +at +\url{http://www.cs.dartmouth.edu/~mckeeman/cs118/assignments/comment.html} +and adopted to \flex\ syntax.}: +$$ +\hbox{\.{"/*" ("/"\yl[\^*/]\yl"*"+[\^*/])* "*"+ "/"}} +$$ +This expression does not handle {\it every\/} practical situation, +however, since it assumes that the end of line character can be +matched like any other. Neither does it detect some often made +mistakes such as attempting to nest comments. A few minor +modifications can fix this deficiency, as well as add some error +handling, however, for the sake of consistency, the approach taken +here mirrors the one in the original \ld. + +The top level of the \.{\\ldcomment} macro simply bypasses the state +setup of the lexer and enters a `|while| loop' in the input +routine. This macro is a reasonable approximation of the functionality +provided by |comment()|. +@<Additional macros for the \ld\ lexer/parser@>= +@G +\def\ldcomment{% + \let\oldyyreturn\yyreturn + \let\oldyylextail\yylextail + \let\yylextail\yymatch %/* start inputting characters until {\tt *}{\tt /} is seen */ + \let\yyreturn\ldcommentskipchars +} +@g + +@ The rest of the |while| loop merely waits for the \.{*/} combination. +@<Additional macros for the \ld\ lexer/parser@>= +@G +\def\ldcommentskipchars{% + \ifnum\yycp@@=`* + \yybreak{\let\yyreturn\ldcommentseekslash\yyinput}% + %/* {\tt *} found, look for {\tt /} */ + \else + \yybreak{\yyinput}% %/* keep skipping characters */ + \yycontinue +}% + +\def\ldcommentseekslash{% + \ifnum\yycp@@=`/ + \yybreak{\ldcommentfinish}%/* {\tt /} found, exit */ + \else + \ifnum\yycp@@=`* + \yybreak@@{\yyinput}% %/* keep skipping {\tt *}'s looking for a {\tt /} */ + \else + \yybreak@@{\let\yyreturn\ldcommentskipchars\yyinput}% + %/* found a character other than {\tt *} or {\tt /} */ + \fi + \yycontinue +}% +@g + +@ Once the end of the comment has been found, resume lexing the input +stream. +@<Additional macros for the \ld\ lexer/parser@>= +@G +\def\ldcommentfinish{% + \let\yyreturn\oldyyreturn + \let\yylextail\oldyylextail + \yylextail +} +@g + +@ The semantics of the macros defined above do not quite match that +of the |comment()| function. The most significant difference is that +the portion of the action following \.{\\ldcomment} expands {\it +before\/} the comment characters are skipped. In most applications, +|comment()| is the last function called so this would not limit the use +of \.{\\ldcomment} too dramatically. + +A more intuitive and easier to use version of \.{\\ldcomment} is +possible, however, if \.{\\yylextail} is not used inside actions (in the case of +an `optimized' lexer the restriction is even weaker, namely, +\.{\\yylextail} merely has to be absent in the portion of the action +following \.{\\ldcomment}). +@<Additional macros for the \ld\ lexer/parser@>= +@G +\def\ldcomment#1\yylextail{% + \let\oldyyreturn\yyreturn + \def\yylexcontinuation{#1\yylextail}% + \let\yyreturn\ldcommentskipchars %/* start inputting characters until {\tt *}{\tt /} is seen */ + \yymatch +} + +\def\ldcommentfinish{% + \let\yyreturn\oldyyreturn + \yylexcontinuation +} +@g + +@ \namedspot{pretendbufferswlex}The same idea can be applied to +`\locallink{pretendbuffersw}pretend buffer switching\endlink'. Whenever +the `real' \ld\ parser encounters an \prodstyle{INCLUDE} command, it +switches the input buffer for the lexer and waits for the lexer to +return the tokens from the file it just opened. When the lexer scans +the end of the included file, it returns a special token, \prodstyle{END} that +completes the appropriate production and lets the parser continue with +its job. + +We would like to simulate the file inclusion by inserting the +appropriate end of file marker for the lexer (a double +\.{\\yyeof}). After the relevant production completes, the marker +has to be cleaned up from the input stream (the lexer is designed to +leave it intact). The macros below are designed to handle this assignment. +@<Additional macros for the \ld\ lexer/parser@>= +@G +\def\ldcleanyyeof#1\yylextail{% + \let\oldyyinput\yyinput + \def\yyinput\yyeof\yyeof{\let\yyinput\oldyyinput#1\yylextail}% + \yymatch +} +@g + +@*1 Regular expressions. +The `heart' of any lexer is the collection of regular expressions that +describe the {\it tokens\/} of the appropriate language. The variey of +tokens recognized by \ld\ is quite extensive and is described in the +sections that follow. + +Variable names and algebraic operations come first. +@<\ld\ token regular expressions@>= +@G +<BOTH,SCRIPT,EXPRESSION,VERS_START,VERS_NODE,VERS_SCRIPT>"/*" {@> @[TeX_( "/ldcomment/yylexnext" );@]@=} +<DEFSYMEXP>"-" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<DEFSYMEXP>"+" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<DEFSYMEXP>{FILENAMECHAR1}{SYMBOLCHARN}* {@> @[TeX_( "/yylexreturnval{NAME}" );@]@=} +<DEFSYMEXP>"=" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<MRI,EXPRESSION>"$"([0-9A-Fa-f])+ {@> @<Return an absolute hex constant@> @=} +<MRI,EXPRESSION>([0-9A-Fa-f])+(H|h|X|x|B|b|O|o|D|d) {@> @<Return a constant in a specific radix@>@=} +<SCRIPT,DEFSYMEXP,MRI,BOTH,EXPRESSION>((("$"|0[xX])([0-9A-Fa-f])+)|(([0-9])+))(M|K|m|k)? { + @> @<Return a constant with a multiplier@>@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"]" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"[" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"<<=" {@> @[TeX_( "/yylexreturnptr{LSHIFTEQ}" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>">>=" {@> @[TeX_( "/yylexreturnptr{RSHIFTEQ}" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"||" {@> @[TeX_( "/yylexreturnptr{OROR}" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"==" {@> @[TeX_( "/yylexreturnptr{EQ}" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"!=" {@> @[TeX_( "/yylexreturnptr{NE}" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>">=" {@> @[TeX_( "/yylexreturnptr{GE}" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"<=" {@> @[TeX_( "/yylexreturnptr{LE}" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"<<" {@> @[TeX_( "/yylexreturnptr{LSHIFT}" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>">>" {@> @[TeX_( "/yylexreturnptr{RSHIFT}" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"+=" {@> @[TeX_( "/yylexreturnptr{PLUSEQ}" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"-=" {@> @[TeX_( "/yylexreturnptr{MINUSEQ}" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"*=" {@> @[TeX_( "/yylexreturnptr{MULTEQ}" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"/=" {@> @[TeX_( "/yylexreturnptr{DIVEQ}" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"&=" {@> @[TeX_( "/yylexreturnptr{ANDEQ}" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"|=" {@> @[TeX_( "/yylexreturnptr{OREQ}" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"&&" {@> @[TeX_( "/yylexreturnptr{ANDAND}" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>">" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"," {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"&" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"|" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"~" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"!" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"?" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"*" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"+" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"-" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"/" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"%" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"<" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"=" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"}" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"{" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>")" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"(" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>":" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>";" {@> @[TeX_( "/yylexreturnchar" );@]@=} +@g + +@ The bulk of tokens produced by the lexer are the keywords used +inside script files. File name syntax is listed as well, along with +miscellanea such as whitespace and version symbols. +@<\ld\ token regular expressions@>= +@G +<BOTH,SCRIPT>"MEMORY" {@> @[TeX_( "/yylexreturnptr{MEMORY}" );@]@=} +<BOTH,SCRIPT>"REGION_ALIAS" {@> @[TeX_( "/yylexreturnptr{REGION_ALIAS}" );@]@=} +<BOTH,SCRIPT>"LD_FEATURE" {@> @[TeX_( "/yylexreturnptr{LD_FEATURE}" );@]@=} +<BOTH,SCRIPT,EXPRESSION>"ORIGIN" {@> @[TeX_( "/yylexreturnptr{ORIGIN}" );@]@=} +<BOTH,SCRIPT>"VERSION" {@> @[TeX_( "/yylexreturnptr{VERSIONK}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"BLOCK" {@> @[TeX_( "/yylexreturnptr{BLOCK}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"BIND" {@> @[TeX_( "/yylexreturnptr{BIND}" );@]@=} +<BOTH,SCRIPT,EXPRESSION>"LENGTH" {@> @[TeX_( "/yylexreturnptr{LENGTH}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"ALIGN" {@> @[TeX_( "/yylexreturnptr{ALIGN_K}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_ALIGN" {@> @[TeX_( "/yylexreturnptr{DATA_SEGMENT_ALIGN}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_RELRO_END" {@> @[TeX_( "/yylexreturnptr{DATA_SEGMENT_RELRO_END}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_END" {@> @[TeX_( "/yylexreturnptr{DATA_SEGMENT_END}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"ADDR" {@> @[TeX_( "/yylexreturnptr{ADDR}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"LOADADDR" {@> @[TeX_( "/yylexreturnptr{LOADADDR}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"ALIGNOF" {@> @[TeX_( "/yylexreturnptr{ALIGNOF}" );@]@=} +<EXPRESSION,BOTH>"MAX" {@> @[TeX_( "/yylexreturnptr{MAX_K}" );@]@=} +<EXPRESSION,BOTH>"MIN" {@> @[TeX_( "/yylexreturnptr{MIN_K}" );@]@=} +<EXPRESSION,BOTH>"LOG2CEIL" {@> @[TeX_( "/yylexreturnptr{LOG2CEIL}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"ASSERT" {@> @[TeX_( "/yylexreturnptr{ASSERT_K}" );@]@=} +<BOTH,SCRIPT>"ENTRY" {@> @[TeX_( "/yylexreturnptr{ENTRY}" );@]@=} +<BOTH,SCRIPT,MRI>"EXTERN" {@> @[TeX_( "/yylexreturnptr{EXTERN}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"NEXT" {@> @[TeX_( "/yylexreturnptr{NEXT}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"sizeof_headers" {@> @[TeX_( "/yylexreturnptr{SIZEOF_HEADERS}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"SIZEOF_HEADERS" {@> @[TeX_( "/yylexreturnptr{SIZEOF_HEADERS}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"SEGMENT_START" {@> @[TeX_( "/yylexreturnptr{SEGMENT_START}" );@]@=} +<BOTH,SCRIPT>"MAP" {@> @[TeX_( "/yylexreturnptr{MAP}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"SIZEOF" {@> @[TeX_( "/yylexreturnptr{SIZEOF}" );@]@=} +<BOTH,SCRIPT>"TARGET" {@> @[TeX_( "/yylexreturnptr{TARGET_K}" );@]@=} +<BOTH,SCRIPT>"SEARCH_DIR" {@> @[TeX_( "/yylexreturnptr{SEARCH_DIR}" );@]@=} +<BOTH,SCRIPT>"OUTPUT" {@> @[TeX_( "/yylexreturnptr{OUTPUT}" );@]@=} +<BOTH,SCRIPT>"INPUT" {@> @[TeX_( "/yylexreturnptr{INPUT}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"GROUP" {@> @[TeX_( "/yylexreturnptr{GROUP}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"AS_NEEDED" {@> @[TeX_( "/yylexreturnptr{AS_NEEDED}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"DEFINED" {@> @[TeX_( "/yylexreturnptr{DEFINED}" );@]@=} +<BOTH,SCRIPT>"CREATE_OBJECT_SYMBOLS" {@> @[TeX_( "/yylexreturnptr{CREATE_OBJECT_SYMBOLS}" );@]@=} +<BOTH,SCRIPT>"CONSTRUCTORS" {@> @[TeX_( "/yylexreturnptr{CONSTRUCTORS}" );@]@=} +<BOTH,SCRIPT>"FORCE_COMMON_ALLOCATION" {@> @[TeX_( "/yylexreturnptr{FORCE_COMMON_ALLOCATION}" );@]@=} +<BOTH,SCRIPT>"INHIBIT_COMMON_ALLOCATION" {@> @[TeX_( "/yylexreturnptr{INHIBIT_COMMON_ALLOCATION}" );@]@=} +<BOTH,SCRIPT>"SECTIONS" {@> @[TeX_( "/yylexreturnptr{SECTIONS}" );@]@=} +<BOTH,SCRIPT>"INSERT" {@> @[TeX_( "/yylexreturnptr{INSERT_K}" );@]@=} +<BOTH,SCRIPT>"AFTER" {@> @[TeX_( "/yylexreturnptr{AFTER}" );@]@=} +<BOTH,SCRIPT>"BEFORE" {@> @[TeX_( "/yylexreturnptr{BEFORE}" );@]@=} +<BOTH,SCRIPT>"FILL" {@> @[TeX_( "/yylexreturnptr{FILL}" );@]@=} +<BOTH,SCRIPT>"STARTUP" {@> @[TeX_( "/yylexreturnptr{STARTUP}" );@]@=} +<BOTH,SCRIPT>"OUTPUT_FORMAT" {@> @[TeX_( "/yylexreturnptr{OUTPUT_FORMAT}" );@]@=} +<BOTH,SCRIPT>"OUTPUT_ARCH" {@> @[TeX_( "/yylexreturnptr{OUTPUT_ARCH}" );@]@=} +<BOTH,SCRIPT>"HLL" {@> @[TeX_( "/yylexreturnptr{HLL}" );@]@=} +<BOTH,SCRIPT>"SYSLIB" {@> @[TeX_( "/yylexreturnptr{SYSLIB}" );@]@=} +<BOTH,SCRIPT>"FLOAT" {@> @[TeX_( "/yylexreturnptr{FLOAT}" );@]@=} +<BOTH,SCRIPT>"QUAD" {@> @[TeX_( "/yylexreturnptr{QUAD}" );@]@=} +<BOTH,SCRIPT>"SQUAD" {@> @[TeX_( "/yylexreturnptr{SQUAD}" );@]@=} +<BOTH,SCRIPT>"LONG" {@> @[TeX_( "/yylexreturnptr{LONG}" );@]@=} +<BOTH,SCRIPT>"SHORT" {@> @[TeX_( "/yylexreturnptr{SHORT}" );@]@=} +<BOTH,SCRIPT>"BYTE" {@> @[TeX_( "/yylexreturnptr{BYTE}" );@]@=} +<BOTH,SCRIPT>"NOFLOAT" {@> @[TeX_( "/yylexreturnptr{NOFLOAT}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"NOCROSSREFS" {@> @[TeX_( "/yylexreturnptr{NOCROSSREFS}" );@]@=} +<BOTH,SCRIPT>"OVERLAY" {@> @[TeX_( "/yylexreturnptr{OVERLAY}" );@]@=} +<BOTH,SCRIPT>"SORT_BY_NAME" {@> @[TeX_( "/yylexreturnptr{SORT_BY_NAME}" );@]@=} +<BOTH,SCRIPT>"SORT_BY_ALIGNMENT" {@> @[TeX_( "/yylexreturnptr{SORT_BY_ALIGNMENT}" );@]@=} +<BOTH,SCRIPT>"SORT" {@> @[TeX_( "/yylexreturnptr{SORT_BY_NAME}" );@]@=} +<BOTH,SCRIPT>"SORT_BY_INIT_PRIORITY" {@> @[TeX_( "/yylexreturnptr{SORT_BY_INIT_PRIORITY}" );@]@=} +<BOTH,SCRIPT>"SORT_NONE" {@> @[TeX_( "/yylexreturnptr{SORT_NONE}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"NOLOAD" {@> @[TeX_( "/yylexreturnptr{NOLOAD}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"DSECT" {@> @[TeX_( "/yylexreturnptr{DSECT}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"COPY" {@> @[TeX_( "/yylexreturnptr{COPY}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"INFO" {@> @[TeX_( "/yylexreturnptr{INFO}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"OVERLAY" {@> @[TeX_( "/yylexreturnptr{OVERLAY}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"ONLY_IF_RO" {@> @[TeX_( "/yylexreturnptr{ONLY_IF_RO}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"ONLY_IF_RW" {@> @[TeX_( "/yylexreturnptr{ONLY_IF_RW}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"SPECIAL" {@> @[TeX_( "/yylexreturnptr{SPECIAL}" );@]@=} +<BOTH,SCRIPT>"o" {@> @[TeX_( "/yylexreturnptr{ORIGIN}" );@]@=} +<BOTH,SCRIPT>"org" {@> @[TeX_( "/yylexreturnptr{ORIGIN}" );@]@=} +<BOTH,SCRIPT>"l" {@> @[TeX_( "/yylexreturnptr{LENGTH}" );@]@=} +<BOTH,SCRIPT>"len" {@> @[TeX_( "/yylexreturnptr{LENGTH}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"INPUT_SECTION_FLAGS" {@> @[TeX_( "/yylexreturnptr{INPUT_SECTION_FLAGS}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"INCLUDE" {@> @[TeX_( "/yylexreturnptr{INCLUDE}" );@]@=} +<BOTH,SCRIPT>"PHDRS" {@> @[TeX_( "/yylexreturnptr{PHDRS}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"AT" {@> @[TeX_( "/yylexreturnptr{AT}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"ALIGN_WITH_INPUT" {@> @[TeX_( "/yylexreturnptr{ALIGN_WITH_INPUT}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"SUBALIGN" {@> @[TeX_( "/yylexreturnptr{SUBALIGN}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"HIDDEN" {@> @[TeX_( "/yylexreturnptr{HIDDEN}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"PROVIDE" {@> @[TeX_( "/yylexreturnptr{PROVIDE}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"PROVIDE_HIDDEN" {@> @[TeX_( "/yylexreturnptr{PROVIDE_HIDDEN}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"KEEP" {@> @[TeX_( "/yylexreturnptr{KEEP}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"EXCLUDE_FILE" {@> @[TeX_( "/yylexreturnptr{EXCLUDE_FILE}" );@]@=} +<EXPRESSION,BOTH,SCRIPT>"CONSTANT" {@> @[TeX_( "/yylexreturnptr{CONSTANT}" );@]@=} +<MRI>"#".*\n? {@> @[TeX_( "/yylexnext" );@]@=} +<MRI>"\n" {@> @[TeX_( "/yylexreturnptr{NEWLINE}" );@]@=} +<MRI>"*".* {@> @[TeX_( "/yylexnext" );@]@=} +<MRI>";".* {@> @[TeX_( "/yylexnext" );@]@=} +<MRI>"END" {@> @[TeX_( "/yylexreturnptr{ENDWORD}" );@]@=} +<MRI>"ALIGNMOD" {@> @[TeX_( "/yylexreturnptr{ALIGNMOD}" );@]@=} +<MRI>"ALIGN" {@> @[TeX_( "/yylexreturnptr{ALIGN_K}" );@]@=} +<MRI>"CHIP" {@> @[TeX_( "/yylexreturnptr{CHIP}" );@]@=} +<MRI>"BASE" {@> @[TeX_( "/yylexreturnptr{BASE}" );@]@=} +<MRI>"ALIAS" {@> @[TeX_( "/yylexreturnptr{ALIAS}" );@]@=} +<MRI>"TRUNCATE" {@> @[TeX_( "/yylexreturnptr{TRUNCATE}" );@]@=} +<MRI>"LOAD" {@> @[TeX_( "/yylexreturnptr{LOAD}" );@]@=} +<MRI>"PUBLIC" {@> @[TeX_( "/yylexreturnptr{PUBLIC}" );@]@=} +<MRI>"ORDER" {@> @[TeX_( "/yylexreturnptr{ORDER}" );@]@=} +<MRI>"NAME" {@> @[TeX_( "/yylexreturnptr{NAMEWORD}" );@]@=} +<MRI>"FORMAT" {@> @[TeX_( "/yylexreturnptr{FORMAT}" );@]@=} +<MRI>"CASE" {@> @[TeX_( "/yylexreturnptr{CASE}" );@]@=} +<MRI>"START" {@> @[TeX_( "/yylexreturnptr{START}" );@]@=} +<MRI>"LIST".* {@> @[TeX_( "/yylexreturnptr{LIST}" );@]@=} +<MRI>"SECT" {@> @[TeX_( "/yylexreturnptr{SECT}" );@]@=} +<EXPRESSION,BOTH,SCRIPT,MRI>"ABSOLUTE" {@> @[TeX_( "/yylexreturnptr{ABSOLUTE}" );@]@=} +<MRI>"end" {@> @[TeX_( "/yylexreturnptr{ENDWORD}" );@]@=} +<MRI>"alignmod" {@> @[TeX_( "/yylexreturnptr{ALIGNMOD}" );@]@=} +<MRI>"align" {@> @[TeX_( "/yylexreturnptr{ALIGN_K}" );@]@=} +<MRI>"chip" {@> @[TeX_( "/yylexreturnptr{CHIP}" );@]@=} +<MRI>"base" {@> @[TeX_( "/yylexreturnptr{BASE}" );@]@=} +<MRI>"alias" {@> @[TeX_( "/yylexreturnptr{ALIAS}" );@]@=} +<MRI>"truncate" {@> @[TeX_( "/yylexreturnptr{TRUNCATE}" );@]@=} +<MRI>"load" {@> @[TeX_( "/yylexreturnptr{LOAD}" );@]@=} +<MRI>"public" {@> @[TeX_( "/yylexreturnptr{PUBLIC}" );@]@=} +<MRI>"order" {@> @[TeX_( "/yylexreturnptr{ORDER}" );@]@=} +<MRI>"name" {@> @[TeX_( "/yylexreturnptr{NAMEWORD}" );@]@=} +<MRI>"format" {@> @[TeX_( "/yylexreturnptr{FORMAT}" );@]@=} +<MRI>"case" {@> @[TeX_( "/yylexreturnptr{CASE}" );@]@=} +<MRI>"extern" {@> @[TeX_( "/yylexreturnptr{EXTERN}" );@]@=} +<MRI>"start" {@> @[TeX_( "/yylexreturnptr{START}" );@]@=} +<MRI>"list".* {@> @[TeX_( "/yylexreturnptr{LIST}" );@]@=} +<MRI>"sect" {@> @[TeX_( "/yylexreturnptr{SECT}" );@]@=} +<EXPRESSION,BOTH,SCRIPT,MRI>"absolute" {@> @[TeX_( "/yylexreturnptr{ABSOLUTE}" );@]@=} +<MRI>{FILENAMECHAR1}{NOCFILENAMECHAR}* {@> @[TeX_( "/yylexreturnval{NAME}" );@]@=} +<BOTH>{FILENAMECHAR1}{FILENAMECHAR}* {@> @[TeX_( "/yylexreturnval{NAME}" );@]@=} +<BOTH>"-l"{FILENAMECHAR}+ {@> @[TeX_( "/yylexreturnval{NAME}" );@]@=} +<EXPRESSION>{FILENAMECHAR1}{NOCFILENAMECHAR}* {@> @[TeX_( "/yylexreturnval{NAME}" );@]@=} +<EXPRESSION>"-l"{NOCFILENAMECHAR}+ {@> @[TeX_( "/yylexreturnval{NAME}" );@]@=} +<SCRIPT>{WILDCHAR}* {@> @[@<Skip a possible comment and return a \prodstyle{NAME}@>@]@=} +<EXPRESSION,BOTH,SCRIPT,VERS_NODE>"\""[^\"]*"\"" {@> @[@<Return the \prodstyle{NAME} inside quotes@>@]@=} +<BOTH,SCRIPT,EXPRESSION>"\n" {@> @[TeX_( "/yylexnext" );@]@=} +<MRI,BOTH,SCRIPT,EXPRESSION>[ \t\r]+ {@> @[TeX_( "/yylexnext" );@]@=} +<VERS_NODE,VERS_SCRIPT>[:,;] {@> @[TeX_( "/yylexreturnchar" );@]@=} +<VERS_NODE>global {@> @[TeX_( "/yylexreturnptr{GLOBAL}" );@]@=} +<VERS_NODE>local {@> @[TeX_( "/yylexreturnptr{LOCAL}" );@]@=} +<VERS_NODE>extern {@> @[TeX_( "/yylexreturnptr{EXTERN}" );@]@=} +<VERS_NODE>{V_IDENTIFIER} {@> @[TeX_( "/yylexreturnval{VERS_IDENTIFIER}" );@]@=} +<VERS_SCRIPT>{V_TAG} {@> @[TeX_( "/yylexreturnval{VERS_TAG}" );@]@=} +<VERS_START>"{" {@> @[TeX_( "/yyBEGIN{VERS_SCRIPT}/yylexreturnchar" );@]@=} +@g + +@ There is a bit of a trick to returning an absolute hex value. The +macros are looking for a \.{\$} suffix while the contents of +\.{\\yytext} start with \.{\\\$}. +@<Return an absolute hex constant@>= +@[TeX_( "/edef/next{/yylval{/nx/hexint{$/expandafter/eatone/the/yytext}" );@]@; +@[TeX_( "{/the/yyfmark}{/the/yysmark}}}/next" );@]@; +@[TeX_( "/yylexreturn{INT}" );@]@; + +@ @<Return a constant in a specific radix@>= +@[TeX_( "/edef/next{/yylval{/nx/bint{/the/yytext}" );@]@; +@[TeX_( "{/the/yyfmark}{/the/yysmark}}}/next" );@]@; +@[TeX_( "/yylexreturn{INT}" );@]@; + +@ @<Return a constant with a multiplier@>= +@[TeX_( "/edef/next{/yylval{/nx/anint{/the/yytext}" );@]@; +@[TeX_( "{/the/yyfmark}{/the/yysmark}}}/next" );@]@; +@[TeX_( "/yylexreturn{INT}" );@]@; + +@ @<Additional macros for the \ld\ lexer/parser@>= +@G +@=\def\matchcomment@@#1/*#2\yyeof#3#4{%@>@; + \yystringempty{#1}{#3}{#4}% +} +\def\matchcomment#1{% +@= \expandafter\matchcomment@@\the#1/*\yyeof@>@; +} +\def\ldstripquotes@@"#1"\yyeof{#1} +\def\ldstripquotes#1{% + \yytext\expandafter\expandafter\expandafter + {\expandafter\ldstripquotes@@\the\yytext\yyeof}% + \yytextpure\expandafter\expandafter\expandafter + {\expandafter\ldstripquotes@@\the\yytextpure\yyeof}% +} +@g + +@ {\it Annoyingly, this pattern can match comments, and we have +longest match issues to consider. So if the first two +characters are a comment opening, put the input back and +try again.} +@<Skip a possible comment and return a \prodstyle{NAME}@>= + @[TeX_( "/matchcomment/yytextpure" );@]@; + @[TeX_( " {/yyless/tw@@/ldcomment}" );@]/*matched the beginning of a comment*/@; + @[TeX_( " {/yylexreturnval{NAME}}" );@]@; + +@ {\it No matter the state, quotes give what's inside.} +@<Return the \prodstyle{NAME} inside quotes@>= + @[TeX_( "/ldstripquotes/yylexreturnval{NAME}" );@]@; + +@ @<Additional macros for the \ld\ lexer/parser@>= +@G +\newcount\versnodenesting +\newcount\includestackptr +@g + +@ Some syntax specific to version scripts. +@<\ld\ token regular expressions@>= +@G +<VERS_SCRIPT>"{" {@> @[TeX_( "/yyBEGIN{VERS_NODE}/versnodenesting=/z@@/yylexreturnchar" );@]@=} +<VERS_SCRIPT>"}" {@> @[TeX_( "/yylexreturnchar" );@]@=} +<VERS_NODE>"{" {@> @[TeX_( "/advance/versnodenesting/@@ne /yylexreturnchar" );@]@=} +<VERS_NODE>"}" {@> @[TeX_( "/advance/versnodenesting/m@@ne" );@]@; + @> @[TeX_( "/ifnum/versnodenesting</z@@" );@]@; + @> @[TeX_( " /yyBEGIN{VERS_SCRIPT}" );@]@; + @> @[TeX_( "/fi" );@]@; + @> @[TeX_( "/yylexreturnchar" );@]@=} +<VERS_START,VERS_NODE,VERS_SCRIPT>[\n] {@> @[TeX_( "/yylexnext" );@]@=} +<VERS_START,VERS_NODE,VERS_SCRIPT>#.* {@> @[TeX_( "/yylexnext" );@]@=} +<VERS_START,VERS_NODE,VERS_SCRIPT>[ \t\r]+ {@> @[TeX_( "/yylexnext" );@]@=} + +<<EOF>> {@> @[@<Process the end of (possibly included) file@>@]@=} + +<SCRIPT,MRI,VERS_START,VERS_SCRIPT,VERS_NODE>. {@> @[TeX_( "/yycomplain{bad character `/the/yytext'" );@] + @> @[TeX_( " in script}" );@] + @> @[TeX_( "/yyerrterminate" );@]@=} +<EXPRESSION,DEFSYMEXP,BOTH>. {@> @[TeX_( "/yycomplain{bad character `/the/yytext'" );@] + @> @[TeX_( " in expression}" );@]@= + @> @[TeX_( "/yyerrterminate" );@]@=} +@g + +@ @<Process the end of (possibly included) file@>= + @[TeX_( "/advance/includestackptr/m@@ne" );@]@; + @[TeX_( "/ifnum/includestackptr=/z@@" );@]@; + @[TeX_( " /yybreak{/yyterminate}" );@]@; + @[TeX_( "/else" );@]@; + @[TeX_( " /yybreak{/ldcleanyyeof/yylexreturn{END}}" );@]@; + @[TeX_( "/yycontinue" );@]@; + +@*1 Parser-lexer interaction support. +\namedspot{stateswitchers}Here are the long promised auxiliary +macros for switching lexer states and handling file input. +@<Additional macros for the \ld\ lexer/parser@>= +@G +\def\ldlex@@script{\yypushstate{SCRIPT}} +\def\ldlex@@mri@@script{\yypushstate{MRI}} +\def\ldlex@@version@@script{\yypushstate{VERS_START}} +\def\ldlex@@version@@file{\yypushstate{VERS_SCRIPT}} +\def\ldlex@@defsym{\yypushstate{DEFSYMEXP}} +\def\ldlex@@expression{\yypushstate{EXPRESSION}} +\def\ldlex@@both{\yypushstate{BOTH}} +\let\ldlex@@popstate\yypopstate + +\def\ldfile@@open@@command@@file#1{% + \advance\includestackptr\@@ne + \appendl\yytextseen{\noexpand\yyeof\noexpand\yyeof}% + \yytextbackuptrue +} + +\def\ldlex@@filename{} +@g + diff --git a/support/splint/examples/ld/ldlexo.w b/support/splint/examples/ld/ldlexo.w new file mode 100644 index 0000000000..6b62d2fd77 --- /dev/null +++ b/support/splint/examples/ld/ldlexo.w @@ -0,0 +1,763 @@ +@q Copyright 2015 Alexander Shibakov@> +@q Copyright 2002-2015 Free Software Foundation, Inc.@> +@q This file is part of SPLinT@> + +@q SPLinT is free software: you can redistribute it and/or modify@> +@q it under the terms of the GNU General Public License as published by@> +@q the Free Software Foundation, either version 3 of the License, or@> +@q (at your option) any later version.@> + +@q SPLinT is distributed in the hope that it will be useful,@> +@q but WITHOUT ANY WARRANTY; without even the implied warranty of@> +@q MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the@> +@q GNU General Public License for more details.@> + +@q You should have received a copy of the GNU General Public License@> +@q along with SPLinT. If not, see <http://www.gnu.org/licenses/>.@> + +@*1 The original lexer. {\it Note that the \ld\ lexer was designed to accomodate +the syntax of various \flex\ flavors, such as the original \lex. The +options \prodstyle{\%a} and \prodstyle{\%o} are ignored by \flex\ and +are a leftover from the archaic days of the original scanner generator.} + +@s input_type int + +@<Original \ld\ lexer@>= +@G + @> @<Original \ld\ macros@> @= +%{@>@<Original \ld\ preamble@> @=%} +%option nounput + @> @<Ignored options@> @= +%% + @> @<Original \ld\ regular expressions@> @= +%% +@g + +@ @<Original \ld\ preamble@>= +#include "bfd.h" +#include "safe-ctype.h" +#include "bfdlink.h" +#include "ld.h" +#include "ldmisc.h" +#include "ldexp.h" +#include "ldlang.h" +#include <ldgram.h> +#include "ldfile.h" +#include "ldlex.h" +#include "ldmain.h" +#include "libiberty.h" + +input_type parser_input;/* The type of top-level parser input. + |yylex| and |yyparse| (indirectly) both check this. */ + +unsigned int lineno = 1;/* Line number in the current input file. */ + +const char *lex_string = NULL;/* The string we are currently lexing, or |NULL| if we are reading a + file. */ + +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result = yy_input (buf, max_size) +/* Support for \flex\ reading from more than one input file (stream). + |include_stack| is \flex's input state for each open file; + |file_name_stack| is the file names. |lineno_stack| is the current + line numbers. + + If |include_stack_ptr| is 0, we haven't started reading anything yet. + Otherwise, stack elements 0 through |include_stack_ptr - 1| are valid. */ + + +#ifndef YY_NO_UNPUT +#define YY_NO_UNPUT +#endif + +#define MAX_INCLUDE_DEPTH 10 +static YY_BUFFER_STATE@, @[include_stack[MAX_INCLUDE_DEPTH]@]; +static const char *file_name_stack[MAX_INCLUDE_DEPTH]; +static unsigned int lineno_stack[MAX_INCLUDE_DEPTH]; +static unsigned int sysrooted_stack[MAX_INCLUDE_DEPTH]; +static unsigned int include_stack_ptr = 0; +static int vers_node_nesting = 0; + +static int yy_input (char *, int); +static void comment (void); +static void lex_warn_invalid (char *where, char *what); + +#define RTOKEN(x) { yylval.token = x; return x; } + +#ifndef yywrap +int yywrap (void) { return 1; }/* Some versions of \flex\ want this. */ +#endif + +@ @<Ignored options@>= +@G +%a 4000 +%o 5000 +@g + +@ {\it Some convenient abbreviations for regular expressions.}% +\ifbootstrapmode\else\yyskipparsetrue\fi@<Original \ld\ macros@>= +@G +CMDFILENAMECHAR [_a-zA-Z0-9\/\.\\_\+\$\:\[\]\\\,\=\&\!\<\>\-\~] +CMDFILENAMECHAR1 [_a-zA-Z0-9\/\.\\_\+\$\:\[\]\\\,\=\&\!\<\>\~] +FILENAMECHAR1 [_a-zA-Z\/\.\\\$\_\~] +SYMBOLCHARN [_a-zA-Z\/\.\\\$\_\~0-9] +FILENAMECHAR [_a-zA-Z0-9\/\.\-\_\+\=\$\:\[\]\\\,\~] +WILDCHAR [_a-zA-Z0-9\/\.\-\_\+\=\$\:\[\]\\\,\~\?\*\^\!] +WHITE [ \t\n\r]+ +NOCFILENAMECHAR [_a-zA-Z0-9\/\.\-\_\+\$\:\[\]\\\~] +V_TAG [.$_a-zA-Z][._a-zA-Z0-9]* +V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)* +@g + +@ {% +\def\aterm{\item{\sqbullet}\ignorespaces}% +\setbox0=\hbox{\sqbullet\enspace}% +\parindent=0pt +\advance\parindent by \wd0 +States: +\aterm |EXPRESSION| definitely in an expression + +\aterm |SCRIPT| definitely in a script + +\aterm |BOTH| either |EXPRESSION| or |SCRIPT| + +\aterm |DEFSYMEXP| in an argument to \.{--defsym} + +\aterm |MRI| in an \MRI\ script + +\aterm |VERS_START| starting a Sun style mapfile + +\aterm |VERS_SCRIPT| a Sun style mapfile + +\aterm |VERS_NODE| a node within a Sun style mapfile + +}% +\ifbootstrapmode\else\yyskipparsefalse\fi +@<\ld\ states@>= +@G +%s SCRIPT +%s EXPRESSION +%s BOTH +%s DEFSYMEXP +%s MRI +%s VERS_START +%s VERS_SCRIPT +%s VERS_NODE +@g + +@ @<\ld\ postamble@>= + if (parser_input != input_selected) + { + /* The first token of the input determines the initial parser state. */ + input_type t = parser_input; + parser_input = input_selected; + switch (t) + { + case input_script: return INPUT_SCRIPT; break; + case input_mri_script: return INPUT_MRI_SCRIPT; break; + case input_version_script: return INPUT_VERSION_SCRIPT; break; + case input_dynamic_list: return INPUT_DYNAMIC_LIST; break; + case input_defsym: return INPUT_DEFSYM; break; + default: abort (); + } +} + +@ @<Original \ld\ regular expressions@>= +@=<BOTH,SCRIPT,EXPRESSION,VERS_START,VERS_NODE,VERS_SCRIPT>"/*" {@> comment ();@+@=}@>@; +@G +<DEFSYMEXP>"-" {@>@[RTOKEN('-');@]@=} +<DEFSYMEXP>"+" {@>@[RTOKEN('+');@]@=} +<DEFSYMEXP>{FILENAMECHAR1}{SYMBOLCHARN}* {@>@[yylval.name = xstrdup (yytext);@+return NAME;@]@=} +<DEFSYMEXP>"=" {@>@[RTOKEN('=');@]@=} + +<MRI,EXPRESSION>"$"([0-9A-Fa-f])+ { +@O + yylval.integer = bfd_scan_vma (yytext + 1, 0, 16); + yylval.bigint.str = NULL; + return INT; +@o +} + +<MRI,EXPRESSION>([0-9A-Fa-f])+(H|h|X|x|B|b|O|o|D|d) { +@O + int ibase ; + switch (yytext[yyleng - 1]) { + case 'X': + case 'x': + case 'H': + case 'h': + ibase = 16; + break; + case 'O': + case 'o': + ibase = 8; + break; + case 'B': + case 'b': + ibase = 2; + break; + default: + ibase = 10; + } + yylval.integer = bfd_scan_vma (yytext, 0, + ibase); + yylval.bigint.str = NULL; + return INT; +@o +} + +<SCRIPT,DEFSYMEXP,MRI,BOTH,EXPRESSION>((("$"|0[xX])([0-9A-Fa-f])+)|(([0-9])+))(M|K|m|k)? { +@O + char *s = yytext; + int ibase = 0; + + if (*s == '$') + { + ++s; + ibase = 16; + } + yylval.integer = bfd_scan_vma (s, 0, ibase); + yylval.bigint.str = NULL; + if (yytext[yyleng - 1] == 'M' + || yytext[yyleng - 1] == 'm') + { + yylval.integer *= 1024 * 1024; + } + else if (yytext[yyleng - 1] == 'K' + || yytext[yyleng - 1]=='k') + { + yylval.integer *= 1024; + } + else if (yytext[0] == '0' + && (yytext[1] == 'x' + || yytext[1] == 'X')) + { + yylval.bigint.str = xstrdup (yytext + 2); + } + return INT; +@o +} + +<BOTH,SCRIPT,EXPRESSION,MRI>"]" {@>@[RTOKEN(']');@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"[" {@>@[RTOKEN('[');@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"<<=" {@>@[RTOKEN(LSHIFTEQ);@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>">>=" {@>@[RTOKEN(RSHIFTEQ);@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"||" {@>@[RTOKEN(OROR);@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"==" {@>@[RTOKEN(EQ);@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"!=" {@>@[RTOKEN(NE);@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>">=" {@>@[RTOKEN(GE);@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"<=" {@>@[RTOKEN(LE);@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"<<" {@>@[RTOKEN(LSHIFT);@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>">>" {@>@[RTOKEN(RSHIFT);@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"+=" {@>@[RTOKEN(PLUSEQ);@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"-=" {@>@[RTOKEN(MINUSEQ);@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"*=" {@>@[RTOKEN(MULTEQ);@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"/=" {@>@[RTOKEN(DIVEQ);@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"&=" {@>@[RTOKEN(ANDEQ);@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"|=" {@>@[RTOKEN(OREQ);@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"&&" {@>@[RTOKEN(ANDAND);@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>">" {@>@[RTOKEN('>');@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"," {@>@[RTOKEN(',');@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"&" {@>@[RTOKEN('&');@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"|" {@>@[RTOKEN('|');@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"~" {@>@[RTOKEN('~');@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"!" {@>@[RTOKEN('!');@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"?" {@>@[RTOKEN('?');@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"*" {@>@[RTOKEN('*');@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"+" {@>@[RTOKEN('+');@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"-" {@>@[RTOKEN('-');@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"/" {@>@[RTOKEN('/');@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"%" {@>@[RTOKEN('%');@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"<" {@>@[RTOKEN('<');@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"=" {@>@[RTOKEN('=');@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"}" {@>@[RTOKEN('}') ; @]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"{" {@>@[RTOKEN('{'); @]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>")" {@>@[RTOKEN(')');@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>"(" {@>@[RTOKEN('(');@]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>":" {@>@[RTOKEN(':'); @]@=} +<BOTH,SCRIPT,EXPRESSION,MRI>";" {@>@[RTOKEN(';');@]@=} +<BOTH,SCRIPT>"MEMORY" {@>@[RTOKEN(MEMORY);@]@=} +<BOTH,SCRIPT>"REGION_ALIAS" {@>@[RTOKEN(REGION_ALIAS);@]@=} +<BOTH,SCRIPT>"LD_FEATURE" {@>@[RTOKEN(LD_FEATURE);@]@=} +<BOTH,SCRIPT,EXPRESSION>"ORIGIN" {@>@[RTOKEN(ORIGIN);@]@=} +<BOTH,SCRIPT>"VERSION" {@>@[RTOKEN(VERSIONK);@]@=} +<EXPRESSION,BOTH,SCRIPT>"BLOCK" {@>@[RTOKEN(BLOCK);@]@=} +<EXPRESSION,BOTH,SCRIPT>"BIND" {@>@[RTOKEN(BIND);@]@=} +<BOTH,SCRIPT,EXPRESSION>"LENGTH" {@>@[RTOKEN(LENGTH);@]@=} +<EXPRESSION,BOTH,SCRIPT>"ALIGN" {@>@[RTOKEN(ALIGN_K);@]@=} +<EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_ALIGN" {@>@[RTOKEN(DATA_SEGMENT_ALIGN);@]@=} +<EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_RELRO_END" {@>@[RTOKEN(DATA_SEGMENT_RELRO_END);@]@=} +<EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_END" {@>@[RTOKEN(DATA_SEGMENT_END);@]@=} +<EXPRESSION,BOTH,SCRIPT>"ADDR" {@>@[RTOKEN(ADDR);@]@=} +<EXPRESSION,BOTH,SCRIPT>"LOADADDR" {@>@[RTOKEN(LOADADDR);@]@=} +<EXPRESSION,BOTH,SCRIPT>"ALIGNOF" {@>@[RTOKEN(ALIGNOF); @]@=} +<EXPRESSION,BOTH>"MAX" {@>@[RTOKEN(MAX_K); @]@=} +<EXPRESSION,BOTH>"MIN" {@>@[RTOKEN(MIN_K); @]@=} +<EXPRESSION,BOTH>"LOG2CEIL" {@>@[RTOKEN(LOG2CEIL); @]@=} +<EXPRESSION,BOTH,SCRIPT>"ASSERT" {@>@[RTOKEN(ASSERT_K); @]@=} +<BOTH,SCRIPT>"ENTRY" {@>@[RTOKEN(ENTRY);@]@=} +<BOTH,SCRIPT,MRI>"EXTERN" {@>@[RTOKEN(EXTERN);@]@=} +<EXPRESSION,BOTH,SCRIPT>"NEXT" {@>@[RTOKEN(NEXT);@]@=} +<EXPRESSION,BOTH,SCRIPT>"sizeof_headers" {@>@[RTOKEN(SIZEOF_HEADERS);@]@=} +<EXPRESSION,BOTH,SCRIPT>"SIZEOF_HEADERS" {@>@[RTOKEN(SIZEOF_HEADERS);@]@=} +<EXPRESSION,BOTH,SCRIPT>"SEGMENT_START" {@>@[RTOKEN(SEGMENT_START);@]@=} +<BOTH,SCRIPT>"MAP" {@>@[RTOKEN(MAP);@]@=} +<EXPRESSION,BOTH,SCRIPT>"SIZEOF" {@>@[RTOKEN(SIZEOF);@]@=} +<BOTH,SCRIPT>"TARGET" {@>@[RTOKEN(TARGET_K);@]@=} +<BOTH,SCRIPT>"SEARCH_DIR" {@>@[RTOKEN(SEARCH_DIR);@]@=} +<BOTH,SCRIPT>"OUTPUT" {@>@[RTOKEN(OUTPUT);@]@=} +<BOTH,SCRIPT>"INPUT" {@>@[RTOKEN(INPUT);@]@=} +<EXPRESSION,BOTH,SCRIPT>"GROUP" {@>@[RTOKEN(GROUP);@]@=} +<EXPRESSION,BOTH,SCRIPT>"AS_NEEDED" {@>@[RTOKEN(AS_NEEDED);@]@=} +<EXPRESSION,BOTH,SCRIPT>"DEFINED" {@>@[RTOKEN(DEFINED);@]@=} +<BOTH,SCRIPT>"CREATE_OBJECT_SYMBOLS" {@>@[RTOKEN(CREATE_OBJECT_SYMBOLS);@]@=} +<BOTH,SCRIPT>"CONSTRUCTORS" {@>@[RTOKEN( CONSTRUCTORS);@]@=} +<BOTH,SCRIPT>"FORCE_COMMON_ALLOCATION" {@>@[RTOKEN(FORCE_COMMON_ALLOCATION);@]@=} +<BOTH,SCRIPT>"INHIBIT_COMMON_ALLOCATION" {@>@[RTOKEN(INHIBIT_COMMON_ALLOCATION);@]@=} +<BOTH,SCRIPT>"SECTIONS" {@>@[RTOKEN(SECTIONS);@]@=} +<BOTH,SCRIPT>"INSERT" {@>@[RTOKEN(INSERT_K);@]@=} +<BOTH,SCRIPT>"AFTER" {@>@[RTOKEN(AFTER);@]@=} +<BOTH,SCRIPT>"BEFORE" {@>@[RTOKEN(BEFORE);@]@=} +<BOTH,SCRIPT>"FILL" {@>@[RTOKEN(FILL);@]@=} +<BOTH,SCRIPT>"STARTUP" {@>@[RTOKEN(STARTUP);@]@=} +<BOTH,SCRIPT>"OUTPUT_FORMAT" {@>@[RTOKEN(OUTPUT_FORMAT);@]@=} +<BOTH,SCRIPT>"OUTPUT_ARCH" {@>@[RTOKEN( OUTPUT_ARCH);@]@=} +<BOTH,SCRIPT>"HLL" {@>@[RTOKEN(HLL);@]@=} +<BOTH,SCRIPT>"SYSLIB" {@>@[RTOKEN(SYSLIB);@]@=} +<BOTH,SCRIPT>"FLOAT" {@>@[RTOKEN(FLOAT);@]@=} +<BOTH,SCRIPT>"QUAD" {@>@[RTOKEN( QUAD);@]@=} +<BOTH,SCRIPT>"SQUAD" {@>@[RTOKEN( SQUAD);@]@=} +<BOTH,SCRIPT>"LONG" {@>@[RTOKEN( LONG);@]@=} +<BOTH,SCRIPT>"SHORT" {@>@[RTOKEN( SHORT);@]@=} +<BOTH,SCRIPT>"BYTE" {@>@[RTOKEN( BYTE);@]@=} +<BOTH,SCRIPT>"NOFLOAT" {@>@[RTOKEN(NOFLOAT);@]@=} +<EXPRESSION,BOTH,SCRIPT>"NOCROSSREFS" {@>@[RTOKEN(NOCROSSREFS);@]@=} +<BOTH,SCRIPT>"OVERLAY" {@>@[RTOKEN(OVERLAY); @]@=} +<BOTH,SCRIPT>"SORT_BY_NAME" {@>@[RTOKEN(SORT_BY_NAME); @]@=} +<BOTH,SCRIPT>"SORT_BY_ALIGNMENT" {@>@[RTOKEN(SORT_BY_ALIGNMENT); @]@=} +<BOTH,SCRIPT>"SORT" {@>@[RTOKEN(SORT_BY_NAME); @]@=} +<BOTH,SCRIPT>"SORT_BY_INIT_PRIORITY" {@>@[RTOKEN(SORT_BY_INIT_PRIORITY); @]@=} +<BOTH,SCRIPT>"SORT_NONE" {@>@[RTOKEN(SORT_NONE); @]@=} +<EXPRESSION,BOTH,SCRIPT>"NOLOAD" {@>@[RTOKEN(NOLOAD);@]@=} +<EXPRESSION,BOTH,SCRIPT>"DSECT" {@>@[RTOKEN(DSECT);@]@=} +<EXPRESSION,BOTH,SCRIPT>"COPY" {@>@[RTOKEN(COPY);@]@=} +<EXPRESSION,BOTH,SCRIPT>"INFO" {@>@[RTOKEN(INFO);@]@=} +<EXPRESSION,BOTH,SCRIPT>"OVERLAY" {@>@[RTOKEN(OVERLAY);@]@=} +<EXPRESSION,BOTH,SCRIPT>"ONLY_IF_RO" {@>@[RTOKEN(ONLY_IF_RO); @]@=} +<EXPRESSION,BOTH,SCRIPT>"ONLY_IF_RW" {@>@[RTOKEN(ONLY_IF_RW); @]@=} +<EXPRESSION,BOTH,SCRIPT>"SPECIAL" {@>@[RTOKEN(SPECIAL); @]@=} +<BOTH,SCRIPT>"o" {@>@[RTOKEN(ORIGIN);@]@=} +<BOTH,SCRIPT>"org" {@>@[RTOKEN(ORIGIN);@]@=} +<BOTH,SCRIPT>"l" {@>@[RTOKEN( LENGTH);@]@=} +<BOTH,SCRIPT>"len" {@>@[RTOKEN( LENGTH);@]@=} +<EXPRESSION,BOTH,SCRIPT>"INPUT_SECTION_FLAGS" {@>@[RTOKEN(INPUT_SECTION_FLAGS); @]@=} +<EXPRESSION,BOTH,SCRIPT>"INCLUDE" {@>@[RTOKEN(INCLUDE);@]@=} +<BOTH,SCRIPT>"PHDRS" {@>@[RTOKEN (PHDRS); @]@=} +<EXPRESSION,BOTH,SCRIPT>"AT" {@>@[RTOKEN(AT);@]@=} +<EXPRESSION,BOTH,SCRIPT>"ALIGN_WITH_INPUT" {@>@[RTOKEN(ALIGN_WITH_INPUT);@]@=} +<EXPRESSION,BOTH,SCRIPT>"SUBALIGN" {@>@[RTOKEN(SUBALIGN);@]@=} +<EXPRESSION,BOTH,SCRIPT>"HIDDEN" {@>@[RTOKEN(HIDDEN); @]@=} +<EXPRESSION,BOTH,SCRIPT>"PROVIDE" {@>@[RTOKEN(PROVIDE); @]@=} +<EXPRESSION,BOTH,SCRIPT>"PROVIDE_HIDDEN" {@>@[RTOKEN(PROVIDE_HIDDEN); @]@=} +<EXPRESSION,BOTH,SCRIPT>"KEEP" {@>@[RTOKEN(KEEP); @]@=} +<EXPRESSION,BOTH,SCRIPT>"EXCLUDE_FILE" {@>@[RTOKEN(EXCLUDE_FILE); @]@=} +<EXPRESSION,BOTH,SCRIPT>"CONSTANT" {@>@[RTOKEN(CONSTANT);@]@=} +<MRI>"#".*\n? {@>@[++ lineno; @]@=} +<MRI>"\n" {@> @[++lineno;@+RTOKEN(NEWLINE);@]@=} +<MRI>"*".* {}/* \MRI\ comment line */ +<MRI>";".* {}/* \MRI\ comment line */ +<MRI>"END" {@>@[RTOKEN(ENDWORD); @]@=} +<MRI>"ALIGNMOD" {@>@[RTOKEN(ALIGNMOD);@]@=} +<MRI>"ALIGN" {@>@[RTOKEN(ALIGN_K);@]@=} +<MRI>"CHIP" {@>@[RTOKEN(CHIP); @]@=} +<MRI>"BASE" {@>@[RTOKEN(BASE); @]@=} +<MRI>"ALIAS" {@>@[RTOKEN(ALIAS); @]@=} +<MRI>"TRUNCATE" {@>@[RTOKEN(TRUNCATE); @]@=} +<MRI>"LOAD" {@>@[RTOKEN(LOAD); @]@=} +<MRI>"PUBLIC" {@>@[RTOKEN(PUBLIC); @]@=} +<MRI>"ORDER" {@>@[RTOKEN(ORDER); @]@=} +<MRI>"NAME" {@>@[RTOKEN(NAMEWORD); @]@=} +<MRI>"FORMAT" {@>@[RTOKEN(FORMAT); @]@=} +<MRI>"CASE" {@>@[RTOKEN(CASE); @]@=} +<MRI>"START" {@>@[RTOKEN(START); @]@=} +<MRI>"LIST".* {@>@[RTOKEN(LIST); @]@=}/* \prodstyle{LIST} and ignore to end of line */ +<MRI>"SECT" {@>@[RTOKEN(SECT); @]@=} +<EXPRESSION,BOTH,SCRIPT,MRI>"ABSOLUTE" {@>@[RTOKEN(ABSOLUTE); @]@=} +<MRI>"end" {@>@[RTOKEN(ENDWORD); @]@=} +<MRI>"alignmod" {@>@[RTOKEN(ALIGNMOD);@]@=} +<MRI>"align" {@>@[RTOKEN(ALIGN_K);@]@=} +<MRI>"chip" {@>@[RTOKEN(CHIP); @]@=} +<MRI>"base" {@>@[RTOKEN(BASE); @]@=} +<MRI>"alias" {@>@[RTOKEN(ALIAS); @]@=} +<MRI>"truncate" {@>@[RTOKEN(TRUNCATE); @]@=} +<MRI>"load" {@>@[RTOKEN(LOAD); @]@=} +<MRI>"public" {@>@[RTOKEN(PUBLIC); @]@=} +<MRI>"order" {@>@[RTOKEN(ORDER); @]@=} +<MRI>"name" {@>@[RTOKEN(NAMEWORD); @]@=} +<MRI>"format" {@>@[RTOKEN(FORMAT); @]@=} +<MRI>"case" {@>@[RTOKEN(CASE); @]@=} +<MRI>"extern" {@>@[RTOKEN(EXTERN); @]@=} +<MRI>"start" {@>@[RTOKEN(START); @]@=} +<MRI>"list".* {@>@[RTOKEN(LIST); @]@=}/* \prodstyle{LIST} and ignore to end of line */ +<MRI>"sect" {@>@[RTOKEN(SECT); @]@=} +<EXPRESSION,BOTH,SCRIPT,MRI>"absolute" {@>@[RTOKEN(ABSOLUTE); @]@=} + +<MRI>{FILENAMECHAR1}{NOCFILENAMECHAR}* { +@O +/* Filename without commas, needed to parse \MRI\ stuff */ + yylval.name = xstrdup (yytext); + return NAME; +@o +} +<BOTH>{FILENAMECHAR1}{FILENAMECHAR}* { +@O + yylval.name = xstrdup (yytext); + return NAME; +@o +} +<BOTH>"-l"{FILENAMECHAR}+ { +@O + yylval.name = xstrdup (yytext + 2); + return LNAME; +@o +} +<EXPRESSION>{FILENAMECHAR1}{NOCFILENAMECHAR}* { +@O + yylval.name = xstrdup (yytext); + return NAME; +@o +} +<EXPRESSION>"-l"{NOCFILENAMECHAR}+ { +@O + yylval.name = xstrdup (yytext + 2); + return LNAME; +@o +} +<SCRIPT>{WILDCHAR}* { +@O + /* Annoyingly, this pattern can match comments, and we have + longest match issues to consider. So if the first two + characters are a comment opening, put the input back and + try again. */ + if (yytext[0] == '/' && yytext[1] == '*') + { + yyless (2); + comment (); + } + else + { + yylval.name = xstrdup (yytext); + return NAME; + } +@o +} + +<EXPRESSION,BOTH,SCRIPT,VERS_NODE>"\""[^\"]*"\"" { +@O + /* No matter the state, quotes + give what's inside */ + yylval.name = xstrdup (yytext + 1); + yylval.name[yyleng - 2] = 0; + return NAME; +@o +} + +<BOTH,SCRIPT,EXPRESSION>"\n" {@>@[lineno++;@]@=} +<MRI,BOTH,SCRIPT,EXPRESSION>[ \t\r]+ {} + +<VERS_NODE,VERS_SCRIPT>[:,;] {@>@[return *yytext; @]@=} +<VERS_NODE>global {@>@[RTOKEN(GLOBAL); @]@=} +<VERS_NODE>local {@>@[RTOKEN(LOCAL); @]@=} +<VERS_NODE>extern {@>@[RTOKEN(EXTERN); @]@=} + +<VERS_NODE>{V_IDENTIFIER} { +@O + yylval.name = xstrdup (yytext); + return VERS_IDENTIFIER; +@o +} + +<VERS_SCRIPT>{V_TAG} { +@O + yylval.name = xstrdup (yytext); + return VERS_TAG; +@o +} + +<VERS_START>"{" {@>@[BEGIN(VERS_SCRIPT);@+return *yytext;@]@=} + +<VERS_SCRIPT>"{" { +@O + BEGIN(VERS_NODE); + vers_node_nesting = 0; + return *yytext; +@o +} + +<VERS_SCRIPT>"}" {@>@[return *yytext;@]@=} +<VERS_NODE>"{" {@>@[vers_node_nesting++;@+return *yytext;@]@=} + +<VERS_NODE>"}" { +@O + if (--vers_node_nesting < 0) + BEGIN(VERS_SCRIPT); + return *yytext; +@o +} + +<VERS_START,VERS_NODE,VERS_SCRIPT>[\n] {@>@[lineno++;@]@=} +<VERS_START,VERS_NODE,VERS_SCRIPT>#.* {}/* Eat up comments */ +<VERS_START,VERS_NODE,VERS_SCRIPT>[ \t\r]+ {}/* Eat up whitespace */ + +<<EOF>> { +@O + include_stack_ptr--; + if (include_stack_ptr == 0) + yyterminate (); + else + yy_switch_to_buffer (include_stack[include_stack_ptr]); + + lineno = lineno_stack[include_stack_ptr]; + input_flags.sysrooted = sysrooted_stack[include_stack_ptr]; + + return END; +@o +} + +<SCRIPT,MRI,VERS_START,VERS_SCRIPT,VERS_NODE>. @>@[lex_warn_invalid (" in script", yytext);@] +<EXPRESSION,DEFSYMEXP,BOTH>. @>@[lex_warn_invalid (" in expression", yytext);@] +@g + +@ Switch \flex\ to reading script file |name|, open on |file|, +saving the current input info on the include stack. +@<Supporting \Cee\ code@>= +void +lex_push_file (FILE *file, const char *name, unsigned int sysrooted) +{ + if (include_stack_ptr >= MAX_INCLUDE_DEPTH) + { + einfo ("%F:includes nested too deeply\n"); + } + file_name_stack[include_stack_ptr] = name; + lineno_stack[include_stack_ptr] = lineno; + sysrooted_stack[include_stack_ptr] = input_flags.sysrooted; + include_stack[include_stack_ptr] = YY_CURRENT_BUFFER; + + include_stack_ptr++; + lineno = 1; + input_flags.sysrooted = sysrooted; + yyin = file; + yy_switch_to_buffer (yy_create_buffer (yyin, YY_BUF_SIZE)); +} + +@ Return a newly created \flex\ input buffer containing |string|, +which is |size| bytes long. +@<Supporting \Cee\ code@>= +static YY_BUFFER_STATE +yy_create_string_buffer (const char *string, size_t size) +{ + YY_BUFFER_STATE b; + + b = malloc (sizeof (struct yy_buffer_state));/* Calls to |malloc| get turned by sed into |xmalloc|. */ + b->yy_input_file = 0; + b->yy_buf_size = size; + + b->yy_ch_buf = malloc ((unsigned) (b->yy_buf_size + 3)); + /* |yy_ch_buf| has to be 2 characters longer than the size given because + we need to put in 2 end-of-buffer characters. */ + + b->yy_ch_buf[0] = '\n'; + strcpy (b->yy_ch_buf+1, string); + b->yy_ch_buf[size+1] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[size+2] = YY_END_OF_BUFFER_CHAR; + b->yy_n_chars = size+1; + b->yy_buf_pos = &b->yy_ch_buf[1]; + + b->yy_is_our_buffer = 1; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + +#ifdef YY_BUFFER_NEW + b->yy_buffer_status = YY_BUFFER_NEW; +#else + b->yy_eof_status = EOF_NOT_SEEN; +#endif + + return b; +} + +@ Switch \flex\ to reading from |string|, saving the current input info +on the include stack. +@<Supporting \Cee\ code@>= +void +lex_redirect (const char *string, const char *fake_filename, unsigned int count) +{ + YY_BUFFER_STATE tmp; + + yy_init = 0; + if (include_stack_ptr >= MAX_INCLUDE_DEPTH) + { + einfo("%F: macros nested too deeply\n"); + } + file_name_stack[include_stack_ptr] = fake_filename; + lineno_stack[include_stack_ptr] = lineno; + include_stack[include_stack_ptr] = YY_CURRENT_BUFFER; + include_stack_ptr++; + lineno = count; + tmp = yy_create_string_buffer (string, strlen (string)); + yy_switch_to_buffer (tmp); +} + +@ Functions to switch to a different \flex\ start condition, +saving the current start condition on |state_stack|. +@<Supporting \Cee\ code@>= +static int state_stack[MAX_INCLUDE_DEPTH * 2]; +static int *state_stack_p = state_stack; + +void +ldlex_script (void) +{ + *(state_stack_p)++ = yy_start; + BEGIN (SCRIPT); +} + +void +ldlex_mri_script (void) +{ + *(state_stack_p)++ = yy_start; + BEGIN (MRI); +} + +void +ldlex_version_script (void) +{ + *(state_stack_p)++ = yy_start; + BEGIN (VERS_START); +} + +void +ldlex_version_file (void) +{ + *(state_stack_p)++ = yy_start; + BEGIN (VERS_SCRIPT); +} + +void +ldlex_defsym (void) +{ + *(state_stack_p)++ = yy_start; + BEGIN (DEFSYMEXP); +} + +void +ldlex_expression (void) +{ + *(state_stack_p)++ = yy_start; + BEGIN (EXPRESSION); +} + +void +ldlex_both (void) +{ + *(state_stack_p)++ = yy_start; + BEGIN (BOTH); +} + +void +ldlex_popstate (void) +{ + yy_start = *(--state_stack_p); +} + +@ Return the current file name, or the previous file if no file is +current. +@<Supporting \Cee\ code@>= +const char* +ldlex_filename (void) +{ + return file_name_stack[include_stack_ptr - (include_stack_ptr != 0)]; +} + +@ Place up to |max_size| characters in |buf| and return +either the number of characters read, or 0 to indicate |EOF|. +@<Supporting \Cee\ code@>= +static int +yy_input (char *buf, int max_size) +{ + int result = 0; + if (YY_CURRENT_BUFFER->yy_input_file) + { + if (yyin) + { + result = fread (buf, 1, max_size, yyin); + if (result < max_size && ferror (yyin)) + einfo ("%F%P: read in flex scanner failed\n"); + } + } + return result; +} + +@ Eat the rest of a \Cee-style comment. +@<Supporting \Cee\ code@>= +static void +comment (void) +{ + int c; + + while (1) + { + c = input(); + while (c != '*' && c != EOF) + { + if (c == '\n') + lineno++; + c = input(); + } + + if (c == '*') + { + c = input(); + while (c == '*') + c = input(); + if (c == '/') + break; /* found the end */ + } + + if (c == '\n') + lineno++; + + if (c == EOF) + { + einfo( "%F%P: EOF in comment\n"); + break; + } + } +} + +@ Warn the user about a garbage character |what| in the input +in context |where|. +@<Supporting \Cee\ code@>= +static void +lex_warn_invalid (char *where, char *what) +{ + char buf[5]; + + if (ldfile_assumed_script) + { /* If we have found an input file whose format we do not recognize, + and we are therefore treating it as a linker script, and we find + an invalid character, then most likely this is a real object file + of some different format. Treat it as such. */ + + bfd_set_error (bfd_error_file_not_recognized); + einfo ("%F%s: file not recognized: %E\n", ldlex_filename ()); + } + + if (! ISPRINT (*what)) + { + sprintf (buf, "\\%03o", *(unsigned char *) what); + what = buf; + } + + einfo ("%P:%S: ignoring invalid character `%s'%s\n", NULL, what, where); +} diff --git a/support/splint/examples/ld/ldman.w b/support/splint/examples/ld/ldman.w new file mode 100644 index 0000000000..c9551d1b3e --- /dev/null +++ b/support/splint/examples/ld/ldman.w @@ -0,0 +1,572 @@ +% Copyright 2012-2015, Alexander Shibakov +% Copyright 2002-2014 Free Software Foundation, Inc. +% This file is part of SPLinT +% +% SPLinT 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. +% +% SPLinT 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 SPLinT. If not, see <http://www.gnu.org/licenses/>. +@s TeX_ TeX +\input limbo.sty +\input ldfrontmatter.sty +\def\MRI{{\sc MRI}} +\def\optimization{5} +\input ldman.sty +% multi-column output +\input dcols.sty + +\let\oldN\N +\let\N\textN +\let\M\textM +\def\ld{\.{ld}} + +\showlastactiontrue +\immediate\openout\gindex=\jobname.gdx +@** Introduction. +\setupfootnotes +This is a manual documenting the development of a parser that can be +used to typeset \ld\ files (linker scripts) with or without the help +of \CWEB. An existing parser for \ld\ has been adopted as a base, with +appropriately designed actions specific to the task of +typesetting. The appendix to this manual contains the full source code +(including the parts written in \Cee) of both the scanner and the parser for \ld, +used in the original program. Some very minor modifications have been +made to make the programs more `presentable' in \CWEB\ (in particular, the +file had to be split into smaller chunks to satisfy \CWEAVE's +limitations). + +Nearly every aspect of the design is discussed, including the +supporting \TeX\ macros that make both the parser and this +documentation possible. The \TeX\ macros presented here are collected +in \.{ldman.sty} which is later included in the \TeX\ file produced by \CWEAVE. +@<Set up the generic parser machinery@>= +@G +\ifx\optimization\UNDEFINED %/* this trick is based on the premise that \.{\\UNDEFINED} */ + \def\optimization{0} %/* is never defined nor created with \.{\\csname$\ldots$\\endcsname} */ +\fi + +\let\nx\noexpand %/* convenient */ + +\input yycommon.sty %/* general routines for stack and array access */ +\input yymisc.sty %/* helper macros (stack manipulation, table processing, value stack pointers) */ +\input yyinput.sty %/* input functions */ +\input yyparse.sty %/* parser machinery */ +\input flex.sty %/* lexer functions */ +\input yyboth.sty %/* parser initialization, optimization */ + +\ifnum\optimization>\tw@ + \input yyfaststack.sty +\fi + +\input yystype.sty %/* scanner auxiliary types and functions */ +\input yyunion.sty %/* parser data structures */ +\input yxunion.sty %/* extended parser data structures */ +@=\input ldunion.sty %@>/* \ld\ parser data structures */@+ +@g + +@*1 Bootstrapping. +To produce a usable parser/scanner duo, several pieces of code must +be generated. The most important of these are the {\it table files\/} +(\.{ptab.tex} and \.{ltab.tex}) for the parser and the scanner. These +consist of the integer tables defining the operation of the parser and +scanner automata, the values of some constants, and the `action switch'. + +Just like in the case of `real' parsers and scanners, in order to +make the parser and the scanner interact seamlessly, some amount of `glue' +is required. As an example, a file containing the (numerical) +definitions of the token values is generated by \bison\ to be used by +a \flex\ generated scanner. Unfortunately, this file has too little +structure for our purposes (it contains definitions of token values +mixed in with other constants making it hard to distinguish one kind of +definition from another). Therefore, the `glue' is generated by +parsing our grammar once again, this time with a \bison\ grammar +designed for typesetting \bison\ files. A special {\it +bootstrapping\/} mode is used to extract the appropriate +information. The name `bootstrapping' notwithstanding, the parser and +lexer used in the bootstrapping phase are not the minimized versions +used in bootstrapping the \bison\ parser. + +The first component generated during the bootstrapping pass is a list +of `token equivalences' (or `aliases') to be used by the lexer. Every +token (to be precise, every {\it named token type}) used in +a \bison\ grammar is declared using one of the +\prodstyle{\%token}, \prodstyle{\%left}, \prodstyle{\%right}, +\prodstyle{\%precedence}, or \prodstyle{\%nonassoc} declarations. If +no {\it alias\/} (see below) has been declared using a +\prodstyle{\%token} declaration, this name ends up in the |yytname| +array output by \bison\ and can be used by the lexer after associating +the token names with their numerical values (accomplished by +\.{\\settokens}). If all tokens are named tokens, no token equivalence +list is necessary to set up the interaction between the lexer and the +parser. In this case (the present \ld\ parser is a typical +example), the token list serves a secondary role: it provides hints +for the macros that typeset the grammar terms, after the \.{\\tokeneq} +macro is redefined to serve this purpose. + +On the other hand, after a declaration such as `\prodstyle{\%token} +\.{CHAR} \.{"char"}' the string \.{"char"} becomes an alias +for the named token \.{CHAR}. Only the string version gets recorded in +the |yytname| array. Establishing the equivalence between the two +token forms can now only be accomplished by examining the grammar +source file and is delegated to the bootstrapping phase parser. + +\leavevmode\namedspot{bootstrapstates}The other responsibility of the bootstrapping parser is to extract +the information about \flex\ {\it states\/} used by the lexer from the +appropriate source file. As is the case with token names, this +information is output in a rather chaotic fashion by the scanner +generator and is all but useless for our purposes. The original +bootstrapping macros were designed to handle \flex's \prodstyle{\%x} +and \prodstyle{\%s} state declarations and produce a \Cee\ file with the +appropriate definitions. This file can later be included by the +`driver' routine to produce the appropriate table file for the lexer. +To round off the bootstrapping mode we only need to establish the +output streams for the tokens and the states, supply the appropriate file +names for the two lists, flag the bootstrapping mode for the +bootstrapping macros and inline typesetting (\.{\\prodstyle} macros) +and input the appropriate machinery. + +This is done by the macros +below. The bootstrap lexer setup (\.{\\bootstraplexersetup}) consists +of inputting the token equivalence table for the \bison\ parser +(i.e.~the parser that processes the \bison\ grammar file) and defining +a robust token output function which simply ignores the token values +the lexer is not aware of (it should not be necessary in our case +since we are using full featured lexer and parser). +@<Define the bootstrapping mode@>= +@G +\newwrite\tokendefs %/* token list */ +\newwrite\stlist %/* \flex\ state list */ +\newwrite\gindex %/* index entries */ + +\def\modebootstrap{% + \edef\bstrapparser{dyytab.tex}% + \bootstrapmodetrue + \def\bootstraplexersetup{% + \input bo.tok% + \let\yylexreturn\yylexreturnbootstrap /* only return tokens whose value is known */ + %\let\yylexreturn\yylexreturnregular /* should also work */ + }% + \input yybootstrap.sty% +} +@g + +@*1 Namespaces and modes. +Every parser/lexer pair (as well as some other macros) operates +within a dedicated {\it namespace\/}. This simply means that the macros +that output token values, switch lexer states and access various +tables `tack on' the string of characters representing the current +namespace to the `low level' control sequence name that performs the +actual output or access. Say, \.{\\yytname} becomes an alias of +\.{\\yytname[main]} while in the \.{[main]} namespace. When a parser +or lexer is initialized, the appropriate tables are aliased with a +generic name in the case of an `unoptimized' parser or lexer. The +optimized parser or lexer handles the namespace referencing internally. + +The mode setup macros for this manual define several separate +namespaces. The \.{[main]} namespace is established for the parser +that does the typesetting of the grammar. Every time a term name is +processed, the token names are looked up in the \.{[ld]} +namespace. The same namespace is used by the parser that typesets \ld\ +script examples in the manual (i.e.~the parser described here). This +is done to provide visual consistency between the description of the +parser and its output. The \.{[small]} namespace is used by the term +name parser itself. Since we use a customized version of the name parser, we +dedicate a separate namespace for this purpose, \.{[ldsmall]}. +The parser based on a subset of the full \bison\ +grammar describing prologue declarations uses the \.{[prologue]} +namespace. The \.{[index]} namespace is used for typesetting the +index entries and is not necessarily associated with any parser or +lexer. +@<Begin namespace setup@>= +@G +\def\indexpseudonamespace{[index]} +\let\parsernamespace\empty +@g + +@ After all the appropriate tables and `glue' have been generated, the +typesetting of this manual can be handled by the {\tt normal} mode. Note +that this requires the \ld\ parser, as well as the \bison\ parser, +including all the appropriate machinery. + +The normal mode is started by including the tables and lists and +initializing the \bison\ parser (accomplished by inputting +\.{yyinit.sty}), followed by handling the token typesetting for the +\ld\ grammar. +@<Define the normal mode@>= +@G +\newtoks\ldcmds + +\def\modenormal{% + \def\drvname{bo}% + \def\appendr##1##2{\edef\appnext{##1{\the##1##2}}\appnext}% + \def\appendl##1##2{\edef\appnext{##1{##2\the##1}}\appnext}% + \input yyinit.sty% + \let\hostparsernamespace\ldnamespace /* the namespace where tokens are looked up for typesetting purposes */ +} +@g + +@ The \ld\ parser initialization requires setting a few global +variables, as well as entering the \.{INITIAL} state for the \ld\ +lexer. The latter is somewhat counterintuitive and is necessitated by +the ability of the parser to switch lexer states. Thus, the parser can +switch the lexer state before the lexer is invoked for the first time +wreaking havoc on the lexer state stack. +@<Define the normal mode@>= +@G +\def\ldparserinit{% + \basicparserinit + \includestackptr=\@@ne + \versnodenesting=\z@@ + \ldcmds{}% + \yyBEGIN{INITIAL}% +} +@g + +@ This is the \ld\ parser invocation routine. It is coded according to +a straightforward sequence initialize-invoke-execute-or-fall back. +@<Define the normal mode@>= +@G +\expandafter\def\csname parserstack[l]\endcsname#1#2{% + \toldparser\ldparserinit\yyparse#1\yyeof\yyeof\endparseinput\endparse + \ifyyparsefail % /* revert to generic macros if parsing failed */ + \yybreak{\message{parsing failed ...}#2}% + \else % /* stage three, process the parsed table */ + \yybreak{% + \message{commands: \the\ldcmds}% + {% + \restorecslist{ld-display}\ldunion + \the\ldcmds + \par + \vskip-\baselineskip + \the\lddisplay + }% + }% + \yycontinue +} +@g + +@ @<Initialize the active mode@>= +@G +\ifx\modeactive\UNDEFINED + \def\modeactive{\modenormal} +\fi + +\modeactive + +\ifbootstrapmode\else + @>@[@<Initialize \ld\ parsers@>@]@; + @>@[@<Modified name parser for \ld\ grammar@>@]@; +\fi +@g + +@ Unless they are being bootstrapped, the \ld\ parser and its +term parser are initialized by the normal mode. The token typesetting +of \ld\ grammar tokens is adjusted at the same time (see the remarks +above about the mechanism that is responsible for this). Most nonterminals +(such as keywords, etc.) may be displayed unchanged (provided the +names used by the lexer agree with their appearance in the script file, +see below), while the typeseting of others is modified in +\.{ltokenset.sty}. + +In the original \bison-\flex\ interface, token names are +defined as straightforward macros (a poor choice as will be seen +shortly) which can sometimes clash with the standard \Cee\ macros. +This is why \ld\ lexer returns \prodstyle{ASSERT} as +\prodstyle{ASSERT_K}. The name parser treats \.{K} as a suffix to +supply a visual reminder of this flaw. Note that the `suffixless' part +of these tokens (such as \prodstyle{ASSERT}) is never declared and +thus has to be entered in \.{ltokenset.sty} by hand. + +The tokens that never appear as part of the input (such as +\prodstyle{END} and \prodstyle{UNARY}) or those that do but have no +fixed appearance (for example, \prodstyle{NAME}) are typeset in a +style that indicates their origin. The details can be found by +examining \.{ltokenset.sty}. +@<Initialize \ld\ parsers@>= +@G +\genericparser + name: ld, + ptables: ptab.tex, + ltables: ltab.tex, + tokens: {}, + asetup: {}, + dsetup: {}, + rsetup: {}, + optimization: {};% +\genericprettytokens + namespace: ld, + tokens: ldp.tok, + correction: ltokenset.sty, + host: ld;% +@g + +@ The macros are collected in a single file included at the beginning +of this documentation. +@(ldman.stx@>= +@<Set up the generic parser machinery@>@; +@<Begin namespace setup@>@; +@<Define the bootstrapping mode@>@; +@<Define the normal mode@>@; +@<Additional macros for the \ld\ lexer/parser@>@; +@<Initialize the active mode@>@; + +@i ldgram.x +@i ldlex.x + +@** Example output. Here is an example output of the \ld\ parser designed in this +document. The original linker script is presented in the section that +follows. The same parser can be used to present examples of \ld\ scripts +in text similar to the one below. +\beginldprod +MEMORY +{ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K + FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K + ASH (rx) : ORIGIN = 8000000, LENGTH = 128K + CLASH (rx) : ORIGIN = 700000, LENGTH = 128K + ASH (rx) : ORIGIN = $8000000, LENGTH = 128K + CLASH (rx) : ORIGIN = 700000B, LENGTH = 128K + INCLUDE file.mem +} +\endprod +\noindent The syntax of \ld\ is modular enough so there does not seem to be a +need for a `parser stack' as in the case of the \bison\ +parser. If one must be able to display still smaller segments of \ld\ +code, using `hidden context' tricks (discussed elsewhere) seems to be +a better approach. +\iffalse +\traceparserstatestrue +\tracestackstrue +\tracerulestrue +\traceactionstrue +\tracelookaheadtrue +\traceparseresultstrue +\tracebadcharstrue +\yyflexdebugtrue +\tracestatestrue +\fi +% +@<Example \ld\ script@>= +@G(l) +INCLUDE file.ld + +MEMORY +{ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K + FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K + ASH (rx) : ORIGIN = 8000000, LENGTH = 128K + CLASH (rx) : ORIGIN = 700000, LENGTH = 128K + ASH (rx) : ORIGIN = $8000000, LENGTH = 128K + CLASH (rx) : ORIGIN = 700000B, LENGTH = 128K + INCLUDE file.mem +} + +_estack = 0x20005000; +_bstack = a > 0 ? NEXT(11) : 0x19; + +SECTIONS +{ + .isr_vector ALIGN(8) (NOLOAD): AT(.) ALIGN(.) ALIGN_WITH_INPUT SUBALIGN(8) SPECIAL + { + . = ALIGN(4); + KEEP(*(.isr_vector)) + . = ALIGN(4); + } > FLASH AT > RAM : FLASH : RAM : OTHER = . + 8 + + .text : + { + /* skip this comment */; + . = ALIGN(4); + *(.text) + *(.text.*) + *(.rodata) + *(.rodata*) + *(.glue_7) + *(.glue_7t) + . = ALIGN(4); + _etext = . + 8; + _sidata = _etext; + } >FLASH AT > RAM + + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = . ; + *(.data) + *(.data.*) + . = ALIGN(4); + _edata = . ; + } >RAM + + .bss : + { + . = ALIGN(4); + _sbss = .; + *(.bss) + *(COMMON) + . = ALIGN(4); + _ebss = . ; + } >RAM +} +@g + +@ @<The same example of an \ld\ script@>= +@G(b) +INCLUDE file.ld + +MEMORY +{ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K + FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K + ASH (rx) : ORIGIN = 8000000, LENGTH = 128K + CLASH (rx) : ORIGIN = 700000, LENGTH = 128K + ASH (rx) : ORIGIN = $8000000, LENGTH = 128K + CLASH (rx) : ORIGIN = 700000B, LENGTH = 128K + INCLUDE file.mem +} + +_estack = 0x20005000; +_bstack = a > 0 ? NEXT(11) : 0x19; + +SECTIONS +{ + .isr_vector ALIGN(8) (NOLOAD): AT(.) ALIGN(.) ALIGN_WITH_INPUT SUBALIGN(8) SPECIAL + { + . = ALIGN(4); + KEEP(*(.isr_vector)) + . = ALIGN(4); + } > FLASH AT > RAM : FLASH : RAM : OTHER = . + 8 + + .text : + { + /* skip this comment */; + . = ALIGN(4); + *(.text) + *(.text.*) + *(.rodata) + *(.rodata*) + *(.glue_7) + *(.glue_7t) + . = ALIGN(4); + _etext = . + 8; + _sidata = _etext; + } >FLASH AT > RAM + + .data : AT ( _sidata ) + { + . = ALIGN(4); + _sdata = . ; + *(.data) + *(.data.*) + . = ALIGN(4); + _edata = . ; + } >RAM + + .bss : + { + . = ALIGN(4); + _sbss = .; + *(.bss) + *(COMMON) + . = ALIGN(4); + _ebss = . ; + } >RAM +} +@g + +@ +\traceparserstatesfalse +\tracestacksfalse +\tracerulesfalse +\traceactionsfalse +\tracelookaheadfalse +\traceparseresultsfalse +\tracebadcharsfalse +\yyflexdebugfalse +\tracestatesfalse + +@i ldnp.x + +@** Appendix. The original code of the \ld\ parser and lexer is reproduced below. It +is mostly left intact and is typeset by the pretty printing parser for +\bison\ input. The lexer (\flex) input is reproduced verbatim and is +left mostly unformatted with the exception of spacing and the embedded +\Cee\ code. + +The treatment of comments is a bit more invasive. \CWEB\ silently +assumes that the comment refers to the preceding statement or a group +of statements which is reflected in the way the comment is +typeset. The comments in \ld\ source files use the +opposite convention. For the sake of consistency, such comments have +been moved so as to make them fit the \CWEB\ style. The comments meant to refer to a +sizable portion of the program (such as a whole function or a group +of functions) are put at the beginning of a \CWEB\ section containing +the appropriate part of the program. + +\CWEB\ treats comments as ordinary \TeX\ so the comments are changed +to take advantage of \TeX\ formatting and introduce some visual +cues. The convention of using {\it italics\/} for the original +comments has been reversed: the italicized comments are the ones +introduced by the author, {\it not\/} the original +creators of \ld. + +@i ldgramo.x +@i ldlexo.x + +@** Index. This section lists the variable names and (in some cases) +the keywords used inside the `language sections' of the \CWEB\ +source. It takes advantage of the built-in facility of \CWEB\ to supply +references for both definitions (set in {\it +italic}) as well as uses for each \Cee\ identifier in the text. + +Special facilities have been added to extend indexing to +\bison\ grammar terms, \TeX\ control sequences encountered in +\bison\ actions, and file and section names encountered in \ld\ +scripts. For a detailed description of the various conventions adhered +to by the index entries the reader is encouraged to consult the +remarks preceding the index of the document describing the core of +the \splint\ suite. We will only mention here that (consistent with +the way \bison\ references are treated) a script example: +$$ +\vbox{ +\beginldprod +MEMORY +{ + MEMORY1 (xrw) : ORIGIN = 0x20000000, LENGTH = 20K + MEMORY2 (rx) : ORIGIN = 0x8000000, LENGTH = 128K +} +_var_1 = 0x20005000; +\endprod +}% +$$ +\noindent inside the \TeX\ part of a \CWEB\ section will generate several +index entries, as well, mimicking \CWEB's behavior for the +{\it inline \Cee\/} (\.{\yl}$\ldots$\.{\yl}). Such entries are labeled +with $^\circ$, to provide a reminder of their origin. +\def\otherlangindexseparator{% + \par + \vskip.5\baselineskip + \centerline{B{\sc ISON}, LD, {\sc AND} \TeX\ {\sc INDICES}}% + \vskip.5\baselineskip + \par +} +\let\currentparsernamespace\parsernamespace + \let\parsernamespace\indexpseudonamespace + \prettywordpair{emptyrhs}{$\circ$ {\rm(empty rhs)}}% + \prettywordpair{inline_action}{$\diamond$ {\rm(inline action)}}% +\let\parsernamespace\currentparsernamespace +\closeout\gindex +\let\inx\inxmod +\let\fin\finmod +\let\oldMRL\MRL +\def\MRL#1{\smash{\oldMRL{#1}}} % a more sophisticated way to handle it woud be to add a \smash whenever we are + % in the [index] namespace but this is simpler and works as well +\def\topofcontents{\null\vskip-3\baselineskip\centerline{C{\sc ONTENTS} (\sc\uppercase\expandafter{\title})}\medskip} diff --git a/support/splint/examples/ld/ldnp.w b/support/splint/examples/ld/ldnp.w new file mode 100644 index 0000000000..f92d0dfc8c --- /dev/null +++ b/support/splint/examples/ld/ldnp.w @@ -0,0 +1,362 @@ +@q Copyright 2012-2015, Alexander Shibakov@> +@q This file is part of SPLinT@> + +@q SPLinT is free software: you can redistribute it and/or modify@> +@q it under the terms of the GNU General Public License as published by@> +@q the Free Software Foundation, either version 3 of the License, or@> +@q (at your option) any later version.@> + +@q SPLinT is distributed in the hope that it will be useful,@> +@q but WITHOUT ANY WARRANTY; without even the implied warranty of@> +@q MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the@> +@q GNU General Public License for more details.@> + +@q You should have received a copy of the GNU General Public License@> +@q along with SPLinT. If not, see <http://www.gnu.org/licenses/>.@> + +@** The name parser for \ld\ term names. +We take a lazy approach to the typeseting of term names for the \ld\ +grammar by creating a dedicated parser for name processing. This way +any pattern we notice can be quickly incorporated into our typesetting scheme. +% We include the macros here since this file is intended to be +% included by the documentation `aggregator' so putting bare \TeX\ +% at the beginning of the file runs the risk of producing an error +% of having \TeX\ material inside a \Cee\ section. +\genericprettytokens namespace: ldsmall, tokens: {}, correction: lstokenset.sty, host: ldsmall; +@(ld_small_parser.yy@>= +@G Switch to generic mode. +%{@> @<Name parser \Cee\ preamble@> @=%} + @> @<Bison options@> @= +%union {@> @<Union of parser types@> @=} +%{@> @<Name parser \Cee\ postamble@> @=%} + @> @<Token and types ...@> @= +%% + @> @<Parser productions@> @= +%% +@g + +@ To put the new name parser to work, we need to initialize it. The +initialization is done by the macros below. After the initialization +has been completed, the switch command is replaced by the one that +activates the new name parser. +@<Modified name parser for \ld\ grammar@>= +@G +\genericparser + name: ldsmall, + ptables: ld_small_tab.tex, + ltables: ld_small_dfa.tex, + tokens: {}, + asetup: {}, + dsetup: {}, + rsetup: {\noexpand\savefullstateextra}, + optimization: {};% +\let\otosmallparser\tosmallparser % /* save the old name parser */ +\let\tosmallparser\toldsmallparser +@g + +@ @<Bison options@>= +@G +%token-table +%debug +%start full_name +@g + +@ @<Token and types declarations@>= +@G +%token PERCENT_IDENTIFIER +%token IDENTIFIER +%token OPTIONAL +%token K_SUFFIX +%token INTEGER +%token EXTENDED +%token WILDCARD +@g + +@*1 The name parser productions. These macros do a bit more than we +need to typeset the term names. Their core is designed to treat +suffixes and prefixes of a certain form in a special way. In addition, +some productions were left in place from the original name parser in +order to be able to refer to, say, \flex\ options in text. The inline +action in one of the rules for \prodstyle{identifier\_string} was +added to adjust the number and the position of the terms so that the +appropriate action can be reused later for +\prodstyle{qualified\_identifier\_string}. +@<Parser productions@>= +@G +full_name: + identifier_string suffixes.opt {@> @<Compose the full name@> @=} +| qualifier '_' identifier_string suffixes.opt {@> @<Compose a qualified name@> @=} +; + +identifier_string: + PERCENT_IDENTIFIER {@> @<Attach option name@> @=} +| IDENTIFIER {@> @<Start with an identifier@> @=} +| '\'' WILDCARD '\'' {@> @<Start with a quoted string@> @=} +| '\'' '.' '\'' {@> @<Start with a \prodstyle{'.'} string@> @=} +| '\'' '_' '\'' {@> @<Start with an \prodstyle{'\_'} string@> @=} +@t}\vb{\flatten}{@> +| incomplete_identifier_string {} IDENTIFIER {@> @<Attach an identifier@> @=} +; +@t}\vb{\resetf}{@> +incomplete_identifier_string: + identifier_string '_' {@> TeX_( "/yy0{/the/yy(1)}" ); @=} +| qualified_identifier_string '_' {@> TeX_( "/yy0{/the/yy(1)}" ); @=} +; + +qualified_identifier_string: + identifier_string '_' qualifier {@> @<Attach qualifier to a name@> @=} +| qualified_identifier_string '_' qualifier {@> @<Attach qualifier to a name@> @=} +; + +suffixes.opt: + {@> TeX_( "/yy0{}" ); @=} +| '.' {@> TeX_( "/yy0{/nx/dotsp/nx/sfxnone}" ); @=} +| '.' suffixes {@> @<Attach suffixes@> @=} +| '.' qualified_suffixes {@> @<Attach qualified suffixes@> @=} +| INTEGER {@> @<Attach an integer@> @=} +| '_' INTEGER {@> @<Attach a subscripted integer@> @=} +| '_' qualifier {@> @<Attach a subscripted qualifier@> @=} +; + +suffixes: + IDENTIFIER {@> @<Start with a named suffix@> @=} +| INTEGER {@> @<Start with a numeric suffix@> @=} +| suffixes '.' {@> @<Add a dot separator@> @=} +| suffixes IDENTIFIER {@> @<Attach a named suffix@> @=} +| suffixes INTEGER {@> @<Attach integer suffix@> @=} +| qualifier '.' {@> TeX_( "/yy0{/nx/sfxn/the/yy(1)/nx/dotsp}" ); @=} +| suffixes qualifier '.' {@> TeX_( "/yy0{/the/yy(1)/nx/sfxn/the/yy(2)/nx/dotsp}" ); @=} +; + +qualified_suffixes: + suffixes qualifier {@> @<Attach a qualifier@> @=} +| qualifier {@> @<Start suffixes with a qualifier@> @=} +; + +qualifier: + OPTIONAL {@> TeX_( "/yy0{/the/yy(1)}" ); @=} +| K_SUFFIX {@> TeX_( "/yy0{/the/yy(1)}" ); @=} +| EXTENDED {@> TeX_( "/yy0{/the/yy(1)}" ); @=} +; +@g + +@ @<Compose the full name@>= + @[TeX_( "/yy0{/the/yy(1)/the/yy(2)}/namechars/yyval" );@]@; + +@ @<Compose a qualified name@>= + @[TeX_( "/yy0{/the/yy(3)/the/yy(4)/nx/dotsp/nx/qual/the/yy(1)}/namechars/yyval" );@]@; + +@ @<Attach option name@>= + @[TeX_( "/getfirst{/yy(1)}/to/toksa" );@]@; + @[TeX_( "/getsecond{/yy(1)}/to/toksb" );@]@; + @[TeX_( "/yy0{/nx/optstr{/the/toksa}{/the/toksb}}" );@]@; + +@ @<Start with an identifier@>= + @[TeX_( "/getfirst{/yy(1)}/to/toksa" );@]@; + @[TeX_( "/getsecond{/yy(1)}/to/toksb" );@]@; + @[TeX_( "/yy0{/nx/idstr{/the/toksa}{/the/toksb}}" );@]@; + +@ @<Start with a tag@>= + @[TeX_( "/getfirst{/yy(2)}/to/toksa" );@]@; + @[TeX_( "/getsecond{/yy(2)}/to/toksb" );@]@; + @[TeX_( "/yy0{/nx/idstr{</the/toksa>}{</the/toksb>}}" );@]@; + +@ @<Start with a quoted string@>= + @[TeX_( "/getfirst{/yy(2)}/to/toksa" );@]@; + @[TeX_( "/getsecond{/yy(2)}/to/toksb" );@]@; + @[TeX_( "/yy0{/nx/chstr{/the/toksa}{/the/toksb}}" );@]@; + +@ @<Start with a \prodstyle{'.'} string@>= + @[TeX_( "/yy0{/nx/chstr{.}{.}}" );@]@; + +@ @<Start with an \prodstyle{'\_'} string@>= + @[TeX_( "/yy0{/nx/chstr{/uscoreletter}{/uscoreletter}}" );@]@; + +@ @<Turn a qualifier into an identifier@>= + @<Start with an identifier@>@; + +@ @<Attach an identifier@>= + @[TeX_( "/getsecond{/yy(1)}/to/toksa" );@]@; + @[TeX_( "/appendr/toksa{/noexpand/_}" );@]@; + @[TeX_( "/getfirst{/yy(3)}/to/toksb" );@]@; + @[TeX_( "/concat/toksa/toksb" );@]@; + @[TeX_( "/getthird{/yy(1)}/to/toksb" );@]@; + @[TeX_( "/appendr/toksb{/uscoreletter}" );@]@; + @[TeX_( "/getsecond{/yy(3)}/to/toksc" );@]@; + @[TeX_( "/concat/toksb/toksc" );@]@; + @[TeX_( "/yy0{/nx/idstr{/the/toksa}{/the/toksb}}" );@]@; + +@ @<Attach qualifier to a name@>= + + +@ @<Attach an integer@>= + @[TeX_( "/yy0{/nx/dotsp/nx/sfxi/the/yy(1)}" );@]@; + +@ @<Attach a subscripted integer@>= + @[TeX_( "/yy0{/nx/dotsp/nx/sfxi/the/yy(2)}" );@]@; + +@ @<Attach a subscripted qualifier@>= + @[TeX_( "/yy0{/nx/dotsp/nx/qual/the/yy(2)}" );@]@; + +@ @<Attach suffixes@>= + @[TeX_( "/yy0{/nx/dotsp/the/yy(2)}" );@]@; + +@ @<Attach qualified suffixes@>= + @<Attach suffixes@>@; + +@ @<Start with a named suffix@>= + @[TeX_( "/yy0{/nx/sfxn/the/yy(1)}" );@]@; + +@ @<Start with a numeric suffix@>= + @[TeX_( "/yy0{/nx/sfxi/the/yy(1)}" );@]@; + +@ @<Add a dot separator@>= + @[TeX_( "/yy0{/the/yy(1)/nx/dotsp}" );@]@; + +@ @<Attach integer suffix@>= + @[TeX_( "/yy0{/the/yy(1)/nx/sfxi/the/yy(2)}" );@]@; + +@ @<Attach a named suffix@>= + @[TeX_( "/yy0{/the/yy(1)/nx/sfxn/the/yy(2)}" );@]@; + +@ @<Attach a qualifier@>= + @[TeX_( "/yy0{/the/yy(1)/nx/qual/the/yy(2)}" );@]@; + +@ @<Start suffixes with a qualifier@>= + @[TeX_( "/yy0{/nx/qual/the/yy(1)}" );@]@; + +@ \Cee\ preamble. In this case, there are no `real' actions that our +grammar performs, only \TeX\ output, so this section is empty. + +@<Name parser \Cee\ preamble@>= + +@ \Cee\ postamble. It is tricky to insert function definitions that use \bison's internal types, +as they have to be inserted in a place that is aware of the internal definitions but before said +definitions are used. + +@<Name parser \Cee\ postamble@>= +#define YYPRINT(file, type, value) @[yyprint (file, type, value)@] + static void yyprint (FILE *file, int type, YYSTYPE value){} + +@ Union of types. + +@<Union of parser types@>= + +@*1 The name scanner. +%\checktabletrue +@(ld_small_lexer.ll@>= +@G + @> @<Lexer definitions@> @= +%{@> @<Lexer \Cee\ preamble@> @=%} + @> @<Lexer options@> @= +%% + @> @<Regular expressions@> @= +%% +@O +void define_all_states( void ) { + @<Collect all state definitions@>@; +} +@o +@g +@t}\ifbootstrapmode\yyskipparsetrue\fi{@> + +@ @<Lexer definitions@>= + @<Lexer states@>@; +@G +aletter [a-zA-Z] +wc ([^\\\']{-}[a-zA-Z0-9]|\\.) +id ({aletter}|{aletter}({aletter}|[0-9])*{aletter}) +int [0-9]+ +@g + +@ @<Collect all state definitions@>= +#define _register_name( name ) @[Define_State( #name, name )@] +/* nothing for now */ +#undef _register_name + +@ Strings and characters in directives/rules. +@<Lexer states@>= +@G +%x SC_ESCAPED_STRING SC_ESCAPED_CHARACTER +@g + +@ @<Lexer \Cee\ preamble@>= + +#include <stdint.h> +#include <stdbool.h> + +@t}\yyskipparsefalse{@> +@ @<Lexer options@>= +@G +%option bison-bridge +%option noyywrap nounput noinput reentrant +%option noyy_top_state +%option debug +%option stack +%option outfile="ld_small_lexer.c" +@g + +@ @<Regular expressions@>= + @<Scan white space@>@; + @<Scan identifiers@>@; + +@ White space skipping. +\traceparserstatestrue +\tracestackstrue +\tracerulestrue +\traceactionstrue +\tracelookaheadtrue +\traceparseresultstrue +\tracebadcharstrue +\yyflexdebugtrue +% +%\prodstyle{abc123} +% +\traceparserstatesfalse +\tracestacksfalse +\tracerulesfalse +\traceactionsfalse +\tracelookaheadfalse +\traceparseresultsfalse +\tracebadcharsfalse +\yyflexdebugfalse +% +\yyskipparsetrue +@<Scan white space@>= +@G +[ \f\n\t\v] {@> @[TeX_( "/yylexnext" );@]@=} +@g + +@ This collection of regular expressions might seem redundant, and in +its present state, it certainly is. However, if later on the +typesetting style for some of the keywords would need to be adjusted, +such changes would be easy to implement, since the template is already +here. +@<Scan identifiers@>= +@G +"%"({aletter}|[0-9]|[-_]|"%"|[<>])+ {@> @[TeX_( "/yylexreturnval{PERCENT_IDENTIFIER}" );@]@=} + +"opt" {@> @[TeX_( "/yylexreturnval{OPTIONAL}" );@]@=} +"K" {@> @[TeX_( "/yylexreturnval{K_SUFFIX}" );@]@=} +"ext" {@> @[TeX_( "/yylexreturnval{EXTENDED}" );@]@=} + +[\'._] {@> @[TeX_( "/yylexreturnchar" );@]@=} +{wc} {@> @[TeX_( "/yylexreturnval{WILDCARD}" );@]@=} + +{id} {@> @[@<Prepare to process an identifier@>@]@=} +{int} {@> @[TeX_( "/yylexreturnval{INTEGER}" );@]@=} + +"\"" {@> @[TeX_( "/yylexnext" );@]@=} +. {@> @[@<React to a bad character@>@]@=} +@g + +@ @<Prepare to process an identifier@>= + @[TeX_( "/yylexreturnval{IDENTIFIER}" );@]@; + +@ \let\hostparsernamespace\ldnamespace\yyskipparsefalse A simple routine to detect +trivial scanning problems. +@<React to a bad character@>= + @[TeX_( "/iftracebadchars" );@]@; + @[TeX_( " /yycomplain{invalid character(s): /the/yytext}" );@]@; + @[TeX_( "/fi" );@]@; + @[TeX_( "/yylexreturn{$undefined}" );@]@; diff --git a/support/splint/examples/ld/ldnump.w b/support/splint/examples/ld/ldnump.w new file mode 100644 index 0000000000..5d4d45f724 --- /dev/null +++ b/support/splint/examples/ld/ldnump.w @@ -0,0 +1,306 @@ +@q Copyright 2012-2015, Alexander Shibakov@> +@q This file is part of SPLinT@> + +@q SPLinT is free software: you can redistribute it and/or modify@> +@q it under the terms of the GNU General Public License as published by@> +@q the Free Software Foundation, either version 3 of the License, or@> +@q (at your option) any later version.@> + +@q SPLinT is distributed in the hope that it will be useful,@> +@q but WITHOUT ANY WARRANTY; without even the implied warranty of@> +@q MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the@> +@q GNU General Public License for more details.@> + +@q You should have received a copy of the GNU General Public License@> +@q along with SPLinT. If not, see <http://www.gnu.org/licenses/>.@> + +@** The name parser for \ld\ term names. +We take a lazy approach to the typeseting of term names for the \ld\ +grammar by creating a dedicated parser for name processing. This way +any pattern we notice can be quickly incorporated into our typesetting scheme. +% We include the macros here since this file is intended to be +% included by the documentation `aggregator' so putting bare \TeX\ +% at the beginning of the file runs the risk of producing an error +% of having \TeX\ material inside a \Cee\ section. +\genericprettytokens namespace: ldsmall, tokens: {}, correction: lstokenset.sty, host: ldsmall; +\iffalse +\let\currentparsernamespace\parsernamespace + \let\parsernamespace\ldsmallnamespace + \let\hostparsernamespace\ldsmallnamespace + \input lstokenset.sty +\let\parsernamespace\currentparsernamespace +\fi +@(ld_num_parser.yy@>= +@G Switch to generic mode. +%{@> @<Name parser \Cee\ preamble@> @=%} + @> @<Bison options@> @= +%union {@> @<Union of parser types@> @=} +%{@> @<Name parser \Cee\ postamble@> @=%} + @> @<Token and types ...@> @= +%% + @> @<Parser productions@> @= +%% +@g + +@ To put the new name parser to work, we need to initialize it. The +initialization is done by the macros below. After the initialization +has been completed, the switch command is replaced by the one that +activates the new name parser. +@<Modified name parser for \ld\ grammar@>= +@G +\genericparser name: ldnum, + ptables: ld_num_tab.tex, + ltables: ld_num_dfa.tex, + tokens: {}, + asetup: {}, + dsetup: {}, + rsetup: {\noexpand\savefullstateextra}, + optimization: {};% +@g + +@ @<Bison options@>= +@G +%token-table +%debug +%start hex_number +@g + +@ @<Token and types declarations@>= +@G +%token DIGIT NYBBLE +@g + +@*1 The name parser productions. These macros do a bit more than we +need to typeset the term names. Their core is designed to treat +suffixes and prefixes of a certain form in a special way. In addition, +some productions were left in place from the original name parser in +order to be able to refer to, say, \flex\ options in text. The inline +action in one of the rules for \prodstyle{identifier\_string} was +added to adjust the number and the position of the terms so that the +appropriate action can be reused later for +\prodstyle{qualified\_identifier\_string}. +@<Parser productions@>= +@G +hex_number: + DIGIT {} + | DIGIT DIGIT {} + | DIGIT DIGIT DIGIT {} + | hex_number nybble {} + ; + +nybble: + DIGIT DIGIT DIGIT DIGIT {} + ; +@g + +@ @<Compose the full name@>= + @[TeX_( "/yy0{/the/yy(1)/the/yy(2)}/namechars/yyval" );@]@; + +@ @<Compose a qualified name@>= + @[TeX_( "/yy0{/the/yy(3)/the/yy(4)/nx/dotsp/nx/qual/the/yy(1)}/namechars/yyval" );@]@; + +@ @<Attach option name@>= + @[TeX_( "/getfirst{/yy(1)}/to/toksa" );@]@; + @[TeX_( "/getsecond{/yy(1)}/to/toksb" );@]@; + @[TeX_( "/yy0{/nx/optstr{/the/toksa}{/the/toksb}}" );@]@; + +@ @<Start with an identifier@>= + @[TeX_( "/getfirst{/yy(1)}/to/toksa" );@]@; + @[TeX_( "/getsecond{/yy(1)}/to/toksb" );@]@; + @[TeX_( "/yy0{/nx/idstr{/the/toksa}{/the/toksb}}" );@]@; + +@ @<Start with a tag@>= + @[TeX_( "/getfirst{/yy(2)}/to/toksa" );@]@; + @[TeX_( "/getsecond{/yy(2)}/to/toksb" );@]@; + @[TeX_( "/yy0{/nx/idstr{</the/toksa>}{</the/toksb>}}" );@]@; + +@ @<Start with a quoted string@>= + @[TeX_( "/getfirst{/yy(2)}/to/toksa" );@]@; + @[TeX_( "/getsecond{/yy(2)}/to/toksb" );@]@; + @[TeX_( "/yy0{/nx/chstr{/the/toksa}{/the/toksb}}" );@]@; + +@ @<Turn a qualifier into an identifier@>= + @<Start with an identifier@>@; + +@ @<Attach an identifier@>= + @[TeX_( "/getsecond{/yy(1)}/to/toksa" );@]@; + @[TeX_( "/appendr/toksa{/noexpand/_}" );@]@; + @[TeX_( "/getfirst{/yy(3)}/to/toksb" );@]@; + @[TeX_( "/concat/toksa/toksb" );@]@; + @[TeX_( "/getthird{/yy(1)}/to/toksb" );@]@; + @[TeX_( "/appendr/toksb{/uscoreletter}" );@]@; + @[TeX_( "/getsecond{/yy(3)}/to/toksc" );@]@; + @[TeX_( "/concat/toksb/toksc" );@]@; + @[TeX_( "/yy0{/nx/idstr{/the/toksa}{/the/toksb}}" );@]@; + +@ @<Attach qualifier to a name@>= + + +@ @<Attach an integer@>= + @[TeX_( "/yy0{/nx/dotsp/nx/sfxi/the/yy(1)}" );@]@; + +@ @<Attach a subscripted integer@>= + @[TeX_( "/yy0{/nx/dotsp/nx/sfxi/the/yy(2)}" );@]@; + +@ @<Attach a subscripted qualifier@>= + @[TeX_( "/yy0{/nx/dotsp/nx/qual/the/yy(2)}" );@]@; + +@ @<Attach suffixes@>= + @[TeX_( "/yy0{/nx/dotsp/the/yy(2)}" );@]@; + +@ @<Attach qualified suffixes@>= + @<Attach suffixes@>@; + +@ @<Start with a named suffix@>= + @[TeX_( "/yy0{/nx/sfxn/the/yy(1)}" );@]@; + +@ @<Start with a numeric suffix@>= + @[TeX_( "/yy0{/nx/sfxi/the/yy(1)}" );@]@; + +@ @<Add a dot separator@>= + @[TeX_( "/yy0{/the/yy(1)/nx/dotsp}" );@]@; + +@ @<Attach integer suffix@>= + @[TeX_( "/yy0{/the/yy(1)/nx/sfxi/the/yy(2)}" );@]@; + +@ @<Attach a named suffix@>= + @[TeX_( "/yy0{/the/yy(1)/nx/sfxn/the/yy(2)}" );@]@; + +@ @<Attach a qualifier@>= + @[TeX_( "/yy0{/the/yy(1)/nx/qual/the/yy(2)}" );@]@; + +@ @<Start suffixes with a qualifier@>= + @[TeX_( "/yy0{/nx/qual/the/yy(1)}" );@]@; + +@ \Cee\ preamble. In this case, there are no `real' actions that our +grammar performs, only \TeX\ output, so this section is empty. + +@<Name parser \Cee\ preamble@>= + +@ \Cee\ postamble. It is tricky to insert function definitions that use \bison's internal types, +as they have to be inserted in a place that is aware of the internal definitions but before said +definitions are used. + +@<Name parser \Cee\ postamble@>= +#define YYPRINT(file, type, value) @[yyprint (file, type, value)@] + static void yyprint (FILE *file, int type, YYSTYPE value){} + +@ Union of types. + +@<Union of parser types@>= + +@*1 The name scanner. +%\checktabletrue +@(ld_num_lexer.ll@>= +@G + @> @<Lexer definitions@> @= +%{@> @<Lexer \Cee\ preamble@> @=%} + @> @<Lexer options@> @= +%% + @> @<Regular expressions@> @= +%% +@O +void define_all_states( void ) { + @<Collect all state definitions@>@; +} +@o +@g + +@ \ifbotstrapmode\yyskipparsetrue\fi@<Lexer definitions@>= + @<Lexer states@>@; +@G +aletter [a-zA-Z] +wc ([^\\\'\"-]{-}[_a-zA-Z0-9]|\\.) +id ({aletter}|{aletter}({aletter}|[0-9])*{aletter}) +int [0-9]+ +@g + +@ @<Collect all state definitions@>= +#define _register_name( name ) @[Define_State( #name, name )@] +/* nothing for now */ +#undef _register_name + +@ Strings and characters in directives/rules. +@<Lexer states@>= +@G +%x SC_ESCAPED_STRING SC_ESCAPED_CHARACTER +@g + +@ @<Lexer \Cee\ preamble@>= + +#include <stdint.h> +#include <stdbool.h> + +@ \yyskipparsefalse@<Lexer options@>= +@G +%option bison-bridge +%option noyywrap nounput noinput reentrant +%option noyy_top_state +%option debug +%option stack +%option outfile="ld_num_lexer.c" +@g + +@ @<Regular expressions@>= + @<Scan white space@>@; + @<Scan identifiers@>@; + +@ White space skipping. +\traceparserstatestrue +\tracestackstrue +\tracerulestrue +\traceactionstrue +\tracelookaheadtrue +\traceparseresultstrue +\tracebadcharstrue +\yyflexdebugtrue +% +%\prodstyle{abc123} +% +\traceparserstatesfalse +\tracestacksfalse +\tracerulesfalse +\traceactionsfalse +\tracelookaheadfalse +\traceparseresultsfalse +\tracebadcharsfalse +\yyflexdebugfalse +% +%\yyskipparsetrue +@<Scan white space@>= +@G +[ \f\n\t\v] {@> @[TeX_( "/yylexnext" );@]@=} +@g + +@ This collection of regular expressions might seem redundant, and in +its present state, it certainly is. However, if later on the +typesetting style for some of the keywords would need to be adjusted, +such changes would be easy to implement, since the template is already +here. +%\yyskipparsefalse % this is not necessary +@<Scan identifiers@>= +@G +"%"({aletter}|[0-9]|[-_]|"%"|[<>])+ {@> @[TeX_( "/yylexreturnval{PERCENT_IDENTIFIER}" );@]@=} + +"opt" {@> @[TeX_( "/yylexreturnval{OPTIONAL}" );@]@=} +"na" {@> @[TeX_( "/yylexreturnval{NO_ATTR}" );@]@=} +"ext" {@> @[TeX_( "/yylexreturnval{EXTENDED}" );@]@=} + +[<>._\'] {@> @[TeX_( "/yylexreturnchar" );@]@=} +{wc} {@> @[TeX_( "/yylexreturnval{WILDCARD}" );@]@=} + +{id} {@> @[@<Prepare to process an identifier@>@]@=} +{int} {@> @[TeX_( "/yylexreturnval{INTEGER}" );@]@=} + +"\"" {@> @[TeX_( "/yylexnext" );@]@=} +. {@> @[@<React to a bad character@>@]@=} +@g + +@ @<Prepare to process an identifier@>= + @[TeX_( "/yylexreturnval{IDENTIFIER}" );@]@; + +@ \let\hostparsernamespace\ldnamespace @<React to a bad character@>= + @[TeX_( "/iftracebadchars" );@]@; + @[TeX_( " /yycomplain{invalid character(s): /the/yytext}" );@]@; + @[TeX_( "/fi" );@]@; + @[TeX_( "/yylexreturn{$undefined}" );@]@; diff --git a/support/splint/examples/ld/ldunion.sty b/support/splint/examples/ld/ldunion.sty new file mode 100644 index 0000000000..b2c3837e57 --- /dev/null +++ b/support/splint/examples/ld/ldunion.sty @@ -0,0 +1,351 @@ +% Copyright 2012-2015, Alexander Shibakov +% This file is part of SPLinT +% +% SPLinT 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. +% +% SPLinT 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 SPLinT. If not, see <http://www.gnu.org/licenses/>. + +% prototypes of all the macros produced by the ld parser +% we will follow the convention: 12string is a string of category 12 characters and spaces, tex_string: a string +% of TeX tokens; sptr is a pointer to the stash stream, fptr is a pointer to the format stream + +\def\yyuniontag{\ldunion} +\def\parserstrictnamespace{ld-parser-strict} +\def\parserprototypesnamespace{ld-parser-strict:headers} + +\def\ldunion{\currentyyunionnamespace} +\def\currentyyunionnamespace{ld-generic} + +% types returned by the lexer (* marks the types that get removed by the parser in some cases) + +\defp\anint#1#2#3{} % integer :: \anint{integer}{fptr}{sptr} +\defp\bint#1#2#3{} % integer in a specifix radix :: \bint{integer}{fptr}{sptr} +\defp\hexint#1#2#3{} % hex integer :: \hexint{integer}{fptr}{sptr} + +% ld commands + +\defp\ldregexp#1{} % name pattern :: \ldregexp{name} +\defp\ldspace{} % space separator :: \ldspace +\defp\ldattributes#1{} % attributes :: \ldattributes{name} +\defp\ldattributesneg#1{} % complemented attributes :: \ldattributesneg{name} +\defp\ldfilename#1{} % file name :: \ldfilename{name} +\defp\ldcommandseparator#1#2{} % command separator +\defp\ldassignment#1#2#3{} % assignment :: \ldassignment{lhs}{op}{rhs} +\defp\ldinclude#1{} % file inclusion :: \ldinclude{file name} +\defp\ldmemory#1{} % memory specification :: \ldmemory{memory spcification} +\defp\ldfill#1{} % fill expression :: \ldfill{expression} +\defp\ldmemoryspec#1#2#3#4{} % memory item :: \ldmemoryspec{name}{attributes}{origin}{length} +\defp\ldoriginspec#1{} % origin :: \ldoriginspec{expression} +\defp\ldlengthspec#1{} % length :: \ldlengthspec{expression} +\defp\ldsections#1{} % ld sections :: \ldsections{sections} +\defp\ldsectionseparator{} % section separator +\defp\ldtype#1{} % section type :: \ldtype{type} +\defp\ldstatement#1{} % stray statement :: \ldstatement{statement} +\defp\ldnamedsection#1#2#3#4#5#6#7{} % named section :: \ldnamedsection{name} + % {{expression}{type}}{at} + % {{}{}{}:alignment} + % {constraint}{statements} + % {{}{}{}{}:placement} + +\savecslist{ld-parser-prototypes}\ldunion + +\input ldint.sty + +\def\bigbracedel{\delimiter"4266308} + +\newtoks\lddisplay + +\defc\ldinclude{% + \toksa={&##\cr\ttl include\ &}#1% + \concat\toksa\toksc + \toksc{\cr} + \concat\toksa\toksc + \edef\next{\lddisplay{\the\lddisplay\halign{\the\toksa}}}\next +} + +\defc\ldmemory{% + \savecslist{local-namespace}{\ldunion}% + \restorecslist{ld-parser:memory-spec}\ldunion + \toksa{}#1% + \toksc{% + \hfil##\qquad&##\hfil&\qquad##\hfil\quad&\hfil##&\quad\hfil##\cr + \ttl memory&\hfil&\ttl attributes&\ttl origin&\ttl length\cr + \noalign{\smallskip}% + }% + \edef\next{\lddisplay{\the\lddisplay\halign{\the\toksc\the\toksa}}}\next + \restorecslist{local-namespace}{\ldunion}% +} + +\defc\ldsections{% + \savecslist{local-namespace}{\ldunion}% + \restorecslist{ld-parser:sections}\ldunion + \toksa{}\def\sections@header{\ttl sections}% + #1% + \toksc{% + &##\hfil\quad\cr + }% + \edef\next{\lddisplay{\the\lddisplay\halign{\the\toksc\the\toksa}}}\next + \restorecslist{local-namespace}{\ldunion}% +} + +\def\ldextractname#1#2{% + \edef\next{\toksc{\gidxentry{\termttstring}{#2}{\ntt #2}}}\next +} + +% the grammar of ld scripts is very uniform so the separator form +% below is more than adequate; if a more sophisticated spacing +% strategy is required, one may consult the design of +% \separatorswitcheq and \separatorswitchneq in yyunion.sty + +\defc\ldcommandseparator{\yyifsamestring{#1}{#2}{}{\appendr\lddisplay{\noexpand\medskip}}} + +\defc\ldstatement{\toksc{\hbox{$#1$}}\concat\lddisplay\toksc} + +\defc\ldassignment{% + #1#2#3% +} + +\defc\anint{% + \uppercase{\ldsciinteger{#1}}% +} + +\defc\hexint{% + \ldsciinteger{#1}% +} + +\defc\bint{% + \uppercase{\ldbasedinteger{#1}}% +} + +\defc\ldregexp{% + \ldreg@xp#1% +} + +\def\ldreg@xp#1#2{% + \hbox{\let\termindex\writeidxentry\edef\next{\toksc{\gidxentry{\termttstring}{#2}}}\next\the\toksc\ntt@#2}% +} + +\defc\ldfill{% + #1% +} + +\defc\ldfilename{\ldextractname#1} + +\savecslist{ld-display}\ldunion + +% memory specifications + +\restorecslist{ld-parser-strict}\ldunion + +\defc\ldmemoryspec{% + \toksb{\hfil&}% + \let\termindex\writeidxhentry + \ldextractname#1\concat\toksb\toksc + \let\termindex\eatone + \appendr\toksb{&}% + \toksc{}#2\concat\toksb\toksc + \toksc{}#3\concat\toksb\toksc + \toksc{}#4\concat\toksb\toksc + \concat\toksa\toksb + \toksb{\cr}\concat\toksa\toksb +} + +\defc\ldattributes{% + \ldextractname#1\appendr\toksc{&}% +} + +\defc\ldlengthspec{% + \toksc{#1}% +} + +\defc\ldoriginspec{% + \toksc{#1&}% +} + +\defc\ldinclude{% + \toksc={\hfil&\ttl include }% + \concat\toksa\toksc#1% + \concat\toksa\toksc + \toksc{&\hfil&\hfil&\hfil\cr}% + \concat\toksa\toksc +} + +\restorecs{ld-display}{\anint\ldfilename} +\toyyunion{ld-parser:memory-spec} + +% sections commands + +\restorecslist{ld-parser-strict}\ldunion + +\newif\ifplacementpushed +\newif\ifsectioncomplete +\newif\iffillextracted + +\defc\ldnamedsection{ % named section :: \ldnamedsection{name} + % {{bind?}{expression}{block?}{expression}{type}}{at} + % {{}{}{}:alignment} + % {constraint}{statements} + % {{}{}{}{}:placement} + \tempca=\z@ % line counter + \tempcb=\z@ % alignment line counter + \placementpushedfalse + \sectioncompletefalse + \fillextractedfalse + \bloop + \toksb{}% + \ifnum\tempca=\z@ + \toksb\expandafter{\sections@header&}% section header + \ldextractname#1% section name + \concat\toksb\toksc + \appendr\toksb{&}% + \ldexpwithtype#2% location and type + \concat\toksb\toksc + \appendr\toksb{&}% + \yystringempty{#3}{\ldpushalignment#4}{\toksc{{\ttl at }$#3$}}% alignment + \concat\toksb\toksc + \appendr\toksb{&}% + \yystringempty{#5}{\ldpushplacement#7}{\toksc{{\ttl #5}}}% constraint + \concat\toksb\toksc + \appendr\toksb{&}% + \ldstartpheaders#7% possible pheaders + \concat\toksb\toksc + \appendr\toksb{\cr}% + \def\sections@header{}% + \else + \toksb\expandafter{&}% section header + \advance\tempca\m@ne + \ldextractitem\tempca{#6}% expression + \advance\tempca\@ne + \yytoksempty\toksc{% + \ldextractfill#7% + \iffillextracted + \ifnum\tempcb<\tw@ + \else + \sectioncompletetrue + \fi + \fi + \fillextractedtrue + }{% + \toksc\expandafter{\expandafter\qquad\expandafter$\the\toksc{}$}% + }% + \concat\toksb\toksc + \appendr\toksb{&}% +% \ldexpwithtype#2% location and type +% \concat\toksa\toksc + \appendr\toksb{&}% + \ldpushalignment#4% alignment + \concat\toksb\toksc + \appendr\toksb{&}% + \ldpushplacement#7% placement + \concat\toksb\toksc + \appendr\toksb{&}% + \ldpushpheaders#7% possible pheaders + \concat\toksb\toksc + \appendr\toksb{\cr}% + \def\sections@header{}% + \fi + \ifsectioncomplete + \else + \concat\toksa\toksb + \advance\tempca\@ne + \repeat +} + +\def\ldextractitem#1#2{% + \yystringempty{#2}{% + \toksc{}% + }{% + \let\ldor\or + \toksc=\ifcase#1#2\else{}\fi + \let\ldor\relax + }% +} + +\def\ldpushalignment#1#2#3{% + \toksd=\ifcase\tempcb{#1}\or{#2}\or{#3}\else{}\fi + \yytoksempty\toksd{% + \advance\tempcb\@ne + \ifnum\tempcb<\tw@ + \yybreak{\ldpushalignment{#1}{#2}{#3}}% + \else + \yybreak{\toksc{}}% + \yycontinue + }{% + \toksc=\ifcase\tempcb{{\ttl align }}\concat\toksc\toksd\or + {{\ttl align\_with\_input}}\or + {{\ttl subalign }}\concat\toksc\toksd\fi + \advance\tempcb\@ne + }% +} + +\def\ldpushplacement#1#2#3#4{% + \ifplacementpushed + \toksc{}% + \else + \yystringempty{#1}{% any > ? + \toksc{}% + }{% + \ldextractname#1% + \toksd{{\ttl in }}% + \appendl\toksc{\the\toksd}% + }% + \yystringempty{#2}{% any AT > ? + }{% + \yytoksempty\toksc{\toksc{{\ttl as }}}{\appendr\toksc{ {\noexpand\ttl as }}}% + \toksd=\toksc + \ldextractname#2% + \concat\toksd\toksc + \toksc=\toksd + }% + \placementpushedtrue + \fi +} + +\def\ldstartpheaders#1#2#3#4{% + \tempcc=\z@ + \yystringempty{#3}{\toksc{}}{\toksc{{\ttl phdrs}}}% +} + +\def\ldextractfill#1#2#3#4{% + \yystringempty{#4}{% + \toksc{}% + \fillextractedtrue + }{% + \iffillextracted + \toksc{}% + \else + \toksc={\qquad{\ttl fill }$#4$}% + \fi + }% +} + +\def\ldpushpheaders#1#2#3#4{% + \ldextractitem\tempcc{#3}% + \advance\tempcc\@ne + \yytoksempty\toksc{}{\expandafter\ldextractname\the\toksc}% +} + +\def\ldexpwithtype#1#2#3#4#5{% TODO + \yystringempty{#2}{\toksc{$}}{\toksc{$#2}}%$ + \yystringempty{#5}{\toksd{{}$}}{#5\appendr\toksd{]$}\appendl\toksd{[}}% + \concat\toksc\toksd +} + +\defc\ldtype{% + \toksd{\hbox{\ttl #1}}% +} + +\defc\ldstatement{} +\defc\ldsectionseparator{\toksc{&\multispan5\cdotfill\quad\cr}\concat\toksa\toksc} + +\restorecs{ld-display}{\anint\ldregexp\ldassignment\ldfill} +\toyyunion{ld-parser:sections} diff --git a/support/splint/examples/ld/lstokenset.sty b/support/splint/examples/ld/lstokenset.sty new file mode 100644 index 0000000000..3ab3ae2d16 --- /dev/null +++ b/support/splint/examples/ld/lstokenset.sty @@ -0,0 +1,23 @@ +% Copyright 2012-2015, Alexander Shibakov +% This file is part of SPLinT +% +% SPLinT 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. +% +% SPLinT 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 SPLinT. If not, see <http://www.gnu.org/licenses/>. + +\prettywordpair{OPTIONAL}{{\tt opt}}% +\prettywordpair{SUFFIX}{{\tt suffix}}% +\prettywordpair{EXTENDED}{{\tt ext}}% +\prettywordpair{INTEGER}{{$[\,0\ldots9\,]\ast$}}% +\prettywordpair{IDENTIFIER}{{$[\,\hbox{\tt a}\ldots\hbox{\tt Z}\,0\ldots9\,]\ast$}}% +\prettywordpair{WILDCARD}{{{\tt *} {\rm or} {\tt ?}}}% +\prettywordpair{PERCENT_IDENTIFIER}{{\tt\%$[\,\hbox{\tt a}\ldots\hbox{\tt Z}\,0\ldots9\,]\ast$}}% diff --git a/support/splint/examples/ld/ltokenset.sty b/support/splint/examples/ld/ltokenset.sty new file mode 100644 index 0000000000..d5d0d9b1ee --- /dev/null +++ b/support/splint/examples/ld/ltokenset.sty @@ -0,0 +1,91 @@ +% Copyright 2012-2015, Alexander Shibakov +% This file is part of SPLinT +% +% SPLinT 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. +% +% SPLinT 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 SPLinT. If not, see <http://www.gnu.org/licenses/>. + +\prettywordpair{comma}{{\tt,}} +\prettywordpair{semicolon}{{\tt;}} +\prettywordpair@@{file\_NAME\_list}{\ifinheader\itbold\else\it\fi file\_{\rm name}\_list} +\prettywordpair@@{high\_level\_library\_NAME\_list}{\ifinheader\itbold\else\it\fi high\_level\_library\_{\rm name}\_list} +\prettywordpair@@{low\_level\_library\_NAME\_list}{\ifinheader\itbold\else\it\fi low\_level\_library\_{\rm name}\_list} +\prettywordpair@@{NAME}{{\rm name}} +\prettywordpair@@{LNAME}{{\rm name$_{\rm L}$}} +\prettywordpair@@{END}{{\rm end}} +\prettywordpair@@{UNARY}{{\rm unary}} +\prettywordpair@@{VERSIONK}{{\tt VERSION}$_{\rm K}$} +\prettytoken{ALIGN} +\prettytoken{MIN} +\prettytoken{MAX} +\prettytoken{TARGET} +\prettytoken{ASSERT} +\prettytoken{INSERT} +\prettywordpair@@{PLUSEQ}{{}$\MRL{+{\K}}${}} +\prettywordpair@@{MINUSEQ}{{}$\MRL{-{\K}}${}} +\prettywordpair@@{MULTEQ}{{}$\MRL{\times{\K}}${}} +\prettywordpair@@{DIVEQ}{{}$\MRL{{\div}{\K}}${}} +\prettywordpair@@{ANDEQ}{{}$\Xandxeq${}} +\prettywordpair@@{OREQ}{{}$\Xorxeq${}} +\prettywordpair@@{LSHIFTEQ}{{}$\MRL{\ll{\K}}${}} +\prettywordpair@@{RSHIFTEQ}{{}$\MRL{\gg{\K}}${}} +\prettywordpair@@{NE}{{}$\not=${}} +\prettywordpair@@{LE}{{}$\leq${}} +\prettywordpair@@{GE}{{}$\geq${}} +\prettywordpair@@{EQ}{{}$=${}} +\prettywordpair@@{OROR}{{}$\V${}} +\prettywordpair@@{ANDAND}{{}$\W${}} +\prettywordpair@@{LSHIFT}{{}$\ll${}} +\prettywordpair@@{RSHIFT}{{}$\gg${}} +\prettywordpair@@{=}{{}$\K${}} +\prettywordpair@@{+}{{}$+${}} +\prettywordpair@@{-}{{}$-${}} +\prettywordpair@@{!}{{}$\CM${}} +\prettywordpair@@{~}{{}$\R${}} +\prettywordpair@@{^}{{}$\XOR${}} +\prettywordpair@@{|}{{}$\OR${}} +\prettywordpair@@{&}{{}$\AND${}} + +\def\gtsymswitch{% + \raw exp *left *right\raw {% + {}$>${}% + } +} + +\def\gtsymswitchdefault{{\tt >}} + +\def\ltsymswitch{% + \raw exp *left *right\raw {% + {}$<${}% + } +} + +\def\ltsymswitchdefault{{\tt <}} + +\setspecialcharsfrom\gtsymswitch +\setspecialcharsfrom\ltsymswitch + +\prettywordpair@@{>}{{% + \let\default\gtsymswitchdefault + \switchon{#1}\in\gtsymswitch +}} + +\prettywordpair@@{<}{{% + \let\default\ltsymswitchdefault + \switchon{#1}\in\ltsymswitch +}} + +\prettywordpair@@{*}{\yyifsamestring{exp}{#1}{{}$\times${}}{{\tt *}}} + +\prettywordpair@@{/}{{}$/${}} + +\expandafter\prettywordpair@@\expandafter{\harmlesscomment}{{}$\div${}} |