summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHombreLaser <buran@silosneeded.com>2024-06-22 16:45:04 -0600
committerHombreLaser <buran@silosneeded.com>2024-06-22 16:45:04 -0600
commit404826e78a56e15e20d3938aed80945295921745 (patch)
treed607769fccfc4e3c77a9465a9800004421c500cb
parent10ecf4d95194a273cc6aab89c3a1bcf739a194cd (diff)
Add parser
-rw-r--r--src/CMakeLists.txt11
-rw-r--r--src/calculator.cpp14
-rw-r--r--src/include/calculator.hpp6
-rw-r--r--src/include/operand.hpp10
-rw-r--r--src/include/parser.hpp24
-rw-r--r--src/include/product.hpp9
-rw-r--r--src/include/substraction.hpp8
-rw-r--r--src/include/sum.hpp8
-rw-r--r--src/include/syntax_tree.hpp12
-rw-r--r--src/include/tokenizer.hpp17
-rw-r--r--src/operand.cpp13
-rw-r--r--src/product.cpp11
-rw-r--r--src/substraction.cpp10
-rw-r--r--src/sum.cpp9
-rw-r--r--src/syntax_tree.cpp13
-rw-r--r--src/tokenizer.cpp28
16 files changed, 179 insertions, 24 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 89b60e6..9265ad8 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -11,7 +11,16 @@ target_include_directories(Pico-I2C-LCD INTERFACE ../libs/Pico-I2C-LCD/)
target_include_directories(Pico-I2C-LCD PUBLIC ../libs/Pico-I2C-LCD/)
# Main executable
-add_executable(pico-calc pico-calc.cpp calculator.cpp tokenizer.cpp)
+add_executable(pico-calc pico-calc.cpp
+ calculator.cpp
+ tokenizer.cpp
+ operand.cpp
+ syntax_tree.cpp
+ sum.cpp
+ substraction.cpp
+ product.cpp
+)
target_link_libraries(pico-calc
hardware_i2c Pico-I2C-LCD pico-keypad hardware_timer)
target_include_directories(pico-calc PUBLIC include exceptions)
+pico_add_extra_outputs(pico-calc)
diff --git a/src/calculator.cpp b/src/calculator.cpp
index 5de706b..4dd8dcd 100644
--- a/src/calculator.cpp
+++ b/src/calculator.cpp
@@ -27,14 +27,20 @@ Calculator::~Calculator() {
void Calculator::run() {
while(true) {
display->Clear();
- std::string input;
- short str_len = 0;
char pressed_key = default_keypad->getKey();
if(pressed_key == '\0')
continue;
- while(str_len <= 15) {
+ processInputs();
+}
+
+void Calculator::processInputs() {
+ char pressed_key;
+ short str_len = 0;
+ std::string input;
+
+ while(str_len <= 15) {
pressed_key = default_keypad->getKey();
if(pressed_key != '\0' && pressed_key != '=') {
@@ -44,7 +50,7 @@ void Calculator::run() {
}
if(pressed_key == '=') {
- std::array tokens = tokenizer.tokenize(input);
+ tokens = tokenizer.tokenize(input);
break;
}
diff --git a/src/include/calculator.hpp b/src/include/calculator.hpp
index 8c5e97a..2362258 100644
--- a/src/include/calculator.hpp
+++ b/src/include/calculator.hpp
@@ -8,9 +8,11 @@
class Calculator {
private:
+ // Private attributes.
LCD_I2C *display;
Keypad *default_keypad;
Tokenizer tokenizer = Tokenizer();
+ Token **tokens;
char default_keypad_chars[4][4] = {
{'1', '2', '3', '+'},
{'4', '5', '6', '-'},
@@ -25,6 +27,10 @@ private:
};
uint keypad_col_pins[4] = {6, 7, 8, 9};
uint keypad_row_pins[4] = {16, 17, 18, 19};
+ // End of private attributes.
+ // Private methods.
+ void processInputs();
+ // End of private methods.
public:
Calculator();
~Calculator();
diff --git a/src/include/operand.hpp b/src/include/operand.hpp
new file mode 100644
index 0000000..cc638de
--- /dev/null
+++ b/src/include/operand.hpp
@@ -0,0 +1,10 @@
+#pragma once
+#include "syntax_tree.hpp"
+
+
+class Operand: SyntaxTree {
+ int value;
+public:
+ Operand(int value);
+ float eval() const;
+};
diff --git a/src/include/parser.hpp b/src/include/parser.hpp
new file mode 100644
index 0000000..7bc7997
--- /dev/null
+++ b/src/include/parser.hpp
@@ -0,0 +1,24 @@
+/* Grammar
+ * Expression --> Term PrimeExpression
+ * PrimeExpression --> (+|-)Expression | Null
+ * Term --> Factor PrimeTerm
+ * PrimeTerm --> (*|/)Term | Null
+ * Factor --> -Expression | (Expression) | operand */
+#pragma once
+#include "tokenizer.hpp"
+#include "syntax_tree.hpp"
+
+
+class Parser {
+private:
+ // Private methods.
+ void parseExpression();
+ void parsePrimeExpression();
+ void parseTerm();
+ void parsePrimeTerm();
+ void parseFactor();
+ // End of private methods.
+public:
+ Parser();
+ const SyntaxTree *parse();
+};
diff --git a/src/include/product.hpp b/src/include/product.hpp
new file mode 100644
index 0000000..1a87f80
--- /dev/null
+++ b/src/include/product.hpp
@@ -0,0 +1,9 @@
+#pragma once
+#include "syntax_tree.hpp"
+
+
+class Product: SyntaxTree {
+public:
+ Product(SyntaxTree *left, SyntaxTree *right);
+ float eval() const;
+};
diff --git a/src/include/substraction.hpp b/src/include/substraction.hpp
new file mode 100644
index 0000000..4a5a8c7
--- /dev/null
+++ b/src/include/substraction.hpp
@@ -0,0 +1,8 @@
+#pragma once
+#include "syntax_tree.hpp"
+
+class Substraction: SyntaxTree {
+public:
+ Substraction(SyntaxTree *left, SyntaxTree *right);
+ float eval() const;
+};
diff --git a/src/include/sum.hpp b/src/include/sum.hpp
new file mode 100644
index 0000000..35d6736
--- /dev/null
+++ b/src/include/sum.hpp
@@ -0,0 +1,8 @@
+#pragma once
+#include "syntax_tree.hpp"
+
+class Sum: SyntaxTree {
+public:
+ Sum(SyntaxTree *left, SyntaxTree *right);
+ float eval() const;
+};
diff --git a/src/include/syntax_tree.hpp b/src/include/syntax_tree.hpp
new file mode 100644
index 0000000..9edf23c
--- /dev/null
+++ b/src/include/syntax_tree.hpp
@@ -0,0 +1,12 @@
+#pragma once
+#include "tokenizer.hpp"
+
+class SyntaxTree {
+protected:
+ const SyntaxTree *left {};
+ const SyntaxTree *right {};
+public:
+ SyntaxTree(SyntaxTree *left = nullptr, SyntaxTree *right = nullptr);
+ virtual ~SyntaxTree();
+ virtual float eval() const = 0;
+};
diff --git a/src/include/tokenizer.hpp b/src/include/tokenizer.hpp
index a3f9998..7d00055 100644
--- a/src/include/tokenizer.hpp
+++ b/src/include/tokenizer.hpp
@@ -1,7 +1,7 @@
#pragma once
#include <regex>
#include <string>
-#include <array>
+#define TOKENS_ARRAY_LEN 16
enum Type {
operand,
@@ -11,7 +11,8 @@ enum Type {
division,
left_parens,
right_parens,
- equals
+ equals,
+ nil
};
struct Token {
@@ -22,14 +23,14 @@ struct Token {
class Tokenizer {
private:
// Private attributes
- std::array<Token *, 16> tokens;
+ Token *tokens[17];
const std::string *to_tokenize;
size_t current_char_index;
short tokens_head;
// Regexes
- std::regex operand_regex = std::regex("^0{1}|\\d+");
- std::regex operation_regex = std::regex("\\+|-|/|\\*");
- std::regex parens_regex = std::regex("(|)");
+ std::regex operand_regex = std::regex("^0{1}|^\\d+");
+ std::regex operation_regex = std::regex("^\\+|^-|/|^\\*");
+ std::regex parens_regex = std::regex("^\\(|^\\)");
// End of private attributes
// Private methods
void clearTokens();
@@ -42,6 +43,6 @@ private:
public:
Tokenizer();
~Tokenizer();
- const std::array<Token *, 16> &tokenize(const std::string &operation);
- const std::array<Token *, 16> &getTokens();
+ Token **tokenize(const std::string &operation);
+ Token **getTokens();
};
diff --git a/src/operand.cpp b/src/operand.cpp
new file mode 100644
index 0000000..67654f0
--- /dev/null
+++ b/src/operand.cpp
@@ -0,0 +1,13 @@
+#include "include/operand.hpp"
+#include "include/syntax_tree.hpp"
+#include "include/tokenizer.hpp"
+
+
+Operand::Operand(int value)
+ : SyntaxTree{nullptr, nullptr}
+ ,value{value}
+{}
+
+float Operand::eval() const {
+ return value;
+}
diff --git a/src/product.cpp b/src/product.cpp
new file mode 100644
index 0000000..093aff1
--- /dev/null
+++ b/src/product.cpp
@@ -0,0 +1,11 @@
+#include "include/product.hpp"
+#include "include/syntax_tree.hpp"
+
+
+Product::Product(SyntaxTree *left, SyntaxTree *right)
+ : SyntaxTree{left, right}
+{}
+
+float Product::eval() const {
+ return left->eval() * right->eval();
+}
diff --git a/src/substraction.cpp b/src/substraction.cpp
new file mode 100644
index 0000000..ba995b5
--- /dev/null
+++ b/src/substraction.cpp
@@ -0,0 +1,10 @@
+#include "include/substraction.hpp"
+#include "include/syntax_tree.hpp"
+
+
+Substraction::Substraction(SyntaxTree *left, SyntaxTree *right)
+ : SyntaxTree{left, right} {}
+
+float Substraction::eval() const {
+ return left->eval() - right->eval();
+}
diff --git a/src/sum.cpp b/src/sum.cpp
new file mode 100644
index 0000000..aa77d4e
--- /dev/null
+++ b/src/sum.cpp
@@ -0,0 +1,9 @@
+#include "include/sum.hpp"
+#include "include/syntax_tree.hpp"
+
+
+Sum::Sum(SyntaxTree *left, SyntaxTree *right) : SyntaxTree{left, right} {}
+
+float Sum::eval() const {
+ return left->eval() + left->eval();
+}
diff --git a/src/syntax_tree.cpp b/src/syntax_tree.cpp
new file mode 100644
index 0000000..83b5d60
--- /dev/null
+++ b/src/syntax_tree.cpp
@@ -0,0 +1,13 @@
+#include "include/syntax_tree.hpp"
+
+SyntaxTree::SyntaxTree(SyntaxTree *left,
+ SyntaxTree *right)
+ : left{left}, right{right} {}
+
+SyntaxTree::~SyntaxTree() {
+ if(left != nullptr)
+ delete left;
+
+ if(right != nullptr)
+ delete right;
+}
diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp
index a156000..783803e 100644
--- a/src/tokenizer.cpp
+++ b/src/tokenizer.cpp
@@ -1,11 +1,11 @@
#include <string>
-#include <array>
#include "include/tokenizer.hpp"
#include "exceptions/tokenizer_exception.hpp"
Tokenizer::Tokenizer() {
- tokens.fill(nullptr);
tokens_head = 0;
+ for(int i = 0; i < TOKENS_ARRAY_LEN; ++i)
+ tokens[i] = nullptr;
}
Tokenizer::~Tokenizer() {
@@ -13,10 +13,14 @@ Tokenizer::~Tokenizer() {
}
void Tokenizer::clearTokens() {
- for(auto token{ tokens.begin() }; *token != nullptr; ++token)
- delete token;
-
- tokens.fill(nullptr);
+ tokens_head = 0;
+
+ for(int i = 0; i < TOKENS_ARRAY_LEN; ++i) {
+ if(tokens[i] != nullptr) {
+ delete tokens[i];
+ tokens[i] = nullptr;
+ }
+ }
}
void Tokenizer::insertToken(Type type, int value = 0) {
@@ -27,8 +31,8 @@ void Tokenizer::insertToken(Type type, int value = 0) {
}
-const std::array<Token *, 16>
-&Tokenizer::tokenize(const std::string &operation) {
+Token **Tokenizer::tokenize(const std::string &operation) {
+ clearTokens();
to_tokenize = &operation;
current_char_index = 0;
@@ -44,6 +48,8 @@ const std::array<Token *, 16>
throw TokenizerException("Invalid character detected.");
}
+ // "Nil" terminated array. Intended to be the epsilon terminal in the grammar.
+ tokens[tokens_head] = new Token { .type = nil, .value = 0 };
return getTokens();
}
@@ -72,7 +78,7 @@ void Tokenizer::matchParens(const std::string &operation) {
std::string remaining(operation.substr(current_char_index));
bool result = std::regex_search(remaining, match,
- operand_regex);
+ parens_regex);
if(!result)
return;
@@ -97,7 +103,7 @@ void Tokenizer::matchOperation(const std::string &operation) {
std::string remaining(operation.substr(current_char_index));
bool result = std::regex_search(remaining, match,
- operand_regex);
+ operation_regex);
if(!result)
return;
@@ -120,6 +126,6 @@ void Tokenizer::matchOperation(const std::string &operation) {
current_char_index += 1;
}
-const std::array<Token *, 16> &Tokenizer::getTokens() {
+Token **Tokenizer::getTokens() {
return tokens;
}