#include <iostream>
#include <cstdlib>

using namespace std;

#include "Parser.h"

int VarX;

Parser::Parser(istream& s)
{
    is= &s;
    lex();
}

char Parser::lex()
{
    while ( !is->eof() && isspace(is->peek()) )
       is->get(); 

    if (is->eof())
       return tok= '#';

    int c= is->get();      // ultimo caracter leido
    switch (c) {
        case '0': case '1': 
        case '2': case '3': 
        case '4': case '5': 
        case '6': case '7': 
        case '8': case '9':
            is->putback(c);
            *is >> num;
            return tok= 'n'; 
        case '+':
        case '-':
        case '*':
        case '/':
        case '%':
        case '^':
        case ';':
        case '(':
        case ')':
            return tok= c;
        case 'x':
        case 'X':
            return tok= 'x';
        default:
            return tok= '#';
       }
}

char Parser::Tok() const
{
    return tok;
}

double Parser::Num() const
{
    return num;
}

Nodo* Parser::prim()
{
   Nodo* p;
   switch (Tok()) {
      case '+':
          lex();
          p= prim();
          break; 
      case '-':
          lex();
          p= new Chs(prim());
          break;
      case 'n':
          p= new Cte(Num()); 
          lex(); 
          break; 
      case 'x':
          p= new Var(&VarX); 
          lex(); 
          break; 
      case '(':
          lex();
          p= expr();
          if (Tok()==')')
             lex();
          else
             Error("Falta un parentesis )");
          break;
      default:
          Error("Falta un factor");
   }
   return p; 
}

Nodo* Parser::factor()
{
   Nodo* f= prim();
   for (;;)
      switch(Tok())
        {
         case '^' : 
               lex();
               f= new Expo(f, prim());
               break;
         default:  
               return f;
        }
}


Nodo* Parser::term()
{
   Nodo* t= factor();
   for (;;) 
      switch (Tok())
        {
         case '*':  
               lex(); 
               t= new Muls(t, factor());
               break;
         case '/':  
               lex(); 
               t= new Divs(t, factor());
               break;
         case '%':  
               lex(); 
               t= new Mods(t, factor());
               break;
         default: return t;
        }
}

Nodo* Parser::expr()
{
   Nodo* e= term();
   for (;;) 
      switch (Tok())
        {
         case '+':  
               lex(); 
               e= new Sum(e, term());
               break;
         case '-':  
               lex(); 
               e= new Res(e, term());
               break;
         default: return e;
        }
}

Nodo* Parser::Read()
{
   Nodo* p= expr();
   if (Tok()==';')
      return p;
   else
      Error("Falta un ;");
}

void Parser::Error(const char* msg)
{
    cerr << "ERROR - " << msg << endl;
    exit(1);   // mortus est, ego te absuelvo
               // pecatis tuis.
}

