Add interpreter

This commit is contained in:
ala89 2023-11-10 17:35:33 +01:00
parent a8e6a4552b
commit ede4dea616
9 changed files with 147 additions and 26 deletions

View File

@ -6,7 +6,7 @@ CXX := g++
LD_CXXFLAGS = LD_CXXFLAGS =
# Compilation flag # Compilation flag
CXXFLAGS = -Wall -Wextra -g -O3 CXXFLAGS = -Wall -Wextra -g -O3 -std=c++2a
# Remove warnings about unused variables, functions, ... # Remove warnings about unused variables, functions, ...
# -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable -Wno-unused-but-set-variable # -Wno-unused-parameter -Wno-unused-function -Wno-unused-variable -Wno-unused-but-set-variable
# Compile with debug # Compile with debug
@ -14,7 +14,7 @@ CXXFLAGS = -Wall -Wextra -g -O3
# See memory leaks and Incorrect Read/Write # See memory leaks and Incorrect Read/Write
# -fsanitize=address -lasan # -fsanitize=address -lasan
$(BUILDDIR)/main: $(SRCDIR)/main.cpp $(BUILDDIR)/input.o src/include/parser.h $(BUILDDIR)/main: $(SRCDIR)/main.cpp $(BUILDDIR)/input.o $(BUILDDIR)/interpreter.o $(BUILDDIR)/parser.o $(BUILDDIR)/tokenize.o
$(CXX) $^ -o $@ $(CXXFLAGS) $(LD_CXXFLAGS) $(CXX) $^ -o $@ $(CXXFLAGS) $(LD_CXXFLAGS)

View File

@ -1,6 +1,12 @@
#ifndef DEF_INPUT_H #ifndef DEF_INPUT_H
#define DEF_INPUT_H #define DEF_INPUT_H
#include <string>
using namespace std;
/*
Retrieves user input
*/
string get_input(); string get_input();
#endif #endif

View File

@ -1,6 +1,14 @@
#ifndef INTERPRETER_H #ifndef INTERPRETER_H
#define INTERPRETER_H #define INTERPRETER_H
#include <variant>
using namespace std;
using EvalResult = variant<int, monostate>;
/*
Evaluates the AST, returning the latest calulated value
*/
EvalResult eval(Node &ast);
#endif #endif

View File

@ -56,7 +56,6 @@ enum class NodeType {
Mod, // -> F % T Mod, // -> F % T
UnaryMinus, // -> -F UnaryMinus, // -> -F
UnaryPlus, // -> +F UnaryPlus, // -> +F
Parenthesis, // -> (Expr)
Assignment // -> Identifier = Expr Assignment // -> Identifier = Expr
}; };

View File

@ -6,14 +6,24 @@
#include <string> #include <string>
using namespace std; using namespace std;
enum class TokenType { Type, Identifier, Number, Plus, Minus, Star, Slash, Percent, Equal, Semicolon, LParenthese, RParenthese }; enum class TokenType { Type, Identifier, Int, Plus, Minus, Star, Slash, Percent, Equal, Semicolon, LParenthese, RParenthese };
enum class Type { Int }; enum class Type { Int };
using TokenData = variant<double, string, Type>; using TokenData = variant<int, string, Type>;
struct Token { struct Token {
TokenType type; TokenType type;
TokenData data; TokenData data;
}; };
/*
Parses a string into a vector of tokens
*/
vector<Token> tokenize(string str);
/*
Formats a list of tokens and prints it
*/
void _debug_print_tokens(vector<Token> tokens);
#endif #endif

View File

@ -1,16 +1,105 @@
#include <vector> #include <vector>
#include <iostream>
#include <unordered_map>
#include <string>
#include "include/parser.h" #include "include/parser.h"
#include "include/interpreter.h" #include "include/interpreter.h"
using namespace std; using namespace std;
void eval(Node &ast) { unordered_map<string, int> memory;
} EvalResult eval(Node &ast) {
if (ast.index() == 0) {
InnerNode node = get<InnerNode>(ast);
switch (node.type) {
case NodeType::Prog:
eval(node.children[0]);
return eval(node.children[1]);
break;
case NodeType::Epsilon:
return {};
break;
case NodeType::Plus: {
int e1 = get<int>(eval(node.children[0]));
int e2 = get<int>(eval(node.children[1]));
return e1 + e2;
} break;
case NodeType::Minus: {
int e1 = get<int>(eval(node.children[0]));
int e2 = get<int>(eval(node.children[1]));
return e1 - e2;
} break;
case NodeType::Mult: {
int e1 = get<int>(eval(node.children[0]));
int e2 = get<int>(eval(node.children[1]));
return e1 * e2;
} break;
case NodeType::Div: {
int e1 = get<int>(eval(node.children[0]));
int e2 = get<int>(eval(node.children[1]));
// if (e2 == 0)
return e1 / e2;
} break;
case NodeType::Mod: {
int e1 = get<int>(eval(node.children[0]));
int e2 = get<int>(eval(node.children[1]));
// if (e2 == 0)
return e1 % e2;
} break;
case NodeType::UnaryPlus: {
int e1 = get<int>(eval(node.children[0]));
return +e1;
} break;
case NodeType::UnaryMinus: {
int e1 = get<int>(eval(node.children[0]));
return -e1;
} break;
case NodeType::Declaration: {
Token typeTok = get<Token>(node.children[0]);
Token identifierTok = get<Token>(node.children[1]);
string identifier = get<string>(identifierTok.data);
int main() { memory[identifier] = 0;
Token oneTok = {
.type = TokenType::Number, return {};
.data = 1.0 } break;
}; case NodeType::AssignedDeclaration: {
Node one = oneTok; Token typeTok = get<Token>(node.children[0]);
Token identifierTok = get<Token>(node.children[1]);
string identifier = get<string>(identifierTok.data);
int expr = get<int>(eval(node.children[2]));
memory[identifier] = expr;
return expr;
} break;
case NodeType::Assignment: {
Token identifierTok = get<Token>(node.children[0]);
string identifier = get<string>(identifierTok.data);
int expr = get<int>(eval(node.children[1]));
memory[identifier] = expr;
return expr;
} break;
}
}
else {
Token token = get<Token>(ast);
switch (token.type) {
case TokenType::Int: {
return get<int>(token.data);
} break;
case TokenType::Identifier: {
string identifier = get<string>(token.data);
// if (!memory.contains(identifier)) return;
return memory[identifier];
} break;
default:
throw;
break;
}
}
return {};
} }

View File

@ -2,9 +2,21 @@
using namespace std; using namespace std;
#include "include/input.h" #include "include/input.h"
#include "include/tokenize.h"
#include "include/parser.h" #include "include/parser.h"
#include "include/interpreter.h"
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
return 0; while (true) {
try {
string input = get_input();
vector<Token> tokens = tokenize(input);
Node ast = parse(tokens);
EvalResult res = eval(ast);
cout << get<int>(res) << endl;
}
catch (...) { // temp
cout << "err" << endl;
}
}
} }

View File

@ -271,7 +271,7 @@ ParseReturn parse_f(vector<Token> tokens) {
throw new ParseException; throw new ParseException;
switch (tokens.back().type) { switch (tokens.back().type) {
case TokenType::Number: { //* U -> Number case TokenType::Int: { //* U -> Number
Token number = tokens.back(); Token number = tokens.back();
tokens.pop_back(); tokens.pop_back();
return { return {
@ -288,12 +288,9 @@ ParseReturn parse_f(vector<Token> tokens) {
throw new ParseException; throw new ParseException;
tokens.pop_back(); tokens.pop_back();
InnerNode node = {
.type=NodeType::Parenthesis,
.children={ ret.node }
};
return { return {
.node=node, .node=ret.node,
.tokens=tokens .tokens=tokens
}; };
} }

View File

@ -9,14 +9,14 @@ regex NUMBER_REGEX ("\\d+(\\.\\d+)?");
regex TYPE_INT_REGEX ("int\\s"); regex TYPE_INT_REGEX ("int\\s");
regex IDENTIFIER_REGEX ("[A-Za-z_]\\w*"); regex IDENTIFIER_REGEX ("[A-Za-z_]\\w*");
void print_tokens(vector<Token> tokens) { void _debug_print_tokens(vector<Token> tokens) {
for (Token token : tokens) { for (Token token : tokens) {
switch (token.type) { switch (token.type) {
case TokenType::Type: case TokenType::Type:
cout << "Type(INT)"; cout << "Type(INT)";
break; break;
case TokenType::Number: case TokenType::Int:
cout << "Number(" << get<double>(token.data) << ")"; cout << "Number(" << get<int>(token.data) << ")";
break; break;
case TokenType::Identifier: case TokenType::Identifier:
cout << "Identifier(" << get<string>(token.data) << ")"; cout << "Identifier(" << get<string>(token.data) << ")";
@ -61,8 +61,8 @@ vector<Token> tokenize(string str) {
smatch m; smatch m;
if (regex_search(str, m, NUMBER_REGEX, regex_constants::match_continuous)) { if (regex_search(str, m, NUMBER_REGEX, regex_constants::match_continuous)) {
Token token = { Token token = {
.type = TokenType::Number, .type = TokenType::Int,
.data = stod(m.str()) .data = stoi(m.str())
}; };
tokens.emplace_back(token); tokens.emplace_back(token);
str.erase(0, m.str().length()); str.erase(0, m.str().length());