GSC Interpreter
A Turing-complete interpreter developed for a compiler course
Loading...
Searching...
No Matches
Interpreter Class Reference

The Interpreter class evaluates statements and expressions in the GSC. More...

#include <interpreter.hpp>

Inheritance diagram for Interpreter:
Collaboration diagram for Interpreter:

Public Member Functions

void interpret (const std::vector< std::shared_ptr< Stmt > > &statements)
 Interpret the given statement list and execute them.
 
- Public Member Functions inherited from ExprVisitor
virtual ~ExprVisitor ()=default
 
- Public Member Functions inherited from StmtVisitor
virtual ~StmtVisitor ()=default
 

Private Member Functions

std::any evaluate (std::shared_ptr< Expr > expr)
 
void execute (std::shared_ptr< Stmt > stmt)
 
void executeBlock (const std::vector< std::shared_ptr< Stmt > > statements, std::shared_ptr< Environment > environment)
 
std::any visitBinaryExpr (std::shared_ptr< Binary > expr) override
 
std::any visitLogicalExpr (std::shared_ptr< Logical > expr) override
 
std::any visitGroupingExpr (std::shared_ptr< Grouping > expr) override
 
std::any visitLiteralExpr (std::shared_ptr< Literal > expr) override
 
std::any visitUnaryExpr (std::shared_ptr< Unary > expr) override
 
std::any visitAssignExpr (std::shared_ptr< Assign > expr) override
 
std::any visitVariableExpr (std::shared_ptr< Variable > expr) override
 
std::any visitBlockStmt (std::shared_ptr< Block > stmt) override
 
std::any visitExpressionStmt (std::shared_ptr< Expression > stmt) override
 
std::any visitPrintStmt (std::shared_ptr< Print > stmt) override
 
std::any visitIfStmt (std::shared_ptr< If > stmt) override
 
std::any visitWhileStmt (std::shared_ptr< While > stmt) override
 
std::any visitVarStmt (std::shared_ptr< Var > stmt) override
 
template<class... N>
void checkNumberOperands (const Token &op, N... operands)
 
bool isTruthy (const std::any &value) const
 
bool isEqual (const std::any &a, const std::any &b) const
 
std::string stringify (const std::any &value) const
 

Private Attributes

std::shared_ptr< Environmentenvironment {new Environment}
 

Detailed Description

The Interpreter class evaluates statements and expressions in the GSC.

Note
It implements the ExprVisitor interface to visit different types of expressions and statements, and evaluate them accordingly. The results of the evaluations are returned as std::any types, allowing for flexibility in the types of values that can be returned.

Definition at line 16 of file interpreter.hpp.

Member Function Documentation

◆ checkNumberOperands()

template<class... N>
void Interpreter::checkNumberOperands ( const Token op,
N...  operands 
)
private

Definition at line 42 of file interpreter.cpp.

42 {
43 if (((operands.type() != typeid(int)) && ...)) {
44 throw RuntimeError(std::make_shared<Token>(op),
45 "Operands must be numbers.");
46 }
47}
Represents a runtime error in the GSC interpreter.

◆ evaluate()

std::any Interpreter::evaluate ( std::shared_ptr< Expr expr)
private

Definition at line 17 of file interpreter.cpp.

17 {
18 return expr->accept(*this);
19}

◆ execute()

void Interpreter::execute ( std::shared_ptr< Stmt stmt)
private

Definition at line 21 of file interpreter.cpp.

21{ stmt->accept(*this); }

◆ executeBlock()

void Interpreter::executeBlock ( const std::vector< std::shared_ptr< Stmt > >  statements,
std::shared_ptr< Environment environment 
)
private

Definition at line 23 of file interpreter.cpp.

25 {
26 std::shared_ptr<Environment> previous = this->environment;
27 try {
29
30 for (const std::shared_ptr<Stmt> &stmt : statements) {
31 execute(stmt);
32 }
33 } catch (...) {
34 this->environment = previous;
35 throw; // Re-throw the exception to be handled by the caller
36 }
37
38 this->environment = previous;
39}
std::shared_ptr< Environment > environment
void execute(std::shared_ptr< Stmt > stmt)

◆ interpret()

void Interpreter::interpret ( const std::vector< std::shared_ptr< Stmt > > &  statements)

Interpret the given statement list and execute them.

Parameters
statementsA vector of shared pointers to Stmt objects representing
Note
This method evaluates the provided statements in the context of the GSC interpreter.
If an error occurs during interpretation, it will shown an error message to the user and set the hadRuntimeError variable to true.

Definition at line 6 of file interpreter.cpp.

7 {
8 try {
9 for (const std::shared_ptr<Stmt> &stmt : statements) {
10 execute(stmt);
11 }
12 } catch (RuntimeError &error) {
14 }
15}
void error(const int &line, const std::string &message)
Report an error in the given line.
Definition error.cpp:12
void runtimeError(const RuntimeError &error)
Report a runtime error given a RuntimeError object.
Definition error.cpp:24

◆ isEqual()

bool Interpreter::isEqual ( const std::any &  a,
const std::any &  b 
) const
private

Definition at line 63 of file interpreter.cpp.

63 {
64 if (a.type() != b.type()) {
65 return false;
66 } else if (a.type() == typeid(std::nullptr_t)) {
67 return true; // Both are nil
68 } else if (a.type() == typeid(bool)) {
69 return std::any_cast<bool>(a) == std::any_cast<bool>(b);
70 } else if (a.type() == typeid(int)) {
71 return std::any_cast<int>(a) == std::any_cast<int>(b);
72 } else if (a.type() == typeid(std::string)) {
73 return std::any_cast<std::string>(a) == std::any_cast<std::string>(b);
74 } else {
75 return false; // Unsupported types
76 }
77}

◆ isTruthy()

bool Interpreter::isTruthy ( const std::any &  value) const
private

Definition at line 49 of file interpreter.cpp.

49 {
50 if (value.type() == typeid(std::nullptr_t)) {
51 return false;
52 } else if (value.type() == typeid(int)) {
53 return std::any_cast<int>(value) != 0; // Non-zero integers are truthy
54 } else if (value.type() == typeid(std::string)) {
55 return !std::any_cast<std::string>(value)
56 .empty(); // Non-empty strings are truthy
57 } else if (value.type() == typeid(bool)) {
58 return std::any_cast<bool>(value);
59 }
60 return true; // All other values are truthy
61}

◆ stringify()

std::string Interpreter::stringify ( const std::any &  value) const
private

Definition at line 79 of file interpreter.cpp.

79 {
80 if (value.type() == typeid(std::nullptr_t)) {
81 return "nil";
82 } else if (value.type() == typeid(bool)) {
83 return std::any_cast<bool>(value) ? "true" : "false";
84 } else if (value.type() == typeid(int)) {
85 return std::to_string(std::any_cast<int>(value));
86 } else if (value.type() == typeid(std::string)) {
87 return std::any_cast<std::string>(value);
88 } else if (value.type() == typeid(const char *)) {
89 return std::any_cast<const char *>(value);
90 }
91 return "Internal error (interpreter): object type not recognized"; // Unsupported
92 // types
93}

◆ visitAssignExpr()

std::any Interpreter::visitAssignExpr ( std::shared_ptr< Assign expr)
overrideprivatevirtual

Implements ExprVisitor.

Definition at line 185 of file interpreter.cpp.

185 {
186 std::any value = evaluate(expr->getValue());
187 environment->assign(expr->getName(), value);
188 return value;
189}
std::any evaluate(std::shared_ptr< Expr > expr)

◆ visitBinaryExpr()

std::any Interpreter::visitBinaryExpr ( std::shared_ptr< Binary expr)
overrideprivatevirtual

Implements ExprVisitor.

Definition at line 120 of file interpreter.cpp.

120 {
121 std::any left = evaluate(expr->getLeft());
122 std::any right = evaluate(expr->getRight());
123 Token op = expr->getOp();
124
125 switch (op.getType()) {
126 case TokenType::PLUS:
127 if (left.type() == typeid(int) && right.type() == typeid(int)) {
128 return std::any_cast<int>(left) + std::any_cast<int>(right);
129 } else if (left.type() == typeid(std::string) &&
130 right.type() == typeid(std::string)) {
131 return std::any_cast<std::string>(left) +
132 std::any_cast<std::string>(right);
133 } else {
134 throw RuntimeError(std::make_shared<Token>(op),
135 "Operands must be two numbers or two strings.");
136 }
137 case TokenType::MINUS:
138 checkNumberOperands(op, left, right);
139 return std::any_cast<int>(left) - std::any_cast<int>(right);
140 case TokenType::STAR:
141 checkNumberOperands(op, left, right);
142 return std::any_cast<int>(left) * std::any_cast<int>(right);
143 case TokenType::SLASH:
144 checkNumberOperands(op, left, right);
145 if (std::any_cast<int>(right) == 0) {
146 throw RuntimeError(std::make_shared<Token>(op), "Division by zero.");
147 }
148 return std::any_cast<int>(left) / std::any_cast<int>(right);
150 checkNumberOperands(op, left, right);
151 return std::any_cast<int>(left) > std::any_cast<int>(right);
153 checkNumberOperands(op, left, right);
154 return std::any_cast<int>(left) >= std::any_cast<int>(right);
155 case TokenType::LESS:
156 checkNumberOperands(op, left, right);
157 return std::any_cast<int>(left) < std::any_cast<int>(right);
159 checkNumberOperands(op, left, right);
160 return std::any_cast<int>(left) <= std::any_cast<int>(right);
162 return isEqual(left, right);
164 return !isEqual(left, right);
165 default:
166 // This should never be reached, but just in case
167 assert(false && "Unknown binary operator");
168 return {};
169 }
170}
void checkNumberOperands(const Token &op, N... operands)
bool isEqual(const std::any &a, const std::any &b) const
Represents a token in the source code.
Definition token.hpp:14
TokenType getType() const
Definition token.cpp:8
@ GREATER
Definition tokenType.hpp:27
@ GREATER_EQUAL
Definition tokenType.hpp:28
@ EQUAL_EQUAL
Definition tokenType.hpp:26
@ BANG_EQUAL
Definition tokenType.hpp:24
@ PLUS
Definition tokenType.hpp:17
@ LESS
Definition tokenType.hpp:29
@ STAR
Definition tokenType.hpp:20
@ SLASH
Definition tokenType.hpp:19
@ LESS_EQUAL
Definition tokenType.hpp:30
@ MINUS
Definition tokenType.hpp:16

◆ visitBlockStmt()

std::any Interpreter::visitBlockStmt ( std::shared_ptr< Block stmt)
overrideprivatevirtual

Implements StmtVisitor.

Definition at line 195 of file interpreter.cpp.

195 {
196 executeBlock(stmt->getStatements(),
197 std::make_shared<Environment>(environment));
198 return {};
199}
void executeBlock(const std::vector< std::shared_ptr< Stmt > > statements, std::shared_ptr< Environment > environment)

◆ visitExpressionStmt()

std::any Interpreter::visitExpressionStmt ( std::shared_ptr< Expression stmt)
overrideprivatevirtual

Implements StmtVisitor.

Definition at line 201 of file interpreter.cpp.

201 {
202 evaluate(stmt->getExpression());
203 return {};
204}

◆ visitGroupingExpr()

std::any Interpreter::visitGroupingExpr ( std::shared_ptr< Grouping expr)
overrideprivatevirtual

Implements ExprVisitor.

Definition at line 95 of file interpreter.cpp.

95 {
96 return evaluate(expr->getExpression());
97}

◆ visitIfStmt()

std::any Interpreter::visitIfStmt ( std::shared_ptr< If stmt)
overrideprivatevirtual

Implements StmtVisitor.

Definition at line 212 of file interpreter.cpp.

212 {
213 std::any condition = evaluate(stmt->getCondition());
214 if (isTruthy(condition)) {
215 execute(stmt->getThenBranch());
216 } else if (stmt->getElseBranch()) {
217 execute(stmt->getElseBranch());
218 }
219 return {};
220}
bool isTruthy(const std::any &value) const

◆ visitLiteralExpr()

std::any Interpreter::visitLiteralExpr ( std::shared_ptr< Literal expr)
overrideprivatevirtual

Implements ExprVisitor.

Definition at line 99 of file interpreter.cpp.

99 {
100 return expr->getValue();
101}

◆ visitLogicalExpr()

std::any Interpreter::visitLogicalExpr ( std::shared_ptr< Logical expr)
overrideprivatevirtual

Implements ExprVisitor.

Definition at line 172 of file interpreter.cpp.

172 {
173 std::any left = evaluate(expr->getLeft());
174 Token op = expr->getOp();
175
176 // Short-circuit evaluation
177 if ((op.getType() == TokenType::OR && isTruthy(left)) ||
178 (op.getType() == TokenType::AND && !isTruthy(left))) {
179 return left;
180 }
181
182 return evaluate(expr->getRight());
183}
@ AND
Definition tokenType.hpp:38
@ OR
Definition tokenType.hpp:39

◆ visitPrintStmt()

std::any Interpreter::visitPrintStmt ( std::shared_ptr< Print stmt)
overrideprivatevirtual

Implements StmtVisitor.

Definition at line 206 of file interpreter.cpp.

206 {
207 std::any value = evaluate(stmt->getExpression());
208 std::cout << stringify(value) << std::endl;
209 return {};
210}
std::string stringify(const std::any &value) const

◆ visitUnaryExpr()

std::any Interpreter::visitUnaryExpr ( std::shared_ptr< Unary expr)
overrideprivatevirtual

Implements ExprVisitor.

Definition at line 103 of file interpreter.cpp.

103 {
104 std::any right = evaluate(expr->getRight());
105 Token op = expr->getOp();
106
107 switch (op.getType()) {
108 case TokenType::MINUS:
109 checkNumberOperands(op, right);
110 return -std::any_cast<int>(right);
111 case TokenType::BANG:
112 return !isTruthy(right);
113 default:
114 // This should never be reached, but just in case
115 assert(false && "Unknown unary operator");
116 return {};
117 }
118}
@ BANG
Definition tokenType.hpp:23

◆ visitVariableExpr()

std::any Interpreter::visitVariableExpr ( std::shared_ptr< Variable expr)
overrideprivatevirtual

Implements ExprVisitor.

Definition at line 191 of file interpreter.cpp.

191 {
192 return environment->get(expr->getName());
193}

◆ visitVarStmt()

std::any Interpreter::visitVarStmt ( std::shared_ptr< Var stmt)
overrideprivatevirtual

Implements StmtVisitor.

Definition at line 229 of file interpreter.cpp.

229 {
230 std::any value = nullptr;
231 if (stmt->getInitializer()) {
232 value = evaluate(stmt->getInitializer());
233 }
234 environment->define(stmt->getName().getLexeme(), std::move(value));
235 return {};
236}

◆ visitWhileStmt()

std::any Interpreter::visitWhileStmt ( std::shared_ptr< While stmt)
overrideprivatevirtual

Implements StmtVisitor.

Definition at line 222 of file interpreter.cpp.

222 {
223 while (isTruthy(evaluate(stmt->getCondition()))) {
224 execute(stmt->getBody());
225 }
226 return {};
227}

Member Data Documentation

◆ environment

std::shared_ptr<Environment> Interpreter::environment {new Environment}
private

Definition at line 18 of file interpreter.hpp.

18{new Environment};
Represents an environment for variable storage in the GSC interpreter.

The documentation for this class was generated from the following files: