%{
    #include <iostream>
    #include <sstream>
    #include <cstring>
    #include <latan/Global.hpp>
	#include <latan/MathCompiler.hpp>

    using namespace std;
    using namespace Latan;
%}

%pure-parser
%name-prefix="_Math_"
%locations
%defines
%error-verbose
%parse-param { Latan::MathParserState* state }
%initial-action {yylloc.last_column = 0;}
%lex-param { void* scanner }

%union
{
	double           val_double;
    char             val_char;
    char             val_str[MAXIDLENGTH];
    Latan::MathNode* val_nodept;
}

%token <val_char> ERR
%token <val_str>  FLOAT
%token <val_str>  ID

%left '+' '-'
%left '*' '/'
%left '^'
%nonassoc UMINUS

%type <val_nodept> expr

%{
	int _Math_lex(YYSTYPE* lvalp, YYLTYPE* llocp, void* scanner);

	void _Math_error(YYLTYPE* locp, MathParserState* state, const char* err)
	{
        stringstream buf;
        
        buf << *state->stream_name << ":" << locp->first_line << ":"\
            << locp->first_column << ": " << err;
        LATAN_ERROR(Parsing,buf.str());
	}

	#define scanner state->scanner
%}

%%

program:
     /* empty string */
    | expr                  {*state->data = $1;}
    ;

expr:
      FLOAT                 {$$ = new MathNode($FLOAT,NodeType::Constant);}
    | ID                    {$$ = new MathNode($ID,NodeType::Variable);}
    | '-' expr %prec UMINUS {$$ = new MathNode("-",NodeType::Operator,1,$2);}
    | expr '+' expr         {$$ = new MathNode("+",NodeType::Operator,2,$1,$3);}
    | expr '-' expr         {$$ = new MathNode("-",NodeType::Operator,2,$1,$3);}
    | expr '*' expr         {$$ = new MathNode("*",NodeType::Operator,2,$1,$3);}
    | expr '/' expr         {$$ = new MathNode("/",NodeType::Operator,2,$1,$3);}
    | expr '^' expr         {$$ = new MathNode("^",NodeType::Operator,2,$1,$3);}
    | '(' expr ')'          {$$ = $2;}
    ;