#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_queue.begin(); ptr != tree_queue.end(); ++ptr) delete *ptr; tree_queue.clear(); throw ParserException("Sintaxis incorrecta."); } Expression *Parser::popQueue() { Expression *val = tree_queue.front(); tree_queue.pop_front(); return val; } Expression *Parser::newTree(token_type type, Expression *left, Expression *right) { switch(type) { case sum: return new AddExpression(left, right); case substraction: return new SubExpression(left, right); case multiplication: return new MultiplicationExpression(left, right); case division: return new DivisionExpression(left, right); default: // Potencia. return new PowerExpression(left, right); } } 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 popQueue(); } void Parser::parseExpr() { parseTerm(); parsePrimeExpr(); } void Parser::parsePrimeExpr() { token_type current; Expression *left, *right; if(tokenizer.getCurrentToken().type == sum || tokenizer.getCurrentToken().type == substraction) { current = tokenizer.getCurrentToken().type; tokenizer.nextToken(); if(checkToken()) panic(); left = popQueue(); parseTerm(); right = popQueue(); tree_queue.push_back(newTree(current, left, right)); parsePrimeExpr(); } } void Parser::parseTerm() { parsePower(); parsePrimeTerm(); } void Parser::parsePrimeTerm() { token_type current; Expression *left, *right; if(tokenizer.getCurrentToken().type == multiplication || tokenizer.getCurrentToken().type == division) { current = tokenizer.getCurrentToken().type; tokenizer.nextToken(); if(checkToken()) panic(); left = popQueue(); parsePower(); right = popQueue(); tree_queue.push_back(newTree(current, left, right)); parsePrimeTerm(); } } void Parser::parsePower() { parseFactor(); parsePrimePower(); } void Parser::parsePrimePower() { Expression *left, *right; if(tokenizer.getCurrentToken().type == power) { tokenizer.nextToken(); if(tokenizer.getCurrentToken().type != number || tokenizer.getCurrentToken().value == "0") panic(); left = popQueue(); right = new Literal(stoi(tokenizer.getCurrentToken().value)); tokenizer.nextToken(); tree_queue.push_back(newTree(power, left, right)); parsePrimePower(); } } void Parser::parseFactor() { trig_functions name; switch(tokenizer.getCurrentToken().type) { case substraction: tokenizer.nextToken(); parseExpr(); tree_queue.push_back(new NegationExpression(popQueue())); 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_queue.push_back(new Function(popQueue(), 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_queue.push_back(new Variable(tokenizer.getCurrentToken().value[0])); tokenizer.nextToken(); break; case number: tree_queue.push_back(new Literal(stoi(tokenizer.getCurrentToken().value))); tokenizer.nextToken(); break; default: panic(); break; } }