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
*/
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<int, string, Type>;
using TokenData = variant<int, double, string, Type>;
struct CodePosition {
int line;
@ -75,7 +75,7 @@ Unary ->
| ! Unary
Val ->
| Number
| Litteral
| ++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) {
if (holds_alternative<InnerNode>(ast)) {
InnerNode node = get<InnerNode>(ast);
@ -30,7 +53,7 @@ EvalResult eval(Node &ast, Memory &memory) {
return {};
break;
case NodeType::If: {
int cond = get<int>(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<int>(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<int>(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<int>(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<int>(eval(node.children[0], memory));
int e2 = get<int>(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<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;
case NodeType::Minus: {
int e1 = get<int>(eval(node.children[0], memory));
int e2 = get<int>(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<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;
case NodeType::Mult: {
int e1 = get<int>(eval(node.children[0], memory));
int e2 = get<int>(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<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;
case NodeType::Div: {
int e1 = get<int>(eval(node.children[0], memory));
int e2 = get<int>(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<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;
case NodeType::Mod: {
int e1 = get<int>(eval(node.children[0], memory));
int e2 = get<int>(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<int>(e1);
int i2 = get<int>(e2);
if (i2 == 0) throw RuntimeError("Modulo by 0", node.pos);
return i1 % i2;
} break;
case NodeType::UnaryPlus: {
int e1 = get<int>(eval(node.children[0], memory));
return +e1;
EvalResult e1 = eval(node.children[0], memory);
if (holds_alternative<int>(e1)) {
return +get<int>(e1);
}
else if (holds_alternative<double>(e1)) {
return +get<double>(e1);
}
} break;
case NodeType::UnaryMinus: {
int e1 = get<int>(eval(node.children[0], memory));
return -e1;
EvalResult e1 = eval(node.children[0], memory);
if (holds_alternative<int>(e1)) {
return -get<int>(e1);
}
else if (holds_alternative<double>(e1)) {
return -get<double>(e1);
}
} break;
case NodeType::Declaration: {
Token typeTok = get<Token>(node.children[0]);
@ -284,8 +363,15 @@ EvalResult eval(Node &ast, Memory &memory) {
else {
Token token = get<Token>(ast);
switch (token.type) {
case TokenType::Int: {
case TokenType::Litteral: {
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;
case TokenType::Identifier: {
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) {
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<Token> 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 {

View File

@ -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<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) {
switch (token.type) {
case TokenType::Type:
cout << "Type(INT)";
break;
case TokenType::Int:
cout << "Number(" << get<int>(token.data) << ")";
case TokenType::Litteral:
cout << "Litteral(" << "tmp" << ")";
break;
case TokenType::Identifier:
cout << "Identifier(" << get<string>(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<Token> tokenize(vector<string> 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
};
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 += m.str().length();
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,15 +223,17 @@ vector<Token> tokenize(vector<string> 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);
}
}
}
return tokens;
}

View File

@ -15,7 +15,7 @@ int main() {
};
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::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<Type>(tokens[0].data) == Type::Int),
_TEST_NO_EXCEPTION(get<string>(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(