From 531f8f2f1adc1c6777920f0a8c68caaee30b0fc4 Mon Sep 17 00:00:00 2001 From: HombreLaser Date: Sun, 10 Apr 2022 10:21:12 -0500 Subject: Corregidos errores de las expresiones. --- exceptions.cpp | 2 +- expressions.cpp | 29 +++++---- include/exceptions.hpp | 2 +- include/expressions.hpp | 1 + include/lexer.hpp | 3 +- include/parser.hpp | 8 ++- lexer.cpp | 16 ++--- main.cpp | 21 +++---- makefile | 4 +- parser.cpp | 153 ++++++++++++++++++++++++++++++++++++------------ 10 files changed, 159 insertions(+), 80 deletions(-) diff --git a/exceptions.cpp b/exceptions.cpp index 23ca88b..a497fea 100644 --- a/exceptions.cpp +++ b/exceptions.cpp @@ -3,6 +3,6 @@ using std::string; -string Exception::showMsg(){ +string Exception::showMsg() const { return error_msg; } diff --git a/expressions.cpp b/expressions.cpp index 722794f..08520f7 100644 --- a/expressions.cpp +++ b/expressions.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include "include/lexer.hpp" @@ -7,7 +6,7 @@ using std::string, std::to_string; -// Literal +// Literal o constante. Literal::Literal(int value) : Expression(NULL, NULL, number) { this->value = value; } @@ -18,11 +17,15 @@ void Literal::setRepr() { repr = to_string(value); } -float Literal::eval(int arg) { +int Literal::getValue() { return value; } -// Function. +float Literal::eval(int arg) { + return getValue(); +} + +// Función. Function::Function(Expression *arg, trig_functions name) : Expression(NULL, NULL, function) { this->arg = arg; function_name = name; @@ -32,6 +35,10 @@ Function::~Function() { delTree(); } +const Expression *Function::getArg() { + return arg; +} + trig_functions Function::getFunctionName() { return function_name; } @@ -54,7 +61,7 @@ float Function::eval(int arg) { return std::asin(function_arg); case i_sec: return std::acos(function_arg); - case i_ctg: + default: // Cotangente. return std::atan(function_arg); } } @@ -101,14 +108,14 @@ Variable::Variable(char name) : Expression(NULL, NULL, variable) { Variable::~Variable() {} void Variable::setRepr() { - repr += name; + repr = string{name}; } float Variable::eval(int arg) { return arg; } -// Sum. +// Suma. AddExpression::AddExpression(Expression *left, Expression *right) : Expression(left, right, sum) {} @@ -123,7 +130,7 @@ float AddExpression::eval(int arg) { return right_val + left_val; } -// Substraction. +// Substracción. SubExpression::SubExpression(Expression *left, Expression *right) : Expression(left, right, substraction) {} @@ -138,7 +145,7 @@ float SubExpression::eval(int arg) { return right_val - left_val; } -// Negation. +// Negación. NegationExpression::NegationExpression(Expression *right) : Expression(NULL, right, substraction) {} @@ -172,7 +179,7 @@ float DivisionExpression::eval(int arg) { return left_val / right_val; } -// Multiplication. +// Multiplicación. MultiplicationExpression::MultiplicationExpression(Expression *left, Expression *right) : Expression(left, right, multiplication) {} @@ -188,7 +195,7 @@ float MultiplicationExpression::eval(int arg) { return left_val * right_val; } -// Power. +// Potencia. PowerExpression::PowerExpression(Expression *left, Expression *right) : Expression(left, right, power) {} diff --git a/include/exceptions.hpp b/include/exceptions.hpp index 4b5fcfa..050779d 100644 --- a/include/exceptions.hpp +++ b/include/exceptions.hpp @@ -12,7 +12,7 @@ private: std::string error_msg; public: explicit Exception(const std::string &error_msg): error_msg(error_msg){} - std::string showMsg(); + std::string showMsg() const; }; class LexerException: public Exception{ diff --git a/include/expressions.hpp b/include/expressions.hpp index 974612d..b7a2921 100644 --- a/include/expressions.hpp +++ b/include/expressions.hpp @@ -59,6 +59,7 @@ private: public: Function(Expression *arg, trig_functions name); ~Function(); + const Expression *getArg(); float eval(int arg) override; trig_functions getFunctionName(); protected: diff --git a/include/lexer.hpp b/include/lexer.hpp index 39d8411..9c12d03 100644 --- a/include/lexer.hpp +++ b/include/lexer.hpp @@ -29,12 +29,11 @@ struct Token{ class Lexer{ private: - char var_name; std::string text; size_t current_char; Token current_token; - bool matchFunction(const std::string &function_name); std::string createNumber(); + bool matchFunction(const std::string &function_name); public: Lexer(std::string text = {}); void setText(std::string text); diff --git a/include/parser.hpp b/include/parser.hpp index 02471d8..3f0032b 100644 --- a/include/parser.hpp +++ b/include/parser.hpp @@ -4,6 +4,7 @@ #include #include +#include "expressions.hpp" #include "lexer.hpp" #ifndef PARSER_H #define PARSER_H @@ -12,6 +13,11 @@ class Parser{ private: std::string text; Lexer tokenizer; + std::vector tree_stack; + Token var{nil, "{}"}; + void panic(); + Expression *popStack(); + Expression *newTree(token_type type); void setText(std::string text); void parseExpr(); void parsePrimeExpr(); @@ -22,7 +28,7 @@ private: void parseFactor(); bool checkToken(); // Checa el token actual del lexer. public: - void parse(std::string expr); + Expression *parse(std::string expr); }; #endif /* PARSER_H */ diff --git a/lexer.cpp b/lexer.cpp index 666b999..a9734d1 100644 --- a/lexer.cpp +++ b/lexer.cpp @@ -18,7 +18,6 @@ void Lexer::setText(string text){ // Inicializamos el lexer. current_char = 0; current_token = nextToken(); - var_name = '\0'; } Token Lexer::getCurrentToken(){ @@ -49,6 +48,7 @@ string Lexer::createNumber(){ } Token Lexer::match(){ + char var_name; // Si ya consumimos todo el texto, // regresamos nil. if(current_char >= text.length()) @@ -73,18 +73,10 @@ Token Lexer::match(){ if(isalpha(text[current_char])) { - /* Si es la primera vez que se lee un token variable o - si la variable leída es igual a la anteriormente leída. */ - if(var_name == '\0' || var_name == text[current_char]) - { - var_name = text[current_char]; - ++current_char; + var_name = text[current_char]; + ++current_char; - return Token(variable, string(1, var_name)); - } - - // Error, se introdujo una expresión con dos o más variables. - throw LexerException("Encontrada más de una variable."); + return Token(variable, string(1, var_name)); } /* El token actual no es ni una variable, número o función. diff --git a/main.cpp b/main.cpp index a7e81bb..0d95196 100644 --- a/main.cpp +++ b/main.cpp @@ -4,6 +4,7 @@ #include #include #include "include/parser.hpp" +#include "include/expressions.hpp" #include "include/exceptions.hpp" using std::string, std::cin, std::cout, std::getline, std::vector, @@ -15,19 +16,13 @@ int main(){ getline(cin, input); - try - { - parser.parse(input); - cout << "Todo correcto." << endl; - } - catch(ParserException e) - { - cout << e.showMsg() << endl; - } - catch(LexerException e) - { - cout << e.showMsg() << endl; - } + //try { + Expression *tree = parser.parse(input); + cout << tree->getRepr() << endl; + //} catch(const ParserException &e) { + //cout << e.showMsg() << endl; + //} + delete tree; return 0; } diff --git a/makefile b/makefile index 0c210ac..c8b4e2f 100644 --- a/makefile +++ b/makefile @@ -1,7 +1,7 @@ CC=g++ CFLAGS= -std=gnu++17 -g -DEPS = include/lexer.hpp include/exceptions.hpp include/parser.hpp -OBJ = lexer.o exceptions.o parser.o main.o +DEPS = include/lexer.hpp include/exceptions.hpp include/parser.hpp include/expressions.hpp +OBJ = expressions.o expression_base.o lexer.o exceptions.o parser.o main.o %.o : %.cpp $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) diff --git a/parser.cpp b/parser.cpp index 11ff786..07ca601 100644 --- a/parser.cpp +++ b/parser.cpp @@ -1,94 +1,145 @@ #include #include "include/parser.hpp" +#include "include/expressions.hpp" #include "include/lexer.hpp" #include "include/exceptions.hpp" -using std::string; +using std::string, std::stoi; -void Parser::setText(string text){ - tokenizer.setText(text); // Se prepara el lexer. +// 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."); } -bool Parser::checkToken(){ - if(tokenizer.getCurrentToken().type == nil) - return false; +Expression *Parser::popStack() { + Expression *val = tree_stack.back(); + tree_stack.pop_back(); + + return val; +} - return true; +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::parse(string expr){ +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) - throw ParserException("Sintaxis incorrecta."); + panic(); + + return popStack(); } -void Parser::parseExpr(){ +void Parser::parseExpr() { parseTerm(); parsePrimeExpr(); } -void Parser::parsePrimeExpr(){ +void Parser::parsePrimeExpr() { + token_type current; + if(tokenizer.getCurrentToken().type == sum - || tokenizer.getCurrentToken().type == substraction) - { + || tokenizer.getCurrentToken().type == substraction) { + current = tokenizer.getCurrentToken().type; + + try { tokenizer.nextToken(); + } catch(const LexerException &e) { + panic(); + } - if(!checkToken()) - throw ParserException("Sintaxis incorrecta."); + if(checkToken()) + panic(); parseTerm(); + tree_stack.push_back(newTree(current)); parsePrimeExpr(); } } -void Parser::parseTerm(){ +void Parser::parseTerm() { parsePower(); parsePrimeTerm(); } -void Parser::parsePrimeTerm(){ +void Parser::parsePrimeTerm() { + token_type current; + if(tokenizer.getCurrentToken().type == multiplication - || tokenizer.getCurrentToken().type == division) - { + || tokenizer.getCurrentToken().type == division) { + current = tokenizer.getCurrentToken().type; + tokenizer.nextToken(); - if(!checkToken()) - throw ParserException("Sintaxis incorrecta."); + if(checkToken()) + panic(); parsePower(); + tree_stack.push_back(newTree(current)); parsePrimeTerm(); } } -void Parser::parsePower(){ +void Parser::parsePower() { parseFactor(); parsePrimePower(); } -void Parser::parsePrimePower(){ - if(tokenizer.getCurrentToken().type == power) - { +void Parser::parsePrimePower() { + if(tokenizer.getCurrentToken().type == power) { + tokenizer.nextToken(); if(tokenizer.getCurrentToken().type != number) - throw ParserException("Sintaxis incorrecta."); + panic(); + tree_stack.push_back(new Literal(stoi(tokenizer.getCurrentToken().value))); tokenizer.nextToken(); + tree_stack.push_back(newTree(power)); parsePrimePower(); } } -void Parser::parseFactor(){ - switch(tokenizer.getCurrentToken().type) - { +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(); @@ -96,35 +147,63 @@ void Parser::parseFactor(){ // Consumimos paréntesis derecho. if(tokenizer.getCurrentToken().type != right_parens) - throw ParserException("Sintaxis incorrecta."); + panic(); tokenizer.nextToken(); break; - case function: + 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) - throw ParserException("Sintaxis incorrecta."); + panic(); - parseExpr(); + tokenizer.nextToken(); + parseExpr(); + if(tokenizer.getCurrentToken().type != right_parens) - throw ParserException("Sintaxis incorrecta."); - + panic(); + tokenizer.nextToken(); + + tree_stack.push_back(new Function(popStack(), name)); break; case variable: - tokenizer.nextToken(); + /* 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: - throw ParserException("Sintaxis incorrecta."); + panic(); break; } -- cgit v1.2.3