diff --git a/src/include/types.h b/src/include/types.h index aa27909..8f7a36e 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -11,10 +11,10 @@ using namespace std; /** * Tokens definition */ -enum class TokenType { Type, Identifier, Int, 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 }; +enum class TokenType { 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 }; enum class Type { Int }; -using TokenData = variant; +using TokenData = variant; struct CodePosition { int line; @@ -75,7 +75,7 @@ Unary -> | ! Unary Val -> - | Number + | Litteral | ++ParIdentifier | --ParIdentifier diff --git a/src/interpreter.cpp b/src/interpreter.cpp index 4f98161..aa2e7d5 100644 --- a/src/interpreter.cpp +++ b/src/interpreter.cpp @@ -18,6 +18,29 @@ bool bool_cast(EvalResult value) { } } +int int_cast(EvalResult value) { + if (holds_alternative(value)) { + return get(value); + } else if (holds_alternative(value)) { + return int(get(value)); + } + else { + throw; + } +} + +double double_cast(EvalResult value) { + if (holds_alternative(value)) { + return double(get(value)); + } + else if (holds_alternative(value)) { + return get(value); + } + else { + throw; + } +} + EvalResult eval(Node &ast, Memory &memory) { if (holds_alternative(ast)) { InnerNode node = get(ast); @@ -30,7 +53,7 @@ EvalResult eval(Node &ast, Memory &memory) { return {}; break; case NodeType::If: { - int cond = get(eval(node.children[0], memory)); + int cond = bool_cast(eval(node.children[0], memory)); if (cond) { eval(node.children[1], memory); @@ -39,7 +62,7 @@ EvalResult eval(Node &ast, Memory &memory) { return {}; } break; case NodeType::IfElse: { - int cond = get(eval(node.children[0], memory)); + int cond = bool_cast(eval(node.children[0], memory)); if (cond) { eval(node.children[1], memory); @@ -52,7 +75,7 @@ EvalResult eval(Node &ast, Memory &memory) { } break; case NodeType::While: { while (true) { - int cond = get(eval(node.children[0], memory)); + int cond = bool_cast(eval(node.children[0], memory)); if (!cond) break; eval(node.children[1], memory); @@ -66,7 +89,7 @@ EvalResult eval(Node &ast, Memory &memory) { eval(node.children[0], memory); while (true) { - int cond = get(eval(node.children[1], memory)); + int cond = bool_cast(eval(node.children[1], memory)); if (!cond) break; eval(node.children[3], memory); @@ -137,39 +160,95 @@ EvalResult eval(Node &ast, Memory &memory) { return e1 >= e2; } break; case NodeType::Plus: { - int e1 = get(eval(node.children[0], memory)); - int e2 = get(eval(node.children[1], memory)); - return e1 + e2; + EvalResult e1 = eval(node.children[0], memory); + EvalResult e2 = eval(node.children[1], memory); + + if (holds_alternative(e1) || holds_alternative(e2)) { + double d1 = double_cast(e1); + double d2 = double_cast(e2); + return d1 + d2; + } + else { + int i1 = get(e1); + int i2 = get(e2); + return i1 + i2; + } } break; case NodeType::Minus: { - int e1 = get(eval(node.children[0], memory)); - int e2 = get(eval(node.children[1], memory)); - return e1 - e2; + EvalResult e1 = eval(node.children[0], memory); + EvalResult e2 = eval(node.children[1], memory); + + if (holds_alternative(e1) || holds_alternative(e2)) { + double d1 = double_cast(e1); + double d2 = double_cast(e2); + return d1 - d2; + } + else { + int i1 = get(e1); + int i2 = get(e2); + return i1 - i2; + } } break; case NodeType::Mult: { - int e1 = get(eval(node.children[0], memory)); - int e2 = get(eval(node.children[1], memory)); - return e1 * e2; + EvalResult e1 = eval(node.children[0], memory); + EvalResult e2 = eval(node.children[1], memory); + + if (holds_alternative(e1) || holds_alternative(e2)) { + double d1 = double_cast(e1); + double d2 = double_cast(e2); + return d1 * d2; + } + else { + int i1 = get(e1); + int i2 = get(e2); + return i1 * i2; + } } break; case NodeType::Div: { - int e1 = get(eval(node.children[0], memory)); - int e2 = get(eval(node.children[1], memory)); - if (e2 == 0) throw RuntimeError("Division by 0", node.pos); - return e1 / e2; + EvalResult e1 = eval(node.children[0], memory); + EvalResult e2 = eval(node.children[1], memory); + + if (holds_alternative(e1) || holds_alternative(e2)) { + double d1 = double_cast(e1); + double d2 = double_cast(e2); + if (d2 == 0) throw RuntimeError("Division by 0", node.pos); + return d1 / d2; + } + else { + int i1 = get(e1); + int i2 = get(e2); + if (i2 == 0) throw RuntimeError("Division by 0", node.pos); + return i1 / i2; + } } break; case NodeType::Mod: { - int e1 = get(eval(node.children[0], memory)); - int e2 = get(eval(node.children[1], memory)); - if (e2 == 0) throw RuntimeError("Modulo by 0", node.pos); - return e1 % e2; + EvalResult e1 = eval(node.children[0], memory); + EvalResult e2 = eval(node.children[1], memory); + + int i1 = get(e1); + int i2 = get(e2); + if (i2 == 0) throw RuntimeError("Modulo by 0", node.pos); + return i1 % i2; } break; case NodeType::UnaryPlus: { - int e1 = get(eval(node.children[0], memory)); - return +e1; + EvalResult e1 = eval(node.children[0], memory); + + if (holds_alternative(e1)) { + return +get(e1); + } + else if (holds_alternative(e1)) { + return +get(e1); + } } break; case NodeType::UnaryMinus: { - int e1 = get(eval(node.children[0], memory)); - return -e1; + EvalResult e1 = eval(node.children[0], memory); + + if (holds_alternative(e1)) { + return -get(e1); + } + else if (holds_alternative(e1)) { + return -get(e1); + } } break; case NodeType::Declaration: { Token typeTok = get(node.children[0]); @@ -284,8 +363,15 @@ EvalResult eval(Node &ast, Memory &memory) { else { Token token = get(ast); switch (token.type) { - case TokenType::Int: { - return get(token.data); + case TokenType::Litteral: { + if (holds_alternative(token.data)) { + return get(token.data); + } else if (holds_alternative(token.data)) { + return get(token.data); + } + else { + throw; + } } break; case TokenType::Identifier: { string identifier = get(token.data); diff --git a/src/parser.cpp b/src/parser.cpp index 512f4dc..eb42b2c 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -354,7 +354,7 @@ ParseReturn parse_statement(vector tokens) { } ParseReturn parse_expr_statement(vector tokens) { - if (tokens.size() < 1 || tokens.back().type != TokenType::Type) + if (tokens.size() < 1 || tokens.back().type != TokenType::Identifier) throw ParseException(); Token type = tokens.back(); @@ -638,7 +638,7 @@ ParseReturn parse_val(vector tokens) { throw ParseException(); switch (tokens.back().type) { - case TokenType::Int: { //* Val -> Number + case TokenType::Litteral: { //* Val -> Number Token number = tokens.back(); tokens.pop_back(); return { diff --git a/src/tokenize.cpp b/src/tokenize.cpp index b8b5153..9323f8a 100644 --- a/src/tokenize.cpp +++ b/src/tokenize.cpp @@ -5,17 +5,43 @@ #include "include/tokenize.h" using namespace std; -regex NUMBER_REGEX ("\\d+(\\.\\d+)?"); -regex TYPE_INT_REGEX ("int(\\s|$)"); +regex INT_REGEX ("\\d+"); +regex DOUBLE_REGEX ("\\d+\\.\\d*|\\d*\\.\\d+"); regex IDENTIFIER_REGEX ("[A-Za-z_]\\w*"); +vector> simpleTokens = { + { "if", TokenType::If }, + { "else", TokenType::Else }, + { "while", TokenType::While }, + { "for", TokenType::For }, + { "++", TokenType::DoublePlus }, + { "--", TokenType::DoubleMinus }, + { "==", TokenType::DoubleEqual }, + { "&&", TokenType::Land }, + { "||", TokenType::Lor }, + { "<=", TokenType::Leq }, + { ">=", TokenType::Geq }, + { "!=", TokenType::NotEqual }, + { "<", TokenType::Lt }, + { ">", TokenType::Gt }, + { "!", TokenType::Not }, + { "+", TokenType::Plus }, + { "-", TokenType::Minus }, + { "*", TokenType::Star }, + { "/", TokenType::Slash }, + { "%", TokenType::Percent }, + { "=", TokenType::Equal }, + { ";", TokenType::Semicolon }, + { "(", TokenType::LParenthese }, + { ")", TokenType::RParenthese }, + { "{", TokenType::LCurlyBracket }, + { "}", TokenType::RCurlyBracket } +}; + void _debug_print_token(Token token) { switch (token.type) { - case TokenType::Type: - cout << "Type(INT)"; - break; - case TokenType::Int: - cout << "Number(" << get(token.data) << ")"; + case TokenType::Litteral: + cout << "Litteral(" << "tmp" << ")"; break; case TokenType::Identifier: cout << "Identifier(" << get(token.data) << ")"; @@ -103,9 +129,8 @@ void _debug_print_token(Token token) { string _debug_print_token_type(TokenType type) { switch (type) { - case TokenType::Type: return "Type"; case TokenType::Identifier: return "Identifier"; - case TokenType::Int: return "Int"; + case TokenType::Litteral: return "Litteral"; case TokenType::Plus: return "Plus"; case TokenType::Minus: return "Minus"; case TokenType::DoublePlus: return "DoublePlus"; @@ -156,155 +181,41 @@ vector tokenize(vector input, int initial_line) { string str = line.substr(j, string::npos); smatch m; - if (regex_search(str, m, NUMBER_REGEX, regex_constants::match_continuous)) { + if (regex_search(str, m, DOUBLE_REGEX, regex_constants::match_continuous)) { Token token = { - .type = TokenType::Int, + .type = TokenType::Litteral, + .data = stod(m.str()), + .pos = pos + }; + tokens.emplace_back(token); + j += m.str().length(); + continue; + } + + if (regex_search(str, m, INT_REGEX, regex_constants::match_continuous)) { + Token token = { + .type = TokenType::Litteral, .data = stoi(m.str()), .pos = pos }; tokens.emplace_back(token); j += m.str().length(); + continue; } - else if (regex_search(str, m, TYPE_INT_REGEX, regex_constants::match_continuous)) { - Token token = { - .type = TokenType::Type, - .data = Type::Int, - .pos = pos - }; - tokens.emplace_back(token); - j += m.str().length(); + + bool matched = false; + for (auto simpleToken: simpleTokens) { + if (str.starts_with(get<0>(simpleToken))) { + Token token = { .type = get<1>(simpleToken), .pos = pos }; + tokens.emplace_back(token); + j += get<0>(simpleToken).length(); + matched = true; + break; + } } - else if (str.starts_with("if")) { - Token token = { .type = TokenType::If, .pos = pos }; - tokens.emplace_back(token); - j += 2; - } - else if (str.starts_with("else")) { - Token token = { .type = TokenType::Else, .pos = pos }; - tokens.emplace_back(token); - j += 4; - } - else if (str.starts_with("while")) { - Token token = { .type = TokenType::While, .pos = pos }; - tokens.emplace_back(token); - j += 5; - } - else if (str.starts_with("for")) { - Token token = { .type = TokenType::For, .pos = pos }; - tokens.emplace_back(token); - j += 3; - } - else if (str.starts_with("++")) { - Token token = { .type = TokenType::DoublePlus, .pos = pos }; - tokens.emplace_back(token); - j += 2; - } - else if (str.starts_with("--")) { - Token token = { .type = TokenType::DoubleMinus, .pos = pos }; - tokens.emplace_back(token); - j += 2; - } - else if (str.starts_with("==")) { - Token token = { .type = TokenType::DoubleEqual, .pos = pos }; - tokens.emplace_back(token); - j += 2; - } - else if (str.starts_with("&&")) { - Token token = { .type = TokenType::Land, .pos = pos }; - tokens.emplace_back(token); - j += 2; - } - else if (str.starts_with("||")) { - Token token = { .type = TokenType::Lor, .pos = pos }; - tokens.emplace_back(token); - j += 2; - } - else if (str.starts_with("<=")) { - Token token = { .type = TokenType::Leq, .pos = pos }; - tokens.emplace_back(token); - j += 2; - } - else if (str.starts_with(">=")) { - Token token = { .type = TokenType::Geq, .pos = pos }; - tokens.emplace_back(token); - j += 2; - } - else if (str.starts_with("!=")) { - Token token = { .type = TokenType::NotEqual, .pos = pos }; - tokens.emplace_back(token); - j += 2; - } - else if (str.starts_with("<")) { - Token token = { .type = TokenType::Lt, .pos = pos }; - tokens.emplace_back(token); - j += 1; - } - else if (str.starts_with(">")) { - Token token = { .type = TokenType::Gt, .pos = pos }; - tokens.emplace_back(token); - j += 1; - } - else if (str.starts_with("!")) { - Token token = { .type = TokenType::Not, .pos = pos }; - tokens.emplace_back(token); - j += 1; - } - else if (str.starts_with("+")) { - Token token = { .type = TokenType::Plus, .pos = pos }; - tokens.emplace_back(token); - j += 1; - } - else if (str.starts_with("-")) { - Token token = { .type = TokenType::Minus, .pos = pos }; - tokens.emplace_back(token); - j += 1; - } - else if (str.starts_with("*")) { - Token token = { .type = TokenType::Star, .pos = pos }; - tokens.emplace_back(token); - j += 1; - } - else if (str.starts_with("/")) { - Token token = { .type = TokenType::Slash, .pos = pos }; - tokens.emplace_back(token); - j += 1; - } - else if (str.starts_with("%")) { - Token token = { .type = TokenType::Percent, .pos = pos }; - tokens.emplace_back(token); - j += 1; - } - else if (str.starts_with("=")) { - Token token = { .type = TokenType::Equal, .pos = pos }; - tokens.emplace_back(token); - j += 1; - } - else if (str.starts_with(";")) { - Token token = { .type = TokenType::Semicolon, .pos = pos }; - tokens.emplace_back(token); - j += 1; - } - else if (str.starts_with("(")) { - Token token = { .type = TokenType::LParenthese, .pos = pos }; - tokens.emplace_back(token); - j += 1; - } - else if (str.starts_with(")")) { - Token token = { .type = TokenType::RParenthese, .pos = pos }; - tokens.emplace_back(token); - j += 1; - } - else if (str.starts_with("{")) { - Token token = { .type = TokenType::LCurlyBracket, .pos = pos }; - tokens.emplace_back(token); - j += 1; - } - else if (str.starts_with("}")) { - Token token = { .type = TokenType::RCurlyBracket, .pos = pos }; - tokens.emplace_back(token); - j += 1; - } - else if (regex_search(str, m, IDENTIFIER_REGEX, regex_constants::match_continuous)) { + if (matched) continue; + + if (regex_search(str, m, IDENTIFIER_REGEX, regex_constants::match_continuous)) { Token token = { .type = TokenType::Identifier, .data = m.str(), @@ -312,13 +223,15 @@ vector tokenize(vector input, int initial_line) { }; tokens.emplace_back(token); j += m.str().length(); + continue; } - else if (isspace(str[0])) { + + if (isspace(str[0])) { j += 1; + continue; } - else { - throw TokenError("Unknown token", pos); - } + + throw TokenError("Unknown token", pos); } } diff --git a/test/tokenize.cpp b/test/tokenize.cpp index 8eb2e4a..d9ed297 100644 --- a/test/tokenize.cpp +++ b/test/tokenize.cpp @@ -15,7 +15,7 @@ int main() { }; vector expectedTypes = { - TokenType::Type, TokenType::Identifier, TokenType::Equal, TokenType::Identifier, + TokenType::Identifier, TokenType::Identifier, TokenType::Equal, TokenType::Identifier, TokenType::DoublePlus, TokenType::DoubleMinus, TokenType::DoubleEqual, TokenType::Land, TokenType::Lor, TokenType::Lt, TokenType::Gt, TokenType::Leq, TokenType::Geq, TokenType::NotEqual, TokenType::Not, TokenType::Star, TokenType::Slash, TokenType::Percent, TokenType::Equal, @@ -42,12 +42,12 @@ int main() { ) _TEST_ASSERT( - _TEST_NO_EXCEPTION(tokens[0].type == TokenType::Type), - "Le premier token devrait être de type 'Type'", + _TEST_NO_EXCEPTION(tokens[0].type == TokenType::Identifier), + "Le premier token devrait être de type 'Identifier'", false ) _TEST_ASSERT( - _TEST_NO_EXCEPTION(get(tokens[0].data) == Type::Int), + _TEST_NO_EXCEPTION(get(tokens[0].data) == "int"), "Les données du premier token devraient être 'Int'", false ) @@ -93,8 +93,8 @@ int main() { ) _TEST_ASSERT( - _TEST_NO_EXCEPTION(tokens[6].type == TokenType::Int), - "Le premier token devrait être de type 'Int'", + _TEST_NO_EXCEPTION(tokens[6].type == TokenType::Litteral), + "Le premier token devrait être de type 'Litteral'", false ) _TEST_ASSERT(