diff --git a/src/include/interpreter.h b/src/include/interpreter.h index 3582ef5..0a119cd 100644 --- a/src/include/interpreter.h +++ b/src/include/interpreter.h @@ -10,6 +10,6 @@ using namespace std; /* Evaluates the AST, returning the latest calulated value */ -EvalResult eval(Node &ast, Memory& memory); +EvalResult eval(Node &ast, Memory& memory); #endif \ No newline at end of file diff --git a/src/include/memory.h b/src/include/memory.h index 01075f2..1bfe920 100644 --- a/src/include/memory.h +++ b/src/include/memory.h @@ -5,7 +5,6 @@ #include "types.h" using namespace std; -template class Memory { public: bool contains(string identifier); @@ -13,9 +12,9 @@ class Memory { void add_scope(ScopeType type); void remove_scope(void); - MemoryEntry get(string identifier); - void declare(string identifier, MemoryEntry value); - void update(string identifier, MemoryEntry value); + MemoryVar& get(string identifier); + void declare(string identifier, Type type); + void update(string identifier, EvalResult value); Scope& _debug_top(void); @@ -25,74 +24,4 @@ class Memory { list scopes; }; -template -Memory::Memory(void) { - scopes.emplace_back(); - scopes.back().depth = 0; -} - -template -bool Memory::contains(string identifier) { - for (auto rit = scopes.rbegin(); rit != scopes.rend(); ++rit) { - Scope& scope = *rit; - if (scope.vars.contains(identifier)) return true; - } - - return false; -} - -template -bool Memory::contains_top(string identifier) { - Scope& top = scopes.back(); - return top.vars.contains(identifier); -} - -template -void Memory::add_scope(ScopeType type) { - Scope& top = scopes.back(); - scopes.emplace_back(); - scopes.back().depth = top.depth + 1; - scopes.back().type = type; -} - -template -void Memory::remove_scope(void) { - scopes.pop_back(); -} - -template -MemoryEntry Memory::get(string identifier) { - for (auto rit = scopes.rbegin(); rit != scopes.rend(); ++rit) { - Scope& scope = *rit; - if (scope.vars.contains(identifier)) return scope.vars[identifier]; - } - - throw; -} - -template -void Memory::declare(string identifier, MemoryEntry value) { - Scope& top = scopes.back(); - top.vars[identifier] = value; -} - -template -void Memory::update(string identifier, MemoryEntry value) { - for (auto rit = scopes.rbegin(); rit != scopes.rend(); ++rit) { - Scope& scope = *rit; - if (scope.vars.contains(identifier)) { - scope.vars[identifier] = value; - return; - } - } - - throw; -} - -template -Scope& Memory::_debug_top(void) { - Scope& top = scopes.back(); - return top; -} - #endif \ No newline at end of file diff --git a/src/include/types.h b/src/include/types.h index 9ac403e..8f9f1c0 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -15,7 +15,7 @@ using namespace std; enum class TokenType { Type, Identifier, Litteral, Plus, Minus, DoublePlus, DoubleMinus, DoubleEqual, Land, Lor, Lt, Gt, Leq, Geq, NotEqual, Not, Star, Slash, Percent, Equal, Semicolon, LParenthese, RParenthese, LCurlyBracket, RCurlyBracket, If, Else, While, For, Comma }; enum class Type { Int, Double }; -using TokenData = variant; +using TokenData = variant; struct CodePosition { int line; @@ -165,8 +165,14 @@ using EvalResult = variant; enum class ScopeType { Block, Function, For }; +struct MemoryVar { + EvalResult value; + Type type; + bool initialized; +}; + struct Scope { - unordered_map vars; + unordered_map vars; int depth; ScopeType type; }; diff --git a/src/interpreter.cpp b/src/interpreter.cpp index 76085a1..452b1d5 100644 --- a/src/interpreter.cpp +++ b/src/interpreter.cpp @@ -41,7 +41,7 @@ double double_cast(EvalResult value) { } } -EvalResult eval(Node &ast, Memory &memory) { +EvalResult eval(Node &ast, Memory &memory) { if (holds_alternative(ast)) { InnerNode node = get(ast); switch (node.type) { @@ -253,24 +253,27 @@ EvalResult eval(Node &ast, Memory &memory) { case NodeType::Declaration: { Token typeTok = get(node.children[0]); Token identifierTok = get(node.children[1]); + Type type = get(typeTok.data); string identifier = get(identifierTok.data); - if (memory.contains_top(identifier)) throw RuntimeError("Identifier \""+identifier+"\" was already declared in this scope", identifierTok.pos); - - memory.declare(identifier, { }); + memory.declare(identifier, type); return {}; } break; case NodeType::AssignedDeclaration: { Token typeTok = get(node.children[0]); Token identifierTok = get(node.children[1]); - // Type type = get(typeTok.data); + Type type = get(typeTok.data); string identifier = get(identifierTok.data); EvalResult value = eval(node.children[2], memory); - if (memory.contains_top(identifier)) throw RuntimeError("Identifier \""+identifier+"\" was already declared in this scope", identifierTok.pos); - - memory.declare(identifier, value); + memory.declare(identifier, type); + if (type == Type::Int) { + memory.update(identifier, int_cast(value)); + } + else if (type == Type::Double) { + memory.update(identifier, double_cast(value)); + } return value; } break; @@ -279,9 +282,14 @@ EvalResult eval(Node &ast, Memory &memory) { string identifier = get(identifierTok.data); EvalResult value = eval(node.children[1], memory); - if (!memory.contains(identifier)) throw RuntimeError("Unknown identifier \""+identifier+"\"", identifierTok.pos); + Type type = memory.get(identifier).type; - memory.update(identifier, value); + if (type == Type::Int) { + memory.update(identifier, int_cast(value)); + } + else if (type == Type::Double) { + memory.update(identifier, double_cast(value)); + } return value; } break; @@ -289,71 +297,71 @@ EvalResult eval(Node &ast, Memory &memory) { Token identifierTok = get(node.children[0]); string identifier = get(identifierTok.data); - if (!memory.contains(identifier)) throw RuntimeError("Unknown identifier \""+identifier+"\"", identifierTok.pos); + MemoryVar& var = memory.get(identifier); - EvalResult value = memory.get(identifier); - - if (holds_alternative(value)) { - memory.update(identifier, get(value) + 1); - return memory.get(identifier); - } - else if (holds_alternative(value)) { + if (!var.initialized) { throw RuntimeError("Accessing uninitialized identifier \""+identifier+"\"", identifierTok.pos); } - - return value; + else if (var.type == Type::Int) { + memory.update(identifier, get(var.value) + 1); + return var.value; + } + else { + return var.value; + } } case NodeType::RIncr: { Token identifierTok = get(node.children[0]); string identifier = get(identifierTok.data); - if (!memory.contains(identifier)) throw RuntimeError("Unknown identifier \""+identifier+"\"", identifierTok.pos); + MemoryVar& var = memory.get(identifier); - EvalResult value = memory.get(identifier); - - if (holds_alternative(memory.get(identifier))) { - memory.update(identifier, get(value) + 1); - } - else if (holds_alternative(value)) { + if (!var.initialized) { throw RuntimeError("Accessing uninitialized identifier \""+identifier+"\"", identifierTok.pos); } - - return value; + else if (var.type == Type::Int) { + int oldVal = get(var.value); + memory.update(identifier, oldVal + 1); + return oldVal; + } + else { + return var.value; + } } case NodeType::LDecr: { Token identifierTok = get(node.children[0]); string identifier = get(identifierTok.data); - if (!memory.contains(identifier)) throw RuntimeError("Unknown identifier \""+identifier+"\"", identifierTok.pos); + MemoryVar& var = memory.get(identifier); - EvalResult value = memory.get(identifier); - - if (holds_alternative(value)) { - memory.update(identifier, get(value) - 1); - return memory.get(identifier); - } - else if (holds_alternative(value)) { + if (!var.initialized) { throw RuntimeError("Accessing uninitialized identifier \""+identifier+"\"", identifierTok.pos); } - - return value; + else if (var.type == Type::Int) { + memory.update(identifier, get(var.value) - 1); + return var.value; + } + else { + return var.value; + } } case NodeType::RDecr: { Token identifierTok = get(node.children[0]); string identifier = get(identifierTok.data); - if (!memory.contains(identifier)) throw RuntimeError("Unknown identifier \""+identifier+"\"", identifierTok.pos); + MemoryVar& var = memory.get(identifier); - EvalResult value = memory.get(identifier); - - if (holds_alternative(memory.get(identifier))) { - memory.update(identifier, get(value) - 1); - } - else if (holds_alternative(value)) { + if (!var.initialized) { throw RuntimeError("Accessing uninitialized identifier \""+identifier+"\"", identifierTok.pos); } - - return value; + else if (var.type == Type::Int) { + int oldVal = get(var.value); + memory.update(identifier, oldVal - 1); + return oldVal; + } + else { + return var.value; + } } default: { throw RuntimeError("Not Implemented", node.pos); @@ -376,13 +384,11 @@ EvalResult eval(Node &ast, Memory &memory) { case TokenType::Identifier: { string identifier = get(token.data); - if (!memory.contains(identifier)) throw RuntimeError("Unknown identifier \""+identifier+"\"", token.pos); + MemoryVar& var = memory.get(identifier); - EvalResult value = memory.get(identifier); - - if (holds_alternative(value)) throw RuntimeError("Accessing uninitialized identifier \""+identifier+"\"", token.pos); + if (!var.initialized) throw RuntimeError("Accessing uninitialized identifier \""+identifier+"\"", token.pos); - return value; + return var.value; } break; default: throw; diff --git a/src/main.cpp b/src/main.cpp index cedbc26..82fc7a8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,7 +24,7 @@ int main(int argc, char* argv[]) { vector input; vector tokens; - Memory memory; + Memory memory; while (true) { try { diff --git a/src/memory.cpp b/src/memory.cpp new file mode 100644 index 0000000..695956b --- /dev/null +++ b/src/memory.cpp @@ -0,0 +1,64 @@ +#include "include/memory.h" +using namespace std; + +Memory::Memory(void) { + scopes.emplace_back(); + scopes.back().depth = 0; +} + +bool Memory::contains(string identifier) { + for (auto rit = scopes.rbegin(); rit != scopes.rend(); ++rit) { + Scope& scope = *rit; + if (scope.vars.contains(identifier)) return true; + } + + return false; +} + +bool Memory::contains_top(string identifier) { + Scope& top = scopes.back(); + return top.vars.contains(identifier); +} + +void Memory::add_scope(ScopeType type) { + Scope& top = scopes.back(); + scopes.emplace_back(); + scopes.back().depth = top.depth + 1; + scopes.back().type = type; +} + +void Memory::remove_scope(void) { + scopes.pop_back(); +} + +MemoryVar& Memory::get(string identifier) { + for (auto rit = scopes.rbegin(); rit != scopes.rend(); ++rit) { + Scope& scope = *rit; + if (scope.vars.contains(identifier)) return scope.vars[identifier]; + } + + throw; +} + +void Memory::declare(string identifier, Type type) { + Scope& top = scopes.back(); + top.vars[identifier].type = type; +} + +void Memory::update(string identifier, EvalResult value) { + for (auto rit = scopes.rbegin(); rit != scopes.rend(); ++rit) { + Scope& scope = *rit; + if (scope.vars.contains(identifier)) { + scope.vars[identifier].value = value; + scope.vars[identifier].initialized = true; + return; + } + } + + throw; +} + +Scope& Memory::_debug_top(void) { + Scope& top = scopes.back(); + return top; +} \ No newline at end of file diff --git a/src/tokenize.cpp b/src/tokenize.cpp index afe8748..468054b 100644 --- a/src/tokenize.cpp +++ b/src/tokenize.cpp @@ -35,9 +35,52 @@ vector> simpleTokens = { { "(", TokenType::LParenthese }, { ")", TokenType::RParenthese }, { "{", TokenType::LCurlyBracket }, - { "}", TokenType::RCurlyBracket } + { "}", TokenType::RCurlyBracket }, + { ",", TokenType::Comma } }; +string _debug_get_type_name(Type type) { + switch (type) { + case Type::Int: return "INT"; + case Type::Double: return "DOUBLE"; + default: return "Unknown"; + } +} + +string _debug_get_token_type_name(TokenType type) { + switch (type) { + case TokenType::Identifier: return "Identifier"; + case TokenType::Litteral: return "Litteral"; + case TokenType::Plus: return "Plus"; + case TokenType::Minus: return "Minus"; + case TokenType::DoublePlus: return "DoublePlus"; + case TokenType::DoubleMinus: return "DoubleMinus"; + case TokenType::DoubleEqual: return "DoubleEqual"; + case TokenType::Land: return "Land"; + case TokenType::Lor: return "Lor"; + case TokenType::Lt: return "Lt"; + case TokenType::Gt: return "Gt"; + case TokenType::Leq: return "Leq"; + case TokenType::Geq: return "Geq"; + case TokenType::NotEqual: return "NotEqual"; + case TokenType::Not: return "Not"; + case TokenType::Star: return "Star"; + case TokenType::Slash: return "Slash"; + case TokenType::Percent: return "Percent"; + case TokenType::Equal: return "Equal"; + case TokenType::Semicolon: return "Semicolon"; + case TokenType::LParenthese: return "LParenthese"; + case TokenType::RParenthese: return "RParenthese"; + case TokenType::LCurlyBracket: return "LCurlyBracket"; + case TokenType::RCurlyBracket: return "RCurlyBracket"; + case TokenType::If: return "If"; + case TokenType::Else: return "Else"; + case TokenType::While: return "While"; + case TokenType::For: return "For"; + default: return "Unknown"; + } +} + void _debug_print_token(Token token) { switch (token.type) { case TokenType::Litteral: @@ -51,6 +94,9 @@ void _debug_print_token(Token token) { case TokenType::Identifier: cout << "Identifier(" << get(token.data) << ")"; break; + case TokenType::Type: + cout << "Type("+_debug_get_type_name(get(token.data))+")"; + break; case TokenType::Plus: cout << "+"; break; @@ -129,40 +175,9 @@ void _debug_print_token(Token token) { case TokenType::For: cout << "For"; break; - } -} - -string _debug_print_token_type(TokenType type) { - switch (type) { - case TokenType::Identifier: return "Identifier"; - case TokenType::Litteral: return "Litteral"; - case TokenType::Plus: return "Plus"; - case TokenType::Minus: return "Minus"; - case TokenType::DoublePlus: return "DoublePlus"; - case TokenType::DoubleMinus: return "DoubleMinus"; - case TokenType::DoubleEqual: return "DoubleEqual"; - case TokenType::Land: return "Land"; - case TokenType::Lor: return "Lor"; - case TokenType::Lt: return "Lt"; - case TokenType::Gt: return "Gt"; - case TokenType::Leq: return "Leq"; - case TokenType::Geq: return "Geq"; - case TokenType::NotEqual: return "NotEqual"; - case TokenType::Not: return "Not"; - case TokenType::Star: return "Star"; - case TokenType::Slash: return "Slash"; - case TokenType::Percent: return "Percent"; - case TokenType::Equal: return "Equal"; - case TokenType::Semicolon: return "Semicolon"; - case TokenType::LParenthese: return "LParenthese"; - case TokenType::RParenthese: return "RParenthese"; - case TokenType::LCurlyBracket: return "LCurlyBracket"; - case TokenType::RCurlyBracket: return "RCurlyBracket"; - case TokenType::If: return "If"; - case TokenType::Else: return "Else"; - case TokenType::While: return "While"; - case TokenType::For: return "For"; - default: return "Unknown"; + case TokenType::Comma: + cout << "Comma"; + break; } } diff --git a/test/bool_logic.cpp b/test/bool_logic.cpp index be9559e..1b6f716 100644 --- a/test/bool_logic.cpp +++ b/test/bool_logic.cpp @@ -6,7 +6,7 @@ #include "../src/include/interpreter.h" int execute(string s) { - Memory memory;; + Memory memory;; vector tokens = tokenize({ s }); Node ast = parse(tokens); EvalResult res = eval(ast, memory); diff --git a/test/expr_arithmetiques.cpp b/test/expr_arithmetiques.cpp index d37d7ff..cc9a0ec 100644 --- a/test/expr_arithmetiques.cpp +++ b/test/expr_arithmetiques.cpp @@ -6,7 +6,7 @@ #include "../src/include/interpreter.h" int execute(string s) { - Memory memory;; + Memory memory;; vector tokens = tokenize({ s }); Node ast = parse(tokens); EvalResult res = eval(ast, memory); diff --git a/test/statements.cpp b/test/statements.cpp index 9e61618..af9980c 100644 --- a/test/statements.cpp +++ b/test/statements.cpp @@ -6,7 +6,7 @@ #include "../src/include/interpreter.h" EvalResult execute(string s) { - Memory memory;; + Memory memory;; vector tokens = tokenize({ s }); Node ast = parse(tokens); EvalResult res = eval(ast, memory); diff --git a/test/tokenize.cpp b/test/tokenize.cpp index e8912a0..73bd85c 100644 --- a/test/tokenize.cpp +++ b/test/tokenize.cpp @@ -11,7 +11,7 @@ int main() { /* All tokens */ vector inputs = { - "int", "a", "=", "x", "++", "--", "==", "&&", "||", "<", ">", "<=", ">=", "!=", "!", "*", "/", "%", "=", ";", "(", ")", "{", "}", "if", "else", "while", "for" + "int", "a", "=", "x", "++", "--", "==", "&&", "||", "<", ">", "<=", ">=", "!=", "!", "*", "/", "%", "=", ";", "(", ")", "{", "}", "if", "else", "while", "for", "," }; vector expectedTypes = { @@ -20,7 +20,8 @@ int main() { TokenType::Lor, TokenType::Lt, TokenType::Gt, TokenType::Leq, TokenType::Geq, TokenType::NotEqual, TokenType::Not, TokenType::Star, TokenType::Slash, TokenType::Percent, TokenType::Equal, TokenType::Semicolon, TokenType::LParenthese, TokenType::RParenthese, TokenType::LCurlyBracket, - TokenType::RCurlyBracket, TokenType::If, TokenType::Else, TokenType::While, TokenType::For + TokenType::RCurlyBracket, TokenType::If, TokenType::Else, TokenType::While, TokenType::For, + TokenType::Comma }; for (size_t i = 0; i < inputs.size(); i++) { diff --git a/test/variables.cpp b/test/variables.cpp index e379fb9..dddac99 100644 --- a/test/variables.cpp +++ b/test/variables.cpp @@ -6,7 +6,7 @@ #include "../src/include/interpreter.h" EvalResult execute(string s) { - Memory memory;; + Memory memory;; vector tokens = tokenize({ s }); Node ast = parse(tokens); EvalResult res = eval(ast, memory);