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

% parser environment

\newif\ifyyskipparse
\newif\ifsaveparseoutput
\newif\ifchecktable
\newif\ifchecktrim

\newwrite\exampletable

\def\basicparserinit{%
    \yytext{}%
    \yytextpure{}%
    \yytextseenpure{}%
    \yytextseen{}%
    \yybyte{}%
    \yyfbyte{}\yysbyte{}%
    \yystash{}%
    \yystashseen{}%
    \yyformat{}%
    \yyformatseen{}%
    \yyfutureyytext{}%
    \yyinitstack\yystatestack
    \yyfmark=\z@
    \yysmark=\z@
    \yyfmarklast=\z@
    \formatmarker=\z@
    \yysmarklast=\z@
    \stashmarker=\z@
    \yytextbackupfalse
    \yyg@yyinit=\z@
    \yyg@yystart=\z@
    \YYATBOL=\@ne
    \yyparsefailfalse
    \YYEOBLASTMATCHtrue
}

\def\parserinit{%
    \basicparserinit
    \yyinitstack\obstackforstring
    \yyinitstack\obstackforstringraw
    \percentpercentcount=\z@
    \lonesting=\z@
    \laststring{}\laststringraw{}%
    \currentlaststring{}\currentlaststringraw{}%
    \parserdatainit
}

\def\parserdatainit{%
    % make control sequences inserted by the parser non expandable to facilitate
    % token list manipulation; currently nothing is done
}

% optimization options

\def\optimizeall{%
        % lexer
    \ifnum\optimization>\z@
        \optimize{yynxt}%
        \optimize{yyaccept}%
        \optimize{yydef}%
        \optimize{yychk}%
        \optimize{yybase}%
        \optimize{yyec}%
        \optimize{yymeta}%
        \tracingstats=\@ne
    \fi
        % parser
    \ifnum\optimization>\@ne
        \optimize{yytranslate}%
        \optimize{yyrone}%
        \optimize{yyrtwo}%
        \optimize{yyrthree}%
        \optimize{yydefact}%
        \optimize{yydefgoto}%
        \optimize{yypact}%
        \optimize{yypgoto}%
        \optimize{yytable}%
        \optimize{yycheck}%
        \optimize{yyprhs}%
        \optimize{yyrhs}%
        \optimize{yytoknum}%
        \optimize{yystos}%
        \optimizetext{yytname}%
    \fi
}

\long\def\endgsec#1#2#3{%
    \ifyyskipparse
        \yybreak{\unparse{#3}}%
    \else
        \yybreak{\csname parserstack[#2]\endcsname{#1}{#3}}%
    \yycontinue
}

\let\endcprod\endgroup
\let\endmprod\endgroup
\let\endprod\endgroup

\def\genericparser name: #1, ptables: #2, ltables: #3, tokens: #4, asetup: #5, dsetup: #6, rsetup: #7, optimization: #8;{%
    % parser initialization
    %
    \expandafter\def\csname #1namespace\endcsname{[#1]}%
    \savecs{local-namespace}\parsernamespace
    \expandafter\let\expandafter\parsernamespace\csname #1namespace\endcsname
    \pinittoks{}%
    \input #2 % load main parser table
    \settokens % set the values of all tokens
    \yystringempty{#4}{}{%
        \input #4 % use token equivalence table to set the values of non-string tokens
    }%
    #5% additional setups
    %
    \input #3 % load lexer tables
    %
    % at this point the macros inside the table files (\newtable, \constset, 
    % \yybigswitch, \stashswitch, \addname, \yydoactionswitch, \setflexstates, 
    % \stateset, \tokeneq) have set up the corresponding stuctures in 
    % the `parser namespace' (e.g. if the parser namespace is `main', 
    % \newtable{yyaccept} created a token register \yyaccept[main]), 
    % assigned the `generic' names to them (to continue 
    % the example above, \newtable does \let\yyaccept\yyaccept[main]) and 
    % recorded the corresponding commands in \pinittoks for future use.
    %
    % lexer state macros are namespace specific (just like token names) 
    % so they have to be set in each namespace.
    %
    \setflexstates
    #8% possible optimization
    %
    % finally, we add the definitions for the variables used in running 
    % the lexer and the parser.
    \newparserstate
    \newlexerstate
    #6% additional data setup (say, \newlexerstateextra)
    %
    % we record all the commands necessary to switch to the desired namespace 
    % in a convenient macro
    \expandafter\edef\csname to#1parser\endcsname{%
        \noexpand\savefullstate % save the state of the current parser
        #7% any data that needs to be saved
        % switch to the new namespace
        \let\noexpand\parsernamespace\expandafter\noexpand\csname #1namespace\endcsname 
        \the\pinittoks % restore all the tables, tokens and constants, and stacks
        \let\noexpand\getcurrentparser\expandafter\noexpand\csname to#1parser\endcsname
    }%
    \restorecs{local-namespace}\parsernamespace
}

\def\genericprettytokens namespace: #1, tokens: #2, correction: #3, host: #4;{%
    \savecs{local-namespace}{\parsernamespace\tokeneq}%
        \yystringempty{#2}{}{%
            \expandafter\let\expandafter\parsernamespace\csname #1namespace\endcsname
            \def\tokeneq##1##2{\prettytoken{##1}}%
            \let\tokenpp\prettytoken
            \input #2 % /* re-use token equivalence table to set the typesetting of tokens */
        }%
        \yystringempty{#3}{}{%
            \expandafter\let\expandafter\parsernamespace\csname #1namespace\endcsname
            \input #3 % input customized typesetting rules for tokens
        }%
        \yystringempty{#4}{}{%
            \expandafter\let\expandafter\hostparsernamespace\csname #4namespace\endcsname
        }%
    \restorecs{local-namespace}{\parsernamespace\tokeneq}%
}
