From d5cb498ba37949193fecafa8c1f15d70ade79515 Mon Sep 17 00:00:00 2001 From: Dimitar Trendafilov Date: Sun, 21 Oct 2018 21:27:36 +0300 Subject: Added a tree interpreter --- JSImpl/src/main.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'JSImpl/src/main.cpp') diff --git a/JSImpl/src/main.cpp b/JSImpl/src/main.cpp index 73f883f..80dcd32 100644 --- a/JSImpl/src/main.cpp +++ b/JSImpl/src/main.cpp @@ -1,6 +1,7 @@ #include "Lexer.h" #include "Parser.h" #include "ASTPrinter.h" +#include "ASTInterpreter.h" #include #define LOG(msg) std::cout << msg << std::endl #define EXECUTE_TEST(test) std::cout << #test << " "; test(); @@ -198,6 +199,26 @@ void TestParseUnaryExpr() expr->Accept(p); } +void RunParseCalc() +{ + IPLVector tokens; + //Tokenize("var a = 0; var b = a + 123;a+b;", tokens); + Tokenize("123 + 321", tokens); + + // TODO make actual test :D + auto expr = Parse(tokens); + ASTPrinter p(std::cout); + expr->Accept(p); + ASTInterpreter i; + std::cout << "Running" << std::endl; + auto result = i.Run(expr.get()); + std::cout << "Stack after run, top to bottom:" << std::endl; + while (!result.empty()) { + std::cout << result.top() << std::endl; + result.pop(); + } +} + void TestHexNumber() { IPLVector tokens; @@ -235,7 +256,8 @@ int main() EXECUTE_TEST(TestHexNumber); EXECUTE_TEST(TestScientificNotationNumber); - // TestParseUnaryExpr(); + //TestParseUnaryExpr(); + //RunParseCalc(); #if defined(_WIN32) std::system("pause"); #endif -- cgit v1.3.1-23-gd82d From 051eb93c188c15e3798018165991b0563bdbaa7f Mon Sep 17 00:00:00 2001 From: Dimitar Trendafilov Date: Mon, 22 Oct 2018 21:54:07 +0300 Subject: Enhanced tree interpreter - Added "proper" C++ like variable scoping - Added operator < - Added ++ and -- --- JSImpl/src/ASTInterpreter.cpp | 156 ++++++++++++++++++++++++++++++++++++++---- JSImpl/src/ASTInterpreter.h | 24 +++++-- JSImpl/src/main.cpp | 21 +++--- 3 files changed, 171 insertions(+), 30 deletions(-) (limited to 'JSImpl/src/main.cpp') diff --git a/JSImpl/src/ASTInterpreter.cpp b/JSImpl/src/ASTInterpreter.cpp index 7ce6d59..d66a9ce 100644 --- a/JSImpl/src/ASTInterpreter.cpp +++ b/JSImpl/src/ASTInterpreter.cpp @@ -3,8 +3,76 @@ #include #include + +#define NOT_IMPLEMENTED (void)e; assert(0 && "not-implemented") + + +struct LValueExtractor : public ExpressionVisitor +{ +public: + LValueExtractor(ASTInterpreter* interpreter) + : m_Interpreter(interpreter) + {} + ~LValueExtractor() {} + + ASTInterpreter::value_type* Run(Expression* program) + { + m_LValue = nullptr; + program->Accept(*this); + return m_LValue; + } + + virtual void Visit(LiteralNull* e) override { NOT_IMPLEMENTED; } + virtual void Visit(LiteralUndefined* e) override { NOT_IMPLEMENTED; } + virtual void Visit(LiteralString* e) override { NOT_IMPLEMENTED; } + virtual void Visit(LiteralNumber* e) override { NOT_IMPLEMENTED; } + virtual void Visit(LiteralBoolean* e) override { NOT_IMPLEMENTED; } + virtual void Visit(BinaryExpression* e) override { NOT_IMPLEMENTED; } + virtual void Visit(UnaryExpression* e) override { NOT_IMPLEMENTED; } + virtual void Visit(IdentifierExpression* e) override { m_LValue = &m_Interpreter->ModifyVariable(e->GetName()); } + virtual void Visit(ListExpression* e) override { NOT_IMPLEMENTED; } + virtual void Visit(VariableDefinitionExpression* e) override { NOT_IMPLEMENTED; } + virtual void Visit(BlockStatement* e) override { NOT_IMPLEMENTED; } + virtual void Visit(LabeledStatement* e) override { NOT_IMPLEMENTED; } + virtual void Visit(IfStatement* e) override { NOT_IMPLEMENTED; } + virtual void Visit(SwitchStatement* e) override { NOT_IMPLEMENTED; } + virtual void Visit(CaseStatement *e) override { NOT_IMPLEMENTED; } + virtual void Visit(WhileStatement* e) override { NOT_IMPLEMENTED; } + virtual void Visit(ForStatement* e) override { NOT_IMPLEMENTED; } + virtual void Visit(FunctionDeclaration* e) override { NOT_IMPLEMENTED; } + virtual void Visit(TopStatements* e) override { NOT_IMPLEMENTED; } + virtual void Visit(EmptyExpression* e) override { NOT_IMPLEMENTED; } + + ASTInterpreter* m_Interpreter; + ASTInterpreter::value_type* m_LValue; +}; + + +struct VariableScope +{ + VariableScope(ASTInterpreter* interpreter) + : m_Interpreter(interpreter) + { + m_Interpreter->EnterScope(); + } + + ~VariableScope() { + m_Interpreter->LeaveScope(); + } + + VariableScope(VariableScope&) = delete; + VariableScope(VariableScope&&) = delete; + VariableScope& operator=(VariableScope&) = delete; + VariableScope& operator=(VariableScope&&) = delete; + + ASTInterpreter* m_Interpreter; +}; + ASTInterpreter::ASTInterpreter() -{} +{ + // Allow globals + EnterScope(); +} ASTInterpreter::~ASTInterpreter() {} @@ -32,7 +100,36 @@ bool ASTInterpreter::EvalToBool(const ExpressionPtr& e) return result != 0.0; } -#define NOT_IMPLEMENTED (void)e; assert(0 && "not-implemented") +void ASTInterpreter::EnterScope() +{ + m_Scopes.push(Scope{}); +} + +void ASTInterpreter::LeaveScope() +{ + const auto& scope = m_Scopes.top(); + for (auto& var : scope) { + auto values = m_Variables.find(var); + values->second.pop(); + if (values->second.empty()) { + m_Variables.erase(values); + } + } + m_Scopes.pop(); +} + +ASTInterpreter::value_type& ASTInterpreter::ModifyVariable(const IPLString& name) +{ + auto values = m_Variables.find(name); + if (values != m_Variables.end()) { + return values->second.top(); + } + else { + assert(0 && "not-defined"); + } + static value_type undefined; + return undefined; +} void ASTInterpreter::Visit(LiteralNull* e) { NOT_IMPLEMENTED; @@ -75,23 +172,45 @@ void ASTInterpreter::Visit(BinaryExpression* e) { case TokenType::Division: m_Evaluation.push(left / right); break; + case TokenType::Less: + m_Evaluation.push(left < right); + break; + case TokenType::Comma: + m_Evaluation.push(right); + break; default: NOT_IMPLEMENTED; } } void ASTInterpreter::Visit(UnaryExpression* e) { - NOT_IMPLEMENTED; + LValueExtractor extractor(this); + auto lvalue = extractor.Run(e->GetExpr().get()); + if (e->GetSuffix()) + { + m_Evaluation.push(*lvalue); + } + switch (e->GetOperator()) + { + case TokenType::PlusPlus: + ++(*lvalue); + break; + case TokenType::MinusMinus: + --(*lvalue); + break; + default: + NOT_IMPLEMENTED; + } + if (!e->GetSuffix()) + { + m_Evaluation.push(*lvalue); + } } void ASTInterpreter::Visit(IdentifierExpression* e) { - auto values = m_Variables.find(e->GetName()); - if (values != m_Variables.end()) { - m_Evaluation.push(values->second.top()); - } else { - throw "Not-defined"; - } + m_Evaluation.push(ModifyVariable(e->GetName())); } + void ASTInterpreter::Visit(ListExpression* e) { for (const auto& stmt: e->GetValues()) { stmt->Accept(*this); @@ -100,7 +219,9 @@ void ASTInterpreter::Visit(ListExpression* e) { void ASTInterpreter::Visit(VariableDefinitionExpression* e) { e->GetValue()->Accept(*this); - m_Variables[e->GetName()].push(m_Evaluation.top()); + auto& name = e->GetName(); + m_Variables[name].push(m_Evaluation.top()); + m_Scopes.top().push_back(name); m_Evaluation.pop(); } @@ -115,10 +236,13 @@ void ASTInterpreter::Visit(LabeledStatement* e) { } void ASTInterpreter::Visit(IfStatement* e) { - if (EvalToBool(e->GetCondition())) { - RunExpression(e->GetIfStatement()); + VariableScope scope(this); + if (EvalToBool(e->GetCondition())) { + VariableScope ifScope(this); + RunExpression(e->GetIfStatement()); } else { - RunExpression(e->GetElseStatement()); + VariableScope elseScope(this); + RunExpression(e->GetElseStatement()); } } @@ -126,18 +250,24 @@ void ASTInterpreter::Visit(SwitchStatement* e) { NOT_IMPLEMENTED;} void ASTInterpreter::Visit(CaseStatement *e) { NOT_IMPLEMENTED;} void ASTInterpreter::Visit(WhileStatement* e) { + VariableScope scope(this); if (e->GetDoWhile()) { + VariableScope bodyScope(this); RunExpression(e->GetBody()); } while (EvalToBool(e->GetCondition())) { + VariableScope bodyScope(this); RunExpression(e->GetBody()); } } void ASTInterpreter::Visit(ForStatement* e) { + VariableScope scope(this); + for (RunExpression(e->GetInitialization()); EvalToBool(e->GetCondition()); RunExpression(e->GetIteration())) { + VariableScope bodyScope(this); RunExpression(e->GetBody()); } } diff --git a/JSImpl/src/ASTInterpreter.h b/JSImpl/src/ASTInterpreter.h index 1ffecde..4d5b46f 100644 --- a/JSImpl/src/ASTInterpreter.h +++ b/JSImpl/src/ASTInterpreter.h @@ -11,10 +11,10 @@ public: ASTInterpreter(); ~ASTInterpreter(); - typedef double value_type; - typedef std::stack ValueStack; + typedef double value_type; + typedef IPLStack ValueStack; - ValueStack Run(Expression* program); + ValueStack Run(Expression* program); virtual void Visit(LiteralNull* e) override; virtual void Visit(LiteralUndefined* e) override; @@ -36,9 +36,19 @@ public: virtual void Visit(FunctionDeclaration* e) override; virtual void Visit(TopStatements* e) override; virtual void Visit(EmptyExpression* e) override; + + value_type& ModifyVariable(const IPLString& name); private: - void RunExpression(const ExpressionPtr& e); - bool EvalToBool(const ExpressionPtr& e); - ValueStack m_Evaluation; - std::unordered_map m_Variables; + void RunExpression(const ExpressionPtr& e); + bool EvalToBool(const ExpressionPtr& e); + + void EnterScope(); + void LeaveScope(); + friend struct VariableScope; + + ValueStack m_Evaluation; + IPLUnorderedMap m_Variables; + + typedef IPLVector Scope; + IPLStack m_Scopes; }; diff --git a/JSImpl/src/main.cpp b/JSImpl/src/main.cpp index 80dcd32..7dcdd74 100644 --- a/JSImpl/src/main.cpp +++ b/JSImpl/src/main.cpp @@ -203,20 +203,21 @@ void RunParseCalc() { IPLVector tokens; //Tokenize("var a = 0; var b = a + 123;a+b;", tokens); - Tokenize("123 + 321", tokens); + Tokenize("var s = 0; for (var i = 0; i < 10; ++i + --s) { s };", tokens); // TODO make actual test :D auto expr = Parse(tokens); - ASTPrinter p(std::cout); - expr->Accept(p); + //ASTPrinter p(std::cout); + //expr->Accept(p); ASTInterpreter i; - std::cout << "Running" << std::endl; + std::cout << "Running" << std::endl; auto result = i.Run(expr.get()); - std::cout << "Stack after run, top to bottom:" << std::endl; - while (!result.empty()) { - std::cout << result.top() << std::endl; - result.pop(); - } + std::cout << "Stack after run, top to bottom:" << std::endl; + while (!result.empty()) { + std::cout << result.top() << std::endl; + result.pop(); + } + std::cout << "S = " << i.ModifyVariable("i") << std::endl; } void TestHexNumber() @@ -257,7 +258,7 @@ int main() EXECUTE_TEST(TestScientificNotationNumber); //TestParseUnaryExpr(); - //RunParseCalc(); + RunParseCalc(); #if defined(_WIN32) std::system("pause"); #endif -- cgit v1.3.1-23-gd82d From 74363cca95d59c3b756675701f6e843597593225 Mon Sep 17 00:00:00 2001 From: Dimitar Trendafilov Date: Wed, 24 Oct 2018 19:48:44 +0300 Subject: Fixed using only defined variables for the interpreter demo --- JSImpl/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'JSImpl/src/main.cpp') diff --git a/JSImpl/src/main.cpp b/JSImpl/src/main.cpp index 7dcdd74..dd54f38 100644 --- a/JSImpl/src/main.cpp +++ b/JSImpl/src/main.cpp @@ -217,7 +217,7 @@ void RunParseCalc() std::cout << result.top() << std::endl; result.pop(); } - std::cout << "S = " << i.ModifyVariable("i") << std::endl; + std::cout << "S = " << i.ModifyVariable("s") << std::endl; } void TestHexNumber() -- cgit v1.3.1-23-gd82d