Add double type

This commit is contained in:
ala89 2023-12-08 09:04:05 +01:00
parent cfe02062a6
commit a1fa96a626
5 changed files with 191 additions and 192 deletions

View File

@ -11,10 +11,10 @@ using namespace std;
/** /**
* Tokens definition * 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 }; enum class Type { Int };
using TokenData = variant<int, string, Type>; using TokenData = variant<int, double, string, Type>;
struct CodePosition { struct CodePosition {
int line; int line;
@ -75,7 +75,7 @@ Unary ->
| ! Unary | ! Unary
Val -> Val ->
| Number | Litteral
| ++ParIdentifier | ++ParIdentifier
| --ParIdentifier | --ParIdentifier

View File

@ -18,6 +18,29 @@ bool bool_cast(EvalResult value) {
} }
} }
int int_cast(EvalResult value) {
if (holds_alternative<int>(value)) {
return get<int>(value);
} else if (holds_alternative<double>(value)) {
return int(get<double>(value));
}
else {
throw;
}
}
double double_cast(EvalResult value) {
if (holds_alternative<int>(value)) {
return double(get<int>(value));
}
else if (holds_alternative<double>(value)) {
return get<double>(value);
}
else {
throw;
}
}
EvalResult eval(Node &ast, Memory &memory) { EvalResult eval(Node &ast, Memory &memory) {
if (holds_alternative<InnerNode>(ast)) { if (holds_alternative<InnerNode>(ast)) {
InnerNode node = get<InnerNode>(ast); InnerNode node = get<InnerNode>(ast);
@ -30,7 +53,7 @@ EvalResult eval(Node &ast, Memory &memory) {
return {}; return {};
break; break;
case NodeType::If: { case NodeType::If: {
int cond = get<int>(eval(node.children[0], memory)); int cond = bool_cast(eval(node.children[0], memory));
if (cond) { if (cond) {
eval(node.children[1], memory); eval(node.children[1], memory);
@ -39,7 +62,7 @@ EvalResult eval(Node &ast, Memory &memory) {
return {}; return {};
} break; } break;
case NodeType::IfElse: { case NodeType::IfElse: {
int cond = get<int>(eval(node.children[0], memory)); int cond = bool_cast(eval(node.children[0], memory));
if (cond) { if (cond) {
eval(node.children[1], memory); eval(node.children[1], memory);
@ -52,7 +75,7 @@ EvalResult eval(Node &ast, Memory &memory) {
} break; } break;
case NodeType::While: { case NodeType::While: {
while (true) { while (true) {
int cond = get<int>(eval(node.children[0], memory)); int cond = bool_cast(eval(node.children[0], memory));
if (!cond) break; if (!cond) break;
eval(node.children[1], memory); eval(node.children[1], memory);
@ -66,7 +89,7 @@ EvalResult eval(Node &ast, Memory &memory) {
eval(node.children[0], memory); eval(node.children[0], memory);
while (true) { while (true) {
int cond = get<int>(eval(node.children[1], memory)); int cond = bool_cast(eval(node.children[1], memory));
if (!cond) break; if (!cond) break;
eval(node.children[3], memory); eval(node.children[3], memory);
@ -137,39 +160,95 @@ EvalResult eval(Node &ast, Memory &memory) {
return e1 >= e2; return e1 >= e2;
} break; } break;
case NodeType::Plus: { case NodeType::Plus: {
int e1 = get<int>(eval(node.children[0], memory)); EvalResult e1 = eval(node.children[0], memory);
int e2 = get<int>(eval(node.children[1], memory)); EvalResult e2 = eval(node.children[1], memory);
return e1 + e2;
if (holds_alternative<double>(e1) || holds_alternative<double>(e2)) {
double d1 = double_cast(e1);
double d2 = double_cast(e2);
return d1 + d2;
}
else {
int i1 = get<int>(e1);
int i2 = get<int>(e2);
return i1 + i2;
}
} break; } break;
case NodeType::Minus: { case NodeType::Minus: {
int e1 = get<int>(eval(node.children[0], memory)); EvalResult e1 = eval(node.children[0], memory);
int e2 = get<int>(eval(node.children[1], memory)); EvalResult e2 = eval(node.children[1], memory);
return e1 - e2;
if (holds_alternative<double>(e1) || holds_alternative<double>(e2)) {
double d1 = double_cast(e1);
double d2 = double_cast(e2);
return d1 - d2;
}
else {
int i1 = get<int>(e1);
int i2 = get<int>(e2);
return i1 - i2;
}
} break; } break;
case NodeType::Mult: { case NodeType::Mult: {
int e1 = get<int>(eval(node.children[0], memory)); EvalResult e1 = eval(node.children[0], memory);
int e2 = get<int>(eval(node.children[1], memory)); EvalResult e2 = eval(node.children[1], memory);
return e1 * e2;
if (holds_alternative<double>(e1) || holds_alternative<double>(e2)) {
double d1 = double_cast(e1);
double d2 = double_cast(e2);
return d1 * d2;
}
else {
int i1 = get<int>(e1);
int i2 = get<int>(e2);
return i1 * i2;
}
} break; } break;
case NodeType::Div: { case NodeType::Div: {
int e1 = get<int>(eval(node.children[0], memory)); EvalResult e1 = eval(node.children[0], memory);
int e2 = get<int>(eval(node.children[1], memory)); EvalResult e2 = eval(node.children[1], memory);
if (e2 == 0) throw RuntimeError("Division by 0", node.pos);
return e1 / e2; if (holds_alternative<double>(e1) || holds_alternative<double>(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<int>(e1);
int i2 = get<int>(e2);
if (i2 == 0) throw RuntimeError("Division by 0", node.pos);
return i1 / i2;
}
} break; } break;
case NodeType::Mod: { case NodeType::Mod: {
int e1 = get<int>(eval(node.children[0], memory)); EvalResult e1 = eval(node.children[0], memory);
int e2 = get<int>(eval(node.children[1], memory)); EvalResult e2 = eval(node.children[1], memory);
if (e2 == 0) throw RuntimeError("Modulo by 0", node.pos);
return e1 % e2; int i1 = get<int>(e1);
int i2 = get<int>(e2);
if (i2 == 0) throw RuntimeError("Modulo by 0", node.pos);
return i1 % i2;
} break; } break;
case NodeType::UnaryPlus: { case NodeType::UnaryPlus: {
int e1 = get<int>(eval(node.children[0], memory)); EvalResult e1 = eval(node.children[0], memory);
return +e1;
if (holds_alternative<int>(e1)) {
return +get<int>(e1);
}
else if (holds_alternative<double>(e1)) {
return +get<double>(e1);
}
} break; } break;
case NodeType::UnaryMinus: { case NodeType::UnaryMinus: {
int e1 = get<int>(eval(node.children[0], memory)); EvalResult e1 = eval(node.children[0], memory);
return -e1;
if (holds_alternative<int>(e1)) {
return -get<int>(e1);
}
else if (holds_alternative<double>(e1)) {
return -get<double>(e1);
}
} break; } break;
case NodeType::Declaration: { case NodeType::Declaration: {
Token typeTok = get<Token>(node.children[0]); Token typeTok = get<Token>(node.children[0]);
@ -284,8 +363,15 @@ EvalResult eval(Node &ast, Memory &memory) {
else { else {
Token token = get<Token>(ast); Token token = get<Token>(ast);
switch (token.type) { switch (token.type) {
case TokenType::Int: { case TokenType::Litteral: {
return get<int>(token.data); if (holds_alternative<int>(token.data)) {
return get<int>(token.data);
} else if (holds_alternative<double>(token.data)) {
return get<double>(token.data);
}
else {
throw;
}
} break; } break;
case TokenType::Identifier: { case TokenType::Identifier: {
string identifier = get<string>(token.data); string identifier = get<string>(token.data);

View File

@ -354,7 +354,7 @@ ParseReturn parse_statement(vector<Token> tokens) {
} }
ParseReturn parse_expr_statement(vector<Token> tokens) { ParseReturn parse_expr_statement(vector<Token> tokens) {
if (tokens.size() < 1 || tokens.back().type != TokenType::Type) if (tokens.size() < 1 || tokens.back().type != TokenType::Identifier)
throw ParseException(); throw ParseException();
Token type = tokens.back(); Token type = tokens.back();
@ -638,7 +638,7 @@ ParseReturn parse_val(vector<Token> tokens) {
throw ParseException(); throw ParseException();
switch (tokens.back().type) { switch (tokens.back().type) {
case TokenType::Int: { //* Val -> Number case TokenType::Litteral: { //* Val -> Number
Token number = tokens.back(); Token number = tokens.back();
tokens.pop_back(); tokens.pop_back();
return { return {

View File

@ -5,17 +5,43 @@
#include "include/tokenize.h" #include "include/tokenize.h"
using namespace std; using namespace std;
regex NUMBER_REGEX ("\\d+(\\.\\d+)?"); regex INT_REGEX ("\\d+");
regex TYPE_INT_REGEX ("int(\\s|$)"); regex DOUBLE_REGEX ("\\d+\\.\\d*|\\d*\\.\\d+");
regex IDENTIFIER_REGEX ("[A-Za-z_]\\w*"); regex IDENTIFIER_REGEX ("[A-Za-z_]\\w*");
vector<tuple<string, TokenType>> 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) { void _debug_print_token(Token token) {
switch (token.type) { switch (token.type) {
case TokenType::Type: case TokenType::Litteral:
cout << "Type(INT)"; cout << "Litteral(" << "tmp" << ")";
break;
case TokenType::Int:
cout << "Number(" << get<int>(token.data) << ")";
break; break;
case TokenType::Identifier: case TokenType::Identifier:
cout << "Identifier(" << get<string>(token.data) << ")"; cout << "Identifier(" << get<string>(token.data) << ")";
@ -103,9 +129,8 @@ void _debug_print_token(Token token) {
string _debug_print_token_type(TokenType type) { string _debug_print_token_type(TokenType type) {
switch (type) { switch (type) {
case TokenType::Type: return "Type";
case TokenType::Identifier: return "Identifier"; case TokenType::Identifier: return "Identifier";
case TokenType::Int: return "Int"; case TokenType::Litteral: return "Litteral";
case TokenType::Plus: return "Plus"; case TokenType::Plus: return "Plus";
case TokenType::Minus: return "Minus"; case TokenType::Minus: return "Minus";
case TokenType::DoublePlus: return "DoublePlus"; case TokenType::DoublePlus: return "DoublePlus";
@ -156,155 +181,41 @@ vector<Token> tokenize(vector<string> input, int initial_line) {
string str = line.substr(j, string::npos); string str = line.substr(j, string::npos);
smatch m; 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 = { 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()), .data = stoi(m.str()),
.pos = pos .pos = pos
}; };
tokens.emplace_back(token); tokens.emplace_back(token);
j += m.str().length(); j += m.str().length();
continue;
} }
else if (regex_search(str, m, TYPE_INT_REGEX, regex_constants::match_continuous)) {
Token token = { bool matched = false;
.type = TokenType::Type, for (auto simpleToken: simpleTokens) {
.data = Type::Int, if (str.starts_with(get<0>(simpleToken))) {
.pos = pos Token token = { .type = get<1>(simpleToken), .pos = pos };
}; tokens.emplace_back(token);
tokens.emplace_back(token); j += get<0>(simpleToken).length();
j += m.str().length(); matched = true;
break;
}
} }
else if (str.starts_with("if")) { if (matched) continue;
Token token = { .type = TokenType::If, .pos = pos };
tokens.emplace_back(token); if (regex_search(str, m, IDENTIFIER_REGEX, regex_constants::match_continuous)) {
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)) {
Token token = { Token token = {
.type = TokenType::Identifier, .type = TokenType::Identifier,
.data = m.str(), .data = m.str(),
@ -312,13 +223,15 @@ vector<Token> tokenize(vector<string> input, int initial_line) {
}; };
tokens.emplace_back(token); tokens.emplace_back(token);
j += m.str().length(); j += m.str().length();
continue;
} }
else if (isspace(str[0])) {
if (isspace(str[0])) {
j += 1; j += 1;
continue;
} }
else {
throw TokenError("Unknown token", pos); throw TokenError("Unknown token", pos);
}
} }
} }

View File

@ -15,7 +15,7 @@ int main() {
}; };
vector<TokenType> expectedTypes = { vector<TokenType> 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::DoublePlus, TokenType::DoubleMinus, TokenType::DoubleEqual, TokenType::Land,
TokenType::Lor, TokenType::Lt, TokenType::Gt, TokenType::Leq, TokenType::Geq, TokenType::NotEqual, TokenType::Lor, TokenType::Lt, TokenType::Gt, TokenType::Leq, TokenType::Geq, TokenType::NotEqual,
TokenType::Not, TokenType::Star, TokenType::Slash, TokenType::Percent, TokenType::Equal, TokenType::Not, TokenType::Star, TokenType::Slash, TokenType::Percent, TokenType::Equal,
@ -42,12 +42,12 @@ int main() {
) )
_TEST_ASSERT( _TEST_ASSERT(
_TEST_NO_EXCEPTION(tokens[0].type == TokenType::Type), _TEST_NO_EXCEPTION(tokens[0].type == TokenType::Identifier),
"Le premier token devrait être de type 'Type'", "Le premier token devrait être de type 'Identifier'",
false false
) )
_TEST_ASSERT( _TEST_ASSERT(
_TEST_NO_EXCEPTION(get<Type>(tokens[0].data) == Type::Int), _TEST_NO_EXCEPTION(get<string>(tokens[0].data) == "int"),
"Les données du premier token devraient être 'Int'", "Les données du premier token devraient être 'Int'",
false false
) )
@ -93,8 +93,8 @@ int main() {
) )
_TEST_ASSERT( _TEST_ASSERT(
_TEST_NO_EXCEPTION(tokens[6].type == TokenType::Int), _TEST_NO_EXCEPTION(tokens[6].type == TokenType::Litteral),
"Le premier token devrait être de type 'Int'", "Le premier token devrait être de type 'Litteral'",
false false
) )
_TEST_ASSERT( _TEST_ASSERT(