summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--exceptions.cpp2
-rw-r--r--expressions.cpp29
-rw-r--r--include/exceptions.hpp2
-rw-r--r--include/expressions.hpp1
-rw-r--r--include/lexer.hpp3
-rw-r--r--include/parser.hpp8
-rw-r--r--lexer.cpp16
-rw-r--r--main.cpp21
-rw-r--r--makefile4
-rw-r--r--parser.cpp153
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 <cstddef>
-#include <math.h>
#include <string>
#include <cmath>
#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 <string>
#include <vector>
+#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<Expression *> 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 <vector>
#include <iostream>
#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 <string>
#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;
}