-- RECONNAISSEUR POUR DES EXPRESSIONS AVEC PRIORITE.
--
--  Grammaire LL(1) :
--              Calc   ::=   E = Calc | =     {num,=}
--              E      ::=   T SE             {num}
--              SE     ::=   epsilon          {=}
--              SE     ::=   + T SE           {+}
--              SE     ::=   - T SE           {-}
--              T      ::=   F  ST            {num}
--              ST     ::=   epsilon          {=, +, -}
--              ST     ::=   * F ST           {*}
--              F      ::=   num              {num}
--
-- Lexicographie :   num       ::=   chiffre+
--                   chiffre   ::=   '0' | ... | '9'
--                   separ     ::=   ' ' | retour-ligne
--
-- procedure eval_calc ;
--    . teste si une entrée est correcte
--    . leve erreur_syntaxique si ce n'est pas le cas
--    . utilise la fonction lire_mot
--
-- function lire_mot return TOKEN ;
--    . reconnait un mot à partir du premier caractère non reconnu de la ligne
--    . lève erreur_lexicale si la reconnaissance est impossible
--    . utilise la fonction lire_car
--
-- function lire_car return character ;
--    . lit un caractère


with text_io; use text_io;

procedure priorite is

   type Token is (NUM, PLUS, MOINS, MULT, EGAL, FF);
   --PARENTHESES type TOKEN is (NUM, PLUS, MOINS, MULT, EGAL, FF, PAR_OUV, PAR_FERM);
   subtype Op is Token range PLUS .. MULT;
   cc : Character;
   Val: Integer;      -- la valeur de la constante lue
   erreur_lexicale, erreur_syntaxique, internal_exception : exception;

   mot_cour : Token;

   subtype Indice is Character range '0'..'9';
   Chiffres: constant array(Indice) of Natural := (0,1,2,3,4,5,6,7,8,9);

   -- FONCTION LIRE_CAR
   function lire_car return character is
   begin
      if end_of_file then return ASCII.NUL;
      elsif end_of_line then skip_line ; return ASCII.LF;
      else get(cc); return cc ; end if;
   end lire_car;

   -- FONCTION LIRE_MOT
   function lire_mot return Token is
   begin
      -- on saute les séparateurs
      while cc = ' ' or cc=ASCII.LF loop cc := lire_car; end loop;
      case cc is
         when '0'..'9' => Val :=  Chiffres(cc);
                          cc := lire_car;
                          while cc in '0'..'9'  loop
                             Val := Val * 10 + Chiffres(cc);
                             cc := lire_car;
                          end loop;
                          return(NUM);
         when  '+' => cc := lire_car; return(PLUS);
         when  '-' => cc := lire_car; return(MOINS);
         when  '*' => cc := lire_car; return(MULT);
         when '='  => cc := lire_car; return (EGAL);
         --PARENTHESES when '(' => cc := lire_car; return (PAR_OUV);
         --PARENTHESES when ')' => cc := lire_car; return (PAR_FERM);
         when ASCII.NUL => return (FF);
         when others => raise erreur_lexicale;
      end case;
   end lire_mot ;

   -- FONCTION APPLIQUER
   function Appliquer(Oper : Op; H : Integer; V : Integer) return Integer is
   begin
      case Oper is
         when PLUS  => return(H + V);
         when MOINS => return(H - V);
         when MULT  => return(H * V);
         when others => raise internal_exception ;
      end case;
   end appliquer ;

   procedure E;
   procedure SE;
   procedure T;
   procedure ST;
   procedure F;

   -- PROCEDURE E
   procedure E is
   begin
      T;
      SE;
   end E;

   -- PROCEDURE SE
   procedure SE is
   begin
      case mot_cour is
         when PLUS | MOINS => mot_cour := lire_mot;
                              T;
                              SE;
         when EGAL => null;
         when others => raise erreur_syntaxique;
      end case ;
   end SE ;

   -- PROCEDURE T
   procedure T is
   begin
      F;
      ST;
   end T;

   -- PROCEDURE ST
   procedure ST  is
   begin
      case mot_cour is
         when MULT => mot_cour := lire_mot;
                      F;
                      ST;
         when EGAL| PLUS| MOINS => null;
         when others => raise erreur_syntaxique;
      end case ;
   end ST ;

   -- PROCEDURE F
   procedure F is
   begin
      case mot_cour is
         when NUM => mot_cour:= lire_mot;
         when others => raise erreur_syntaxique;
      end case;
   end F;

   -- PROCEDURE EVAL_CALC
   procedure eval_calc is
   begin
      mot_cour := lire_mot;
      while mot_cour /= EGAL loop
         E;
         if mot_cour /= EGAL then raise erreur_syntaxique; end if;
         mot_cour := lire_mot;
      end loop;
      mot_cour := lire_mot;
      if mot_cour /= FF then raise erreur_syntaxique; end if;
   end eval_calc;

-- CORPS DE PRIORITE
begin
   cc := lire_car;   -- pour respect invariant de lire_mot
   eval_calc;

exception
   when erreur_lexicale => put_line ("erreur lexicale");
   when erreur_syntaxique => put_line ("erreur syntaxique");
   when internal_exception => put_line ("erreur interne");

end priorite;
