-------------------------------------------------------------------------------
-- (C) Altran Praxis Limited
-------------------------------------------------------------------------------
--
-- The SPARK toolset is free software; you can redistribute it and/or modify it
-- under terms of the GNU General Public License as published by the Free
-- Software Foundation; either version 3, or (at your option) any later
-- version. The SPARK toolset 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 distributed with the SPARK toolset; see file
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy of
-- the license.
--
--=============================================================================

separate (SP_Parser_Actions)
function SPA (CST : SP_Productions.Valid_States;
              CSY : SP_Symbols.SP_Terminal) return SP_Parse_Act is
   Index_Pair                          : Packed_PAT_Index_Pair;
   Index, Max_Index                    : PAT_Index;
   CSY_POS, Next_Symbol, Packed_Result : Packed_Sym_Action_Pair;
   Result                              : SP_Parse_Act;
begin -- SPA
   CSY_POS     := SP_Symbols.SP_Terminal'Pos (CSY);
   Index_Pair  := State_Table (CST);
   Index       := PAT_Index (Index_Pair mod PAT_Index_Size);
   Max_Index   := PAT_Index (Index_Pair / PAT_Index_Size);
   Next_Symbol := Parse_Action_Table (Index) mod Term_Sym_Lim;
   while Next_Symbol /= CSY_POS and then Index < Max_Index loop
      Index       := Index + 1;
      Next_Symbol := Parse_Action_Table (Index) mod Term_Sym_Lim;
   end loop;
   if Next_Symbol /= CSY_POS and then Next_Symbol /= Default then
      Result := Error_Action;
   else
      Packed_Result := Parse_Action_Table (Index);
      case SP_Action_Kind'Val ((Packed_Result / Act) mod Act_Lim) is
         when Shift =>
            Result :=
              SP_Parse_Act'
              (Act     => Shift,
               State   => SP_Productions.SP_State ((Packed_Result / State) mod State_Lim),
               Symbol  => No_Sym,
               Red_By  => No_Red,
               Prod_No => No_Prod);
         when Reduce =>
            Result :=
              SP_Parse_Act'
              (Reduce,
               SP_Productions.No_State,
               SP_Symbols.SP_Symbol'Val ((Packed_Result / Symbol) mod Symbol_Lim + First_Non_Terminal),
               SP_Productions.SP_Right ((Packed_Result / Red_By) mod Red_By_Lim),
               0);
         when Accpt =>
            if Next_Symbol = CSY_POS then
               Result := Accept_Action;
            else
               Result := Error_Action;
            end if;
         when Error =>               -- can never have this option
            Result := Error_Action;
      end case;
   end if;
   return Result;
end SPA;
