% 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/>.

% global variables: current token, state, variable to store various table indices

\def\yyparse{%
  \yylen=\z@ %
  \yyinitstack\yyssa % state stack
  \yyinitstack\yyvsa % data stack
  \yystate=\z@ %
  \yychar=\YYEMPTY\relax
  \yylval{}% bogus value
  \yynewstate
}

\newif\iftracestacks
\newif\iftraceparserstates
\newif\iftracerules

\def\yynewstate{%
  \ifnum\yystate=\YYFINAL\relax
      \yybreak\yypaccept
  \else
      \yypushr\yystate\on\yyssa
      {%
          \iftraceparserstates
              \derrmessage{^^Jstate \the\yystate\iftracestacks, \fi}%
          \fi
          \iftracestacks
              \iftraceparserstates
              \else
                  \derrmessage{^^J}%
              \fi
              \showstack\yyssa\derrmessage{state stack: \stackcs^^J}%
          \fi
      }%
      \yybreak\yybackup
  \yycontinue
}

\def\yybackup{%
  \yyn=\fgetelemof{yypact}\at\yystate\relax
                                    % yyn = yypact[yystate]
  \ifnum\yyn=\YYPACTNINF\relax      % if (yyn == YYPACT_NINF) (if(yypact_value_is_default(yyn)))
      \yybreak\yydefault            %     goto yydefault
  \else                             % else
      \ifnum\yychar=\YYEMPTY\relax  %     if (yychar == YYEMPTY)
                                    % ... ... if desired, this is where `hidden context' may be inserted
                                    % ... ... for example:
                                    % ... ... \gethidden\yychar
                                    % ... ... \ifnum\yychar=\YYEMPTY\relax
                                    % ... ...     \yybreak@@\yylex
                                    % ... ... \else
                                    % ... ...     \yybreak@@\yyparsetail
                                    % ... ... \fi
                                    % ... ... here \gethidden#1 is a hidden context-extracting macro that
                                    % ... ... takes a token value from a special stream and puts it in #1
                                    % ... ... filling this special stream should be done by the lexer, 
                                    % ... ... respecting any state changes required.
          \yybreak@\yylex           %         yychar = YYLEX
      \else
          \yybreak@\yyparsetail
      \fi
  \yycontinue
}

\newif\iftracelookahead

\def\yyparsetail{% this is where the lexer returns
  \ifnum\yychar>\YYEOF\relax        % if (yychar > YYEOF)
      \yytoken=\fgetelemof{yytranslate}\at\yychar\relax
      \iftracelookahead
          \derrmessage{lookahead: \tokname, value: \the\yylval^^J}%
      \fi
                                    %     yytoken = yytranslate[yychar]
  \else                             % else
      \yychar=\YYEOF\relax          %     yychar = yytoken = YYEOF
      \yytoken=\YYEOF\relax
  \fi% valid lookahead token
  \advance\yyn by\yytoken           % yyn = yypact[yystate] + yytoken
  \ifnum\yyn<\z@
      \yybreak\yydefault
  \else 
      \ifnum\yyn>\YYLAST\relax
          \yybreak@\yydefault
      \else
          \ifnum\fgetelemof{yycheck}\at\yyn=\yytoken      
                                    % if (yyn >= 0 && yyn <= YYLAST &&
                                    %           yytoken == yycheck[yyn])
              \yyn=\fgetelemof{yytable}\at\yyn\relax
                                    %     yyn = yytable[ yypact[yystate] + yytoken ]
              \ifnum\yyn>\z@        %     if (yyn > 0) ...shift
                  \iftraceactions
                      \derrmessage{shifting \tokname^^J}%
                  \fi
                  \yystate=\yyn     %         yystate = yytable[ yypact[yystate] + yytoken ]
                  \yychar=\YYEMPTY\relax  
                                    %         yychar = YYEMPTY ...drop
                                    %                          ...the
                                    %                          ...shifted token 
                  \yypushr\yylval\on\yyvsa
                                    %         ...shift the value
                                    %         *++yyvsa = yylval
                  \yybreak@@@\yynewstate % new state will be shifted
              \else                 % ...if (yyn < 0)
                  \iffalse          % if (yytable_value_is_error(yyn))
                                    % \ifnum\yyn=\YYTABLEERROR\relax
                      \yybreak@@@@\yyerr
                  \else             
                      \yyn=-\yyn
                      \yybreak@@@@\yyreduce
                  \fi
              \fi
          \else
              \yybreak@@\yydefault% goto yydefault
          \fi
      \fi
  \yycontinue
}

\newif\iftraceactions

\def\yydefault{%
  \yyn=\fgetelemof{yydefact}\at\yystate\relax
                                      % yyn = yydefact[yystate]
  \iftraceactions
      \derrmessage{default action^^J}%
  \fi
  \ifnum\yyn=\z@
      \xskiptofi\yyerr
  \else
      \xskiptofi\yyreduce             % if (yyn != 0) goto yyreduce
  \fi
}

\def\yyreduce{%
  \yylen=\fgetelemof{yyrtwo}\at\yyn\relax
  \iftracerules
      \derrmessage{^^Jreducing (rule \the\yyn)}\printrule{\yyn}%
  \fi
  {%
       \iftracestacks
           \iftracerules
           \else
               \derrmessage{^^J}%
           \fi
           \showstack\yyssa
           \derrmessage{stack: \stackcs^^Jpopping \the\yylen^^J}%
       \fi
  }%
  \yyilen=\fgetelemof{yyrthree}\at\yyn\relax
  \ifnum\yyilen>\z@ % this is an inline rule
      \ifnum\yylen>\z@
          \errmessage{an inline rule with a nontrivial left hand side: rule \the\yyn}%
      \fi
  \else
      \yyilen\yylen
  \fi
  \ifnum\yyilen>\z@
      \yypeekvstack\yyvsa\upto\yyilen
      \yyval\csname $$'1\endcsname % $$ = $1
  \fi
  %
  \yyaction % value
  %
  \yypopstack\yyvsa\by\yylen
  \yypopstack\yyssa\by\yylen           % YYPOPSTACK(yylen)
  \yypushr\yyval\on\yyvsa 
                                       % ...push the computed
                                       % ...value on the value stack
                                       %
  \yyn=\fgetelemof{yyrone}\at\yyn\relax
                                       % yyn = yyr1[yyn]
                                       %
  \yylen\yyn                           % 
  \advance\yylen-\YYNTOKENS\relax      % ...reuse yylen
  \yystate=\fgetelemof{yypgoto}\at\yylen\relax
                                       % yystate = yypgoto[ yyn - YYNTOKENS ]
  \yyreadstackr\yyssa\at\z@\to\yyilen  % 
                                       % ...reuse yyilen
  \advance\yystate\yyilen              % yystate = yypgoto[ yyn - YYNTOKENS ] + yyssa[0]
                                       %
  \ifnum\yystate<\z@                   % if (yystate < 0)
      \yystate=\fgetelemof{yydefgoto}\at\yylen\relax 
                                       %     yystate = yydefgoto[ yyn - YYNTOKENS ]
  \else                                % else
      \ifnum\yystate>\YYLAST\relax     %     ...
          \yystate=\fgetelemof{yydefgoto}\at\yylen\relax
      \else
          \ifnum\fgetelemof{yycheck}\at\yystate=\yyilen            
                                       % if (yystate >= 0 && yystate <= YYLAST && yyssa[0] == yycheck[yystate])
                                       %
              \yystate=\fgetelemof{yytable}\at\yystate\relax
                                       %     yystate = yytable[yystate]
          \else
              \yystate=\fgetelemof{yydefgoto}\at\yylen\relax
          \fi
      \fi
  \fi
  \yylen=\z@
  \yynewstate
}

\newif\iftraceparseresults

\def\yypaccept{%
    \iftraceparseresults
        \derrmessage{accepted^^J}%
    \fi
    \finishparse
}

\def\yyerr{%
    \iftraceparseresults
        \derrmessage{(parse) error^^J}%
    \fi
    \cleanupparse
}

% no symbolic name support by default

\let\yysymswitch\eatone
\let\yysymcleanup\eatone

\def\derrmessage#1{{%
  \newlinechar=`\^^J%
  \edef\tokname{\fgetelemof{yytname}\at\yytoken}%
  \message{#1}%
}}

% these macros reuse dedicated counters ... locally

\def\printrule#1{{% some values are computed several times to save on register assignments
                  % this has more to do with not polluting the namespace than speed
    \edef\ruleline{\space\space\space\fgetelemof{yytname}\at{\fgetelemof{yyrone}\at{#1}}:}%
    \yyn=\fgetelemof{yyprhs}\at{#1}
    \ifnum\fgetelemof{yyrhs}\at\yyn>\m@ne
        \loop
            \edef\ruleline{\ruleline\space\fgetelemof{yytname}\at{\fgetelemof{yyrhs}\at\yyn}}%
            \advance\yyn\@ne
        \ifnum\fgetelemof{yyrhs}\at\yyn>\m@ne
        \repeat
    \else
        \edef\ruleline{\ruleline\space<empty>}%
    \fi
    \message{ -->\ruleline}%
}}

% print the rule without using yyprhs and yyrhs (necessary if using
% bison version 3.0 or above)

\def\printrule#1{{%
    \edef\ruleline{\space\space\space\fgetelemof{yytname}\at{\fgetelemof{yyrone}\at{#1}}:}%
    \ifnum\yylen>\z@
        \yypeeksstack\yyssa\upto\yylen\withprefix{\appendtoruleline}%
    \else
        \edef\ruleline{\ruleline\space<empty>}%
    \fi
    \message{ -->\ruleline}%
}}

\def\appendtoruleline#1{%
    \edef\ruleline{\ruleline\space\fgetelemof{yytname}\at{\fgetelemof{yystos}\at{#1}}}%
}

% the two control sequences below are replaced in yyfaststack.sty 
% to match the appropriate stack implementation 

\def\showstacksym#1{%
  \edef\stackcs{\stackcs^^J \space\space\fgetelemof{yytname}\at{\fgetelemof{yystos}\at{#1}}}%
}

\def\showstack#1{%
    \def\stackcs{}%
    \let\sts\showstacksym
    #1%
}

\newif\iftracediscardedinput

\long\def\cleanupparse#1\endparse{%
    \iftracediscardedinput
        \immediate\write16{discarding the rest of the input}%
    \fi
    \yyerror
}

\newif\ifyyparsefail

\def\yyerror{\yyparsefailtrue}

\long\def\finishparse#1\endparseinput{%
    \yystringempty{#1}{}{\yylval{#1}\immediate\write16{skipping: \the\yylval}}%
}
\let\endparse\relax
\let\endparseinput\relax

% action code

\def\yyaction{%
    \yysymswitch{\yyn}% setting symbol names
    % the big switch, set \yyval
    \yybigswitch{\yyn}%
    %
    \yysymcleanup{\yyn}% removing symbol names from the namespace
}
