% Copyright 2012-2020, 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/>.

% assigning symbolic names to production terms (this is only a demonstration)
% no attempt is made to make this code modular or namespace safe;
% the approach is not very elegant and can stand a lot of improvement;
% it was decided against such optimization to present a more explicit demonstration
% of the procedures

\def\makesymbols{%
  \ifsymdemo
      \restorecslist{symbols}\yyunion
      \toksa{}\toksb{}\toksc{}\toksd{}%
      %\showthe\newsymswitch
      \the\symstream
      \global\newsymswitch\newsymswitch
  \else
      \newsymswitch{}% otherwise \yysymswitch is trying to expand the wrong names (\namepair is not present to do \csname ... )
  \fi
}

% symbolic reference name parser

\newtoks\newsymswitch
\newread\symnames

\newwrite\symbolicswitch
\newif\ifsymdemo

\symdemotrue

\ifbootstrapmode
    \symdemofalse
\fi

\ifsymdemo
    \def\inamespace{[intermediate]}%
    \let\parsernamespace\inamespace
    \let\hostparsernamespace\mainnamespace % purely for testing reasons
    \pinittoks{}%
    \input cweb/gyytab.tex % this should be the parser that will be used later
                                            % in this case it is just an example
    \edef\tointermediateparser{%
        \let\noexpand\parsernamespace\noexpand\inamespace % switch to the new namespace
        \the\pinittoks % restore all the tables, tokens and constants, and stacks
        \let\noexpand\getcurrentparser\noexpand\tointermediateparser
    }%
    \settokens % this simply assigns values to tokens where the name of each token is taken out of yytname ...
    \input bo.tok % this will set up token equivalences in the namespace above ...
                  % those are the values gleaned during the bootstrapping stage.
                  % in the general case, one needs to run a bootsrapping (or similar)
                  % parser to extract the token information.
    \optimizeall % this is necessary for correct rule listing in the output stage:
                 % otherwise \fgetelemof will use the current value of the \yy... token registers which
                 % will hold the values of the full parser that is loaded next
    \newsymswitch{}%
    \listrules                                % ... to be used while listing the rules
    % note that we do not bother to set up a lexer for this parser (even though we already have one and the
    % \optimizeall macro above will create a set of associative tables for it---this is merely an unwanted
    % sideffect); after the rules have been listed, the intemediate parser is no longer needed.
    %\showthe\newsymswitch
    \def\fullnamespace{[full]}% this is the parser that parses the bison grammar from a raw
                              % bison file; it can play a role of the bootstrap parser for
                              % the grammar above, as well, since its input is a complete
                              % bison file; note that it cannot be a bootstrap parser for itself
                              % because it will reject any input that does not form a complete
                              % bison file; this is why a special grammar was created that includes
                              % only a small subset of the full set of productions (%token rules only) to
                              % serve as a bootstrap grammar.
    %\tomainparser % this will set the value of \setflexstates, so that, if the lexer initialization
                   % below is omitted, the \setflexstates macro can still be used to correctly set the
                   % lexer states
    \let\parsernamespace\fullnamespace
    \pinittoks{}% %%
    \input cweb/fyytab.tex
    \input cweb/ltab.tex % we reinitialize the lexer out of necessity:
                                          % \collecttokennames needs to know how to switch
                                          % between two lexer/parser environments so both states
                                          % have to be preserved; if one is sure that
                                          % grammar_declarations will not used in the productions
                                          % part of the file, this can simply be disabled
    \settokens
    \setflexstates % the main lexer can be reused in this case; the states still need to be set up
    \input bo.tok % set up the tokens for the bison grammar parser
    \newparserstate
    \newlexerstate
    \newlexerstateextra
    %
    \setnulstack{yyirulestack}%
    %
    \edef\tofullparser{%
        \let\noexpand\parsernamespace\noexpand\fullnamespace % switch to the new namespace
        \the\pinittoks % restore all the tables, tokens and constants, and stacks
        \let\noexpand\getcurrentparser\noexpand\tofullparser
    }%
    \optimizeall
    \toksa{\input bg.y}% start building the parsing command
                       % this has to be done carefully, since all the characters input
                       % from the parser file have to be `harmless', so their categories
                       % have to be reset; in order for the parser to be able to stop,
                       % appropriate command sequences would have to be inserted at the end
    \toksb{\yyeof\yyeof\endparseinput\endparse
        \let\yyinput\yyinputold
        \undoascii
        \ifyyparsefail
            \errmessage{could not process symbols}%
        \else  
            \symstream\table
            \tointermediateparser % the parsing is finished, so we have two very long strings:
                                  %  o the rules of the hosted parser ([intermediate])
                                  %  o the rules of the same parser just parsed
                                  % these two strings are used to associate the symbolic names
                                  % (which only exist in the second list) to the rule numbers and
                                  % the relevant terms;
                                  % switching the parse namespace above is done so that the term
                                  % indices are looked up in the appropriate table
            %\showthe\table
            \makesymbols % list all the rules deriving explicit non-terminals
            %\showthe\newsymswitch
            \setexplicitinlinerules\newsymswitch % process implicit non-terminals resulting from inline actions
            %\showthe\newsymswitch
            \makesymrefs\newsymswitch % create the switch to be used by the parser (\yyparse)
        \fi
    }%
    % build the command to create the symbolic name switch
    \toksc{\tofullparser\basicparserinit\bisonparserinit\bisonparserdatainit
        \let\yyinputold\yyinput
        \let\yyinput\yyinputtrivial % a demo of a stripped down, slightly faster input routine
        \doascii{11}\expandafter\yyparse}%
    \edef\next{\the\toksc\the\toksa\relax\the\toksb}\next % \relax is to stop \TeX\ from trying to expand the file name further
                                                          % it is not flagged as a bad character  because it is part of the epilogue
    \immediate\openout\symbolicswitch=\jobname.sns
    %
    \edef\next{\setsncommands{\def\noexpand\symswitch\hashletter1{\harmlesscomment^^J\noexpand\ifcase\hashletter1\relax
                                                                           \harmlesscomment^^J\the\setsncommands
                                                                           \noexpand\else\harmlesscomment^^J%
                                                                           \noexpand\fi\harmlesscomment^^J%
                                                                           }\harmlesscomment^^J^^J}}\next
    \edef\next{\unsetsncommands{\def\noexpand\symswitchoff\hashletter1{\harmlesscomment^^J\noexpand\ifcase\hashletter1\relax
                                                                           \harmlesscomment^^J\the\unsetsncommands
                                                                           \noexpand\else\harmlesscomment^^J%
                                                                           \noexpand\fi\harmlesscomment^^J%
                                                                           }\harmlesscomment^^J^^J}}\next
    {\newlinechar=`\^^J \immediate\write\symbolicswitch{\the\setsncommands\the\unsetsncommands}}%
    \immediate\closeout\symbolicswitch
    \tomainparser % go back to the main parser
%
%   \flex\ parser test
%    
    {%
        \toflexreparser
        \basicparserinit
        \flexreparserinit
        \flexreparserdatainit
        \yyBEGIN{SECT2}%
        \flin@ruletrue
        % special status of `\yl' in \CWEB\ makes the following workaround necessary
        % if the code is unsed inside a \CWEB\ file
        %|@t}\expandafter\yyparse\space [a-b]*(c|d|e)?\yyeof\yyeof\endparseinput\endparse{@>|
        \expandafter\yyparse\space [a-b]*(c|d|e)?\yyeof\yyeof\endparseinput\endparse
        \ifyyparsefail\else
            \ferrmessage{done processing flex}%
        \fi
    }%    
%
    {%
        \def\flnamespace{[flex]}
        \let\parsernamespace\flnamespace
        \toflexparser
        \basicparserinit
        %\flexparserinit
        \flexparserdatainit
        \yylessusedtrue % TODO: put it in the \genericparser command
        \let\f@nishparse\finishparse
        \def\finishparse{\endinput\message{end of input}\relax\let\cleanupcs\f@nishparse}%
        \def\next{%
            \catcode`\\=12
            \catcode`\^^J=12
            \catcode`\%=12
            \catcode`\^^M=12
            \catcode`\{=12
            \catcode`\}=12
            \catcode`\#=12
            \catcode`\_=12
            %\yydebugmost
            \expandafter\yyparse\input cweb/lo.l \cleanupcs\yyeof\yyeof\endparseinput\endparse % note that the space after the file name is necessary
            \ifyyparsefail
                \errmessage{stopped}%
            \fi
            \yydebugnone
            \basicparserinit
            \expandafter\yyparse\input cweb/fil.l \cleanupcs\yyeof\yyeof\endparseinput\endparse 
            % note that the space after the file name is necessary
        }\expandafter\next % to lock the \catcode of the brace
    }%
\fi
