It's alive! (implemented base interpreter)

This commit is contained in:
Bobby Lucero 2023-05-27 16:04:39 -04:00
parent 9500cf9773
commit 3e5ba29283
11 changed files with 282 additions and 40 deletions

View File

@ -22,7 +22,7 @@ OBJ_FILES := $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/%.o,$(CPP_FILES))
$(shell mkdir -p $(dir $(OBJ_FILES))) $(shell mkdir -p $(dir $(OBJ_FILES)))
# Default target # Default target
all: clean $(BUILD_DIR)/bob all: build run
# Rule to create necessary directories # Rule to create necessary directories
$(DIRS): $(DIRS):
@ -37,8 +37,12 @@ $(BUILD_DIR)/bob: $(OBJ_FILES)
$(CC) $(CFLAGS) $^ -o $@ $(CC) $(CFLAGS) $^ -o $@
run:
./$(BUILD_DIR)/bob ./$(BUILD_DIR)/bob
build: clean $(BUILD_DIR)/bob
# Clean build directory # Clean build directory
clean: clean:
rm -rf $(BUILD_DIR)/* rm -rf $(BUILD_DIR)/*

View File

@ -6,14 +6,14 @@
#include <initializer_list> #include <initializer_list>
class ASTPrinter : public Visitor class ASTPrinter : Visitor
{ {
sptr(Object) visitBinaryExpr(BinaryExpr* expression) override; sptr(Object) visitBinaryExpr(sptr(BinaryExpr) expr) override;
sptr(Object) visitGroupingExpr(GroupingExpr* expression) override; sptr(Object) visitGroupingExpr(sptr(GroupingExpr) expr) override;
sptr(Object) visitLiteralExpr(LiteralExpr* expression) override; sptr(Object) visitLiteralExpr(sptr(LiteralExpr) expr) override;
sptr(Object) visitUnaryExpr(UnaryExpr* expression) override; sptr(Object) visitUnaryExpr(sptr(UnaryExpr) expr) override;
public: public:
sptr(Object) print(Expr* expr); sptr(Object) print(sptr(Expr) expr);
private: private:
sptr(Object) parenthesize(std::string name, std::vector<sptr(Expr)> exprs); sptr(Object) parenthesize(std::string name, std::vector<sptr(Expr)> exprs);

View File

@ -15,10 +15,10 @@ struct UnaryExpr;
struct Visitor struct Visitor
{ {
virtual sptr(Object) visitBinaryExpr(BinaryExpr* expression) = 0; virtual sptr(Object) visitBinaryExpr(sptr(BinaryExpr) expr) = 0;
virtual sptr(Object) visitGroupingExpr(GroupingExpr* expression) = 0; virtual sptr(Object) visitGroupingExpr(sptr(GroupingExpr) expr) = 0;
virtual sptr(Object) visitLiteralExpr(LiteralExpr* expression) = 0; virtual sptr(Object) visitLiteralExpr(sptr(LiteralExpr) expr) = 0;
virtual sptr(Object) visitUnaryExpr(UnaryExpr* expression) = 0; virtual sptr(Object) visitUnaryExpr(sptr(UnaryExpr) expr) = 0;
}; };
@ -28,7 +28,7 @@ struct Expr{
}; };
struct BinaryExpr : Expr struct BinaryExpr : Expr, public std::enable_shared_from_this<BinaryExpr>
{ {
const std::shared_ptr<Expr> left; const std::shared_ptr<Expr> left;
const Token oper; const Token oper;
@ -38,11 +38,11 @@ struct BinaryExpr : Expr
{ {
} }
sptr(Object) accept(Visitor* visitor) override{ sptr(Object) accept(Visitor* visitor) override{
return visitor->visitBinaryExpr(this); return visitor->visitBinaryExpr(shared_from_this() );
} }
}; };
struct GroupingExpr : Expr struct GroupingExpr : Expr, public std::enable_shared_from_this<GroupingExpr>
{ {
const std::shared_ptr<Expr> expression; const std::shared_ptr<Expr> expression;
@ -50,23 +50,24 @@ struct GroupingExpr : Expr
{ {
} }
sptr(Object) accept(Visitor* visitor) override{ sptr(Object) accept(Visitor* visitor) override{
return visitor->visitGroupingExpr(this); return visitor->visitGroupingExpr(shared_from_this());
} }
}; };
struct LiteralExpr : Expr struct LiteralExpr : Expr, public std::enable_shared_from_this<LiteralExpr>
{ {
const std::string value; const std::string value;
const bool isNumber; const bool isNumber;
LiteralExpr(std::string value, bool isNumber) : value(value), isNumber(isNumber) const bool isNull;
LiteralExpr(std::string value, bool isNumber, bool isNull) : value(value), isNumber(isNumber), isNull(isNull)
{ {
} }
sptr(Object) accept(Visitor* visitor) override{ sptr(Object) accept(Visitor* visitor) override{
return visitor->visitLiteralExpr(this); return visitor->visitLiteralExpr(shared_from_this());
} }
}; };
struct UnaryExpr : Expr struct UnaryExpr : Expr, public std::enable_shared_from_this<UnaryExpr>
{ {
const Token oper; const Token oper;
const std::shared_ptr<Expr> right; const std::shared_ptr<Expr> right;
@ -75,7 +76,7 @@ struct UnaryExpr : Expr
{ {
} }
sptr(Object) accept(Visitor* visitor) override{ sptr(Object) accept(Visitor* visitor) override{
return visitor->visitUnaryExpr(this); return visitor->visitUnaryExpr(shared_from_this());
} }
}; };

23
headers/Interpreter.h Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#include "Expression.h"
#include "helperFunctions/ShortHands.h"
#include "TypeWrapper.h"
class Interpreter : Visitor
{
public:
sptr(Object) visitBinaryExpr(sptr(BinaryExpr) expression) override;
sptr(Object) visitGroupingExpr(sptr(GroupingExpr) expression) override;
sptr(Object) visitLiteralExpr(sptr(LiteralExpr) expression) override;
sptr(Object) visitUnaryExpr(sptr(UnaryExpr) expression) override;
void interpret(sptr(Expr) expr);
private:
sptr(Object) evaluate(sptr(Expr) expr);
bool isTruthy(sptr(Object) object);
bool isEqual(sptr(Object) a, sptr(Object) b);
std::string stringify(sptr(Object) object);
};

View File

@ -5,14 +5,25 @@ struct Object
virtual ~Object(){}; virtual ~Object(){};
}; };
struct Number : public Object struct Number : Object
{ {
double value; double value;
explicit Number(double value) : value(value) {} explicit Number(double value) : value(value) {}
}; };
struct String : public Object struct String : Object
{ {
std::string value; std::string value;
explicit String(std::string str) : value(str) {} explicit String(std::string str) : value(str) {}
};
struct Boolean : Object
{
bool value;
explicit Boolean(bool value) : value(value) {}
};
struct None : public Object
{
}; };

View File

@ -4,6 +4,7 @@
#include <fstream> #include <fstream>
#include <string> #include <string>
#include "../headers/Lexer.h" #include "../headers/Lexer.h"
#include "../headers/Interpreter.h"
#define VERSION "0.0.1" #define VERSION "0.0.1"
@ -11,6 +12,7 @@ class Bob
{ {
public: public:
Lexer lexer; Lexer lexer;
Interpreter interpreter;
public: public:
void runFile(std::string path); void runFile(std::string path);

View File

@ -4,22 +4,22 @@
#include "../headers/ASTPrinter.h" #include "../headers/ASTPrinter.h"
sptr(Object) ASTPrinter::visitBinaryExpr(BinaryExpr* expression){ sptr(Object) ASTPrinter::visitBinaryExpr(sptr(BinaryExpr) expression){
std::cout << expression->left << std::endl; std::cout << expression->left << std::endl;
return parenthesize(expression->oper.lexeme, std::vector<sptr(Expr)>{expression->left, expression->right}); return parenthesize(expression->oper.lexeme, std::vector<sptr(Expr)>{expression->left, expression->right});
} }
sptr(Object) ASTPrinter::visitGroupingExpr(GroupingExpr* expression){ sptr(Object) ASTPrinter::visitGroupingExpr(sptr(GroupingExpr) expression){
return parenthesize("group", std::vector<sptr(Expr)>{expression->expression}); return parenthesize("group", std::vector<sptr(Expr)>{expression->expression});
} }
sptr(Object) ASTPrinter::visitLiteralExpr(LiteralExpr* expression){ sptr(Object) ASTPrinter::visitLiteralExpr(sptr(LiteralExpr) expression){
return msptr(String)(expression->value); return msptr(String)(expression->value);
} }
sptr(Object) ASTPrinter::visitUnaryExpr(UnaryExpr* expression){ sptr(Object) ASTPrinter::visitUnaryExpr(sptr(UnaryExpr) expression){
return parenthesize(expression->oper.lexeme, std::vector<sptr(Expr)>{expression->right}); return parenthesize(expression->oper.lexeme, std::vector<sptr(Expr)>{expression->right});
} }
sptr(Object) ASTPrinter::print(Expr *expr) { sptr(Object) ASTPrinter::print(sptr(Expr) expr) {
return expr->accept(this); return expr->accept(this);
} }

206
source/Interpreter.cpp Normal file
View File

@ -0,0 +1,206 @@
//
// Created by Bobby Lucero on 5/27/23.
//
#include <utility>
#include <sstream>
#include <cmath>
#include <iomanip>
#include <limits>
#include "../headers/Interpreter.h"
sptr(Object) Interpreter::visitLiteralExpr(sptr(LiteralExpr) expr) {
if(expr->isNull) return msptr(None)();
if(expr->isNumber) return msptr(Number)(std::stod(expr->value));
return msptr(String)(expr->value);
}
sptr(Object) Interpreter::visitGroupingExpr(sptr(GroupingExpr) expression) {
return evaluate(expression->expression);
}
sptr(Object) Interpreter::visitUnaryExpr(sptr(UnaryExpr) expression)
{
sptr(Object) right = evaluate(expression->right);
if(expression->oper.type == MINUS)
{
if(std::dynamic_pointer_cast<Number>(right))
{
double value = std::dynamic_pointer_cast<Number>(right)->value;
return msptr(Number)(-value);
}
else
{
throw std::runtime_error("Operand must be a number when using: " + expression->oper.lexeme);
}
}
if(expression->oper.type == BANG)
{
return msptr(Boolean)(!isTruthy(right));
}
}
sptr(Object) Interpreter::visitBinaryExpr(sptr(BinaryExpr) expression)
{
sptr(Object) left = evaluate(expression->left);
sptr(Object) right = evaluate(expression->right);
switch (expression->oper.type) {
case BANG_EQUAL:
return msptr(Boolean)(!isEqual(left, right));
case DOUBLE_EQUAL:
return msptr(Boolean)(isEqual(left, right));
default:
;
}
if(std::dynamic_pointer_cast<Number>(left) && std::dynamic_pointer_cast<Number>(right))
{
double left_double = std::dynamic_pointer_cast<Number>(left)->value;
double right_double = std::dynamic_pointer_cast<Number>(right)->value;
switch (expression->oper.type) {
case GREATER:
return msptr(Boolean)(left_double > right_double);
case GREATER_EQUAL:
return msptr(Boolean)(left_double >= right_double);
case LESS:
return msptr(Boolean)(left_double < right_double);
case LESS_EQUAL:
return msptr(Boolean)(left_double <= right_double);
case MINUS:
return msptr(Number)(left_double - right_double);
case PLUS:
return msptr(Number)(left_double + right_double);
case SLASH:
return msptr(Number)(left_double / right_double);
case STAR:
return msptr(Number)(left_double * right_double);
default:
return msptr(None)(); //unreachable
}
}
else if(std::dynamic_pointer_cast<String>(left) && std::dynamic_pointer_cast<String>(right))
{
std::string left_string = std::dynamic_pointer_cast<String>(left)->value;
std::string right_string = std::dynamic_pointer_cast<String>(right)->value;
return msptr(String)(left_string + right_string);
}
else
{
throw std::runtime_error("Operands must be of same type when using: " + expression->oper.lexeme);
}
}
sptr(Object) Interpreter::evaluate(sptr(Expr) expr) {
return expr->accept(this);
}
bool Interpreter::isTruthy(sptr(Object) object) {
if(auto boolean = std::dynamic_pointer_cast<Boolean>(object))
{
boolean->value;
}
if(auto obj = std::dynamic_pointer_cast<None>(object))
{
return false;
}
return true;
}
bool Interpreter::isEqual(sptr(Object) a, sptr(Object) b) {
if(auto left = std::dynamic_pointer_cast<Number>(a))
{
if(auto right = std::dynamic_pointer_cast<Number>(b))
{
return left->value == right->value;
}
return false;
}
else if(auto left = std::dynamic_pointer_cast<Boolean>(a))
{
if(auto right = std::dynamic_pointer_cast<Boolean>(b))
{
return left->value == right->value;
}
return false;
}
else if(auto left = std::dynamic_pointer_cast<String>(a))
{
if(auto right = std::dynamic_pointer_cast<String>(b))
{
return left->value == right->value;
}
return false;
}
else if(auto left = std::dynamic_pointer_cast<None>(a))
{
if(auto right = std::dynamic_pointer_cast<None>(b))
{
return true;
}
return false;
}
}
void Interpreter::interpret(std::shared_ptr<Expr> expr) {
sptr(Object) value = evaluate(std::move(expr));
std::cout << stringify(value) << std::endl;
}
std::string Interpreter::stringify(std::shared_ptr<Object> object) {
if(std::dynamic_pointer_cast<None>(object))
{
return "None";
}
else if(auto num = std::dynamic_pointer_cast<Number>(object))
{
double integral = num->value;
double fractional = std::modf(num->value, &integral);
std::stringstream ss;
if(std::abs(fractional) < std::numeric_limits<double>::epsilon())
{
ss << std::fixed << std::setprecision(0) << integral;
return ss.str();
}
else
{
ss << std::fixed << std::setprecision(std::numeric_limits<double>::digits10) << num->value;\
std::string str = ss.str();
str.erase(str.find_last_not_of('0') + 1, std::string::npos);
if (str.back() == '.') {
str.pop_back();
}
return str;
}
}
else if(auto string = std::dynamic_pointer_cast<String>(object))
{
return string->value;
}
else if(auto Bool = std::dynamic_pointer_cast<Boolean>(object))
{
return Bool->value == 1 ? "true" : "false";
}
}

View File

@ -120,7 +120,7 @@ std::vector<Token> Lexer::Tokenize(std::string source){
} }
else if(t == '"') else if(t == '"')
{ {
std::string str = std::string(1, src[0]); std::string str;
advance(); advance();
while(!src.empty() && src[0] != '"') while(!src.empty() && src[0] != '"')
{ {
@ -134,7 +134,7 @@ std::vector<Token> Lexer::Tokenize(std::string source){
} }
else if(src[0] == '"') else if(src[0] == '"')
{ {
str += '"';
advance(); advance();
tokens.push_back(Token{STRING, str, line}); tokens.push_back(Token{STRING, str, line});
} }

View File

@ -47,7 +47,6 @@ sptr(Expr) Parser::term()
while(match({MINUS, PLUS})) while(match({MINUS, PLUS}))
{ {
std::cout << "Found comparison" << std::endl;
Token op = previous(); Token op = previous();
sptr(Expr) right = factor(); sptr(Expr) right = factor();
expr = msptr(BinaryExpr)(expr, op, right); expr = msptr(BinaryExpr)(expr, op, right);
@ -84,12 +83,12 @@ sptr(Expr) Parser::unary()
sptr(Expr) Parser::primary() sptr(Expr) Parser::primary()
{ {
if(match({FALSE})) return msptr(LiteralExpr)("true", false); if(match({FALSE})) return msptr(LiteralExpr)("true", false, false);
if(match({TRUE})) return msptr(LiteralExpr)("true", false); if(match({TRUE})) return msptr(LiteralExpr)("true", false, false);
if(match({NONE})) return msptr(LiteralExpr)("none", false); if(match({NONE})) return msptr(LiteralExpr)("none", false, false);
if(match({NUMBER})) return msptr(LiteralExpr)(previous().lexeme, true); if(match({NUMBER})) return msptr(LiteralExpr)(previous().lexeme, true, false);
if(match({STRING})) return msptr(LiteralExpr)(previous().lexeme, false); if(match({STRING})) return msptr(LiteralExpr)(previous().lexeme, false, false);
if(match({OPEN_PAREN})) if(match({OPEN_PAREN}))
{ {

View File

@ -51,11 +51,7 @@ void Bob::run(string source)
vector<Token> tokens = lexer.Tokenize(source); vector<Token> tokens = lexer.Tokenize(source);
Parser p(tokens); Parser p(tokens);
shared_ptr<Expr> expr = p.parse(); shared_ptr<Expr> expr = p.parse();
interpreter.interpret(expr);
ASTPrinter printer;
cout << dynamic_pointer_cast<String>(printer.print(expr.get()))->value << endl;
for(Token t : tokens){ for(Token t : tokens){