#include #include "include/parser.hpp" #include "include/expressions.hpp" #include "include/lexer.hpp" #include "include/exceptions.hpp" using std::string, std::stoi; // De haber habido un error vaciaremos la pila de expresiones. void Parser::panic() { for(auto ptr = tree_stack.begin(); ptr != tree_stack.end(); ++ptr) delete *ptr; throw ParserException("Sintaxis incorrecta."); } Expression *Parser::popStack() { Expression *val = tree_stack.back(); tree_stack.pop_back(); return val; } Expression *Parser::newTree(token_type type) { switch(type) { case sum: return new AddExpression(popStack(), popStack()); case substraction: return new SubExpression(popStack(), popStack()); case multiplication: return new MultiplicationExpression(popStack(), popStack()); case division: return new DivisionExpression(popStack(), popStack()); default: // Potencia. return new PowerExpression(popStack(), popStack()); } } void Parser::setText(string text) { tokenizer.setText(text); // Se prepara el lexer. var.value = "{}"; var.type = nil; } bool Parser::checkToken() { return tokenizer.getCurrentToken().type == nil; } Expression *Parser::parse(string expr) { setText(expr); parseExpr(); /* Si no se ha consumido toda la cadena, lanzamos error. */ if(tokenizer.getCurrentToken().type != nil) panic(); return popStack(); } void Parser::parseExpr() { parseTerm(); parsePrimeExpr(); } void Parser::parsePrimeExpr() { token_type current; if(tokenizer.getCurrentToken().type == sum || tokenizer.getCurrentToken().type == substraction) { current = tokenizer.getCurrentToken().type; try { tokenizer.nextToken(); } catch(const LexerException &e) { panic(); } if(checkToken()) panic(); parseTerm(); tree_stack.push_back(newTree(current)); parsePrimeExpr(); } } void Parser::parseTerm() { parsePower(); parsePrimeTerm(); } void Parser::parsePrimeTerm() { token_type current; if(tokenizer.getCurrentToken().type == multiplication || tokenizer.getCurrentToken().type == division) { current = tokenizer.getCurrentToken().type; tokenizer.nextToken(); if(checkToken()) panic(); parsePower(); tree_stack.push_back(newTree(current)); parsePrimeTerm(); } } void Parser::parsePower() { parseFactor(); parsePrimePower(); } void Parser::parsePrimePower() { if(tokenizer.getCurrentToken().type == power) { tokenizer.nextToken(); if(tokenizer.getCurrentToken().type != number) panic(); tree_stack.push_back(new Literal(stoi(tokenizer.getCurrentToken().value))); tokenizer.nextToken(); tree_stack.push_back(newTree(power)); parsePrimePower(); } } void Parser::parseFactor() { trig_functions name; switch(tokenizer.getCurrentToken().type) { case substraction: tokenizer.nextToken(); parseExpr(); tree_stack.push_back(new NegationExpression(popStack())); break; case left_parens: tokenizer.nextToken(); parseExpr(); // Consumimos paréntesis derecho. if(tokenizer.getCurrentToken().type != right_parens) panic(); tokenizer.nextToken(); break; case function: if(tokenizer.getCurrentToken().value == "sin") name = i_sin; else if(tokenizer.getCurrentToken().value == "cos") name = i_cos; else if(tokenizer.getCurrentToken().value == "tan") name = i_tan; else if(tokenizer.getCurrentToken().value == "csc") name = i_csc; else if(tokenizer.getCurrentToken().value == "sec") name = i_sec; else name = i_ctg; tokenizer.nextToken(); if(tokenizer.getCurrentToken().type != left_parens) panic(); tokenizer.nextToken(); parseExpr(); if(tokenizer.getCurrentToken().type != right_parens) panic(); tokenizer.nextToken(); tree_stack.push_back(new Function(popStack(), name)); break; case variable: /* Checamos si no se ha registrado ningún nombre de variable o si la variable leída por el lexer es la misma que la que se había leído. */ if(tokenizer.getCurrentToken().value == var.value || var.type == nil) var = tokenizer.getCurrentToken(); else panic(); // Se introdujeron dos variables en la expresión. tree_stack.push_back(new Variable(tokenizer.getCurrentToken().value[0])); tokenizer.nextToken(); break; case number: tree_stack.push_back(new Literal(stoi(tokenizer.getCurrentToken().value))); tokenizer.nextToken(); break; default: panic(); break; } }