@q Copyright 2015-2022 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@> @=%}
@> @<Miscellaneous \ld\ lexer options@> @=
@> @<Ignored options@> @=
%%
@> @<Original \ld\ regular expressions@> @=
%%
@> @<Original \ld\ postamble@> @=
@g

@ @<Miscellaneous \ld\ lexer options@>=
@G(fs1)
%option nounput
@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(fs1)
%a 4000
%o 5000
@g

@ {\it Some convenient abbreviations for regular expressions.}%
@<Original \ld\ macros@>=
@G(fs1)
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(fs1)
%s SCRIPT
%s EXPRESSION
%s BOTH
%s DEFSYMEXP
%s MRI
%s VERS_START
%s VERS_SCRIPT
%s VERS_NODE
@g

@ @<Original \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@>=
@G(fs2)
@=<BOTH,SCRIPT,EXPRESSION,VERS_START,VERS_NODE,VERS_SCRIPT>"/*" {@> comment ();@+@=}@>@;
<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
}
@t}\vb{\insertraw{\insrulealign{\rulealigntemplate}{\cr\egroup\egroup}}}{@>
<MRI,EXPRESSION>@>@t}\vb{\insertraw{\insparensalign{&}{}}}{@>@=([0-9A-Fa-f])+@>@t}\vb{\insertraw{\insparensalign{\rlap{$\odot$}\cr&}{}}}{@>@=(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
}
@t}\vb{\insertraw{\insrulealign{\rulealigntemplate}{\cr\egroup\egroup}}}{@>
<SCRIPT,DEFSYMEXP,MRI,BOTH,EXPRESSION>((("$"|0[xX])([0-9A-Fa-f])+)|(([0-9])+@>@t}\vb{\insertraw{\insparensalign{\rlap{$\odot$}\cr&}{}}}{@>@=)@>@t}\vb{\insertraw{\insparensalign{&}{}}}{@>@=)(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
    @t}\C{Annoyingly, this pattern can match comments,}\6{@>
    @t}\C{and we have longest match issues to consider.}\6{@>
    @t}\C{So if the first two characters are a comment}\6{@>
    @t}\C{opening, put the input back and try again.}\6{@>
 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);
}