float arithmetic.

main
bog 2024-04-01 21:08:42 +02:00
parent d8be5d7b0f
commit 5cb141e4cf
14 changed files with 372 additions and 54 deletions

View File

@ -16,3 +16,4 @@ LITERAL ::=
BUILTIN ::=
| int
| bool
| float

10
features/float.sk Normal file
View File

@ -0,0 +1,10 @@
assert 6.200 eq 6.2
assert 5.2 + 1.2 eq 6.4
assert 5.2 - 1.2 eq 4.0
assert 5.2 * 1.2 eq 6.24
assert 5.2 / 2.0 eq 2.6
assert 12.0 % 2.5 eq 2.0
assert 25.0 ^ 0.5 eq 5.0
assert 1 + 1.0 eq 2.0
assert 3.0 * 2 eq 6.0

View File

@ -30,6 +30,7 @@ bool lexer_next_is(struct lexer* self, TokenKind kind);
void lexer_consume_next(struct lexer* self);
struct token* lexer_try_new_next(struct lexer* self);
struct token* lexer_try_scan_int(struct lexer* self);
struct token* lexer_try_scan_float(struct lexer* self);
struct token* lexer_try_scan_text(struct lexer* self,
char const* text,
TokenKind kind);

View File

@ -10,7 +10,7 @@ G(NODE_ADD), G(NODE_SUB), G(NODE_MUL),\
G(NODE_DIV), G(NODE_POW), G(NODE_MOD),\
G(NODE_USUB), G(NODE_ASSERT_EQ), \
G(NODE_BOOL), G(NODE_AND), G(NODE_OR), \
G(NODE_NOT)
G(NODE_NOT), G(NODE_FLOAT)
SK_ENUM_H(NodeKind, NODE_KIND);

View File

@ -51,6 +51,11 @@ SK state_push(struct state* self,
SK state_push_int(struct state* self, int integer, int line);
SK state_push_bool(struct state* self, bool boolean, int line);
SK state_push_float(struct state* self, double real, int line);
TypeKind state_common_num_type(struct state* self, SK lhs, SK rhs);
double state_as_real(struct state* self, SK lhs);
int state_line(struct state* self, SK lhs);
SK state_add(struct state* self);
SK state_sub(struct state* self);

View File

@ -11,7 +11,7 @@ G(TOKEN_MUL), G(TOKEN_DIV), G(TOKEN_MOD), \
G(TOKEN_POW), G(TOKEN_OPAR), G(TOKEN_CPAR), \
G(TOKEN_ASSERT), G(TOKEN_ASSERT_EQ), \
G(TOKEN_BOOL), G(TOKEN_AND), G(TOKEN_OR), \
G(TOKEN_NOT)
G(TOKEN_NOT), G(TOKEN_FLOAT)
SK_ENUM_H(TokenKind, TOKEN_KIND);

View File

@ -5,13 +5,14 @@
#include "node.h"
#define TYPE_KIND(G) \
G(TYPE_INT), G(TYPE_BOOL)
G(TYPE_INT), G(TYPE_BOOL), G(TYPE_FLOAT)
SK_ENUM_H(TypeKind, TYPE_KIND);
union val
{
int integer;
double real;
bool boolean;
};

View File

@ -62,6 +62,13 @@ void compiler_compile(struct compiler* self,
val);
} break;
case NODE_FLOAT: {
union val val;
val.real = atof(node->token->value);
compiler_compile_value(self, node, prog, TYPE_FLOAT,
val);
} break;
case NODE_ADD: {
compiler_compile_children(self, node, prog);
prog_add_instr(prog, OP_ADD, SK_NO_PARAM);

View File

@ -74,6 +74,14 @@ void exec_execute(struct exec* self,
);
} break;
case TYPE_FLOAT: {
state_push_float(
state,
constant->val.real,
constant->line
);
} break;
case TYPE_BOOL: {
state_push_bool(
state,

View File

@ -133,6 +133,11 @@ struct token* lexer_try_new_next(struct lexer* self)
struct token* tok = NULL;
if ( (tok=lexer_try_scan_float(self)) )
{
return tok;
}
if ( (tok=lexer_try_scan_int(self)) )
{
return tok;
@ -212,6 +217,60 @@ struct token* lexer_try_scan_int(struct lexer* self)
return tok;
}
struct token* lexer_try_scan_float(struct lexer* self)
{
assert(self);
size_t cursor = self->context.cursor;
struct str value;
str_init(&value);
if (cursor < self->len
&& self->source[cursor] == '-')
{
str_push(&value, self->source[cursor]);
cursor++;
}
while (cursor < self->len
&& isdigit(self->source[cursor]))
{
str_push(&value, self->source[cursor]);
cursor++;
}
if (cursor >= self->len
|| self->source[cursor] != '.')
{
str_free(&value);
return NULL;
}
str_push(&value, self->source[cursor]);
cursor++;
while (cursor < self->len
&& isdigit(self->source[cursor]))
{
str_push(&value, self->source[cursor]);
cursor++;
}
struct token* tok = NULL;
if (value.size > 0
&& (value.value[0] != '-' || value.size > 1))
{
tok = malloc(sizeof(struct token));
token_init(tok, TOKEN_FLOAT,
value.value, self->context.line);
self->context.cursor = cursor;
}
str_free(&value);
return tok;
}
struct token* lexer_try_scan_text(struct lexer* self,
char const* text,
TokenKind kind)

View File

@ -50,18 +50,40 @@ struct node* parser_try_root(struct parser* self)
node_init(node, NODE_ROOT, tok);
struct str error_str;
str_init(&error_str);
while (!lexer_is_at_end(&self->lexer))
{
struct node* expr = SK_TRY(parser_try_expr);
if (!expr)
{
while (self->lexer.context.cursor < self->lexer.len
&& !lexer_is_sep(&self->lexer,
self->lexer.context.cursor))
{
str_push(&error_str,
self->lexer.source[
self->lexer.context.cursor
]);
self->lexer.context.cursor++;
}
break;
}
node_push_new_child(node, expr);
}
if (self->lexer.context.cursor < self->lexer.len)
{
errors_push(self->lexer.context.line, "unexpected end");
errors_push(self->lexer.context.line,
"unexpected end near '%s'",
error_str.value);
}
str_free(&error_str);
return node;
}
@ -87,12 +109,19 @@ struct node* parser_try_assert(struct parser* self)
struct token* tok = lexer_try_new_next(&self->lexer);
struct node* lhs = SK_TRY(parser_try_expr);
if (!lhs) { return NULL; }
if (!lhs)
{
token_free(tok); free(tok);
return NULL;
}
if (!lexer_next_is(&self->lexer, TOKEN_ASSERT_EQ))
{
token_free(tok);
free(tok);
node_free(lhs);
free(lhs);
return NULL;
}
@ -102,6 +131,8 @@ struct node* parser_try_assert(struct parser* self)
{
token_free(tok);
free(tok);
node_free(lhs);
free(lhs);
return NULL;
}
@ -398,5 +429,16 @@ struct node* parser_try_builtin(struct parser* self)
return node;
}
if (lexer_next_is(&self->lexer, TOKEN_FLOAT))
{
struct node* node = malloc(sizeof(struct node));
node_init(node,
NODE_FLOAT,
lexer_try_new_next(&self->lexer));
return node;
}
return NULL;
}

View File

@ -146,19 +146,86 @@ SK state_push_bool(struct state* self, bool boolean, int line)
return state_push(self, TYPE_BOOL, val, line);
}
SK state_push_float(struct state* self, double real, int line)
{
assert(self);
union val val;
val.real = real;
return state_push(self, TYPE_FLOAT, val ,line);
}
TypeKind state_common_num_type(struct state* self, SK lhs, SK rhs)
{
assert(self);
struct value const* left = state_try_get_value(self, lhs);
struct value const* right = state_try_get_value(self, rhs);
if (left->type == TYPE_FLOAT
|| right->type == TYPE_FLOAT)
{
return TYPE_FLOAT;
}
return TYPE_INT;
}
double state_as_real(struct state* self, SK lhs)
{
assert(self);
struct value* value = state_try_get_value(self, lhs);
if (value->type == TYPE_INT)
{
return value->val.integer;
}
else if (value->type == TYPE_FLOAT)
{
return value->val.real;
}
errors_push(value->line, "expected a number, got '%s'",
TypeKindStr[value->type] + strlen("TYPE_"));
return 0.0;
}
int state_line(struct state* self, SK lhs)
{
assert(self);
struct value const* value = state_try_get_value(self, lhs);
return value->line;
}
SK state_add(struct state* self)
{
SK rhs = state_pop(self);
SK lhs = state_pop(self);
struct value* left = state_try_get_value(self, lhs);
struct value* right = state_try_get_value(self, rhs);
TypeKind type = state_common_num_type(self, lhs, rhs);
return state_push_int(
self,
left->val.integer + right->val.integer,
left->line
);
if (type == TYPE_INT)
{
return state_push_int(
self,
state_as_real(self, lhs) + state_as_real(self, rhs),
state_line(self, lhs)
);
}
else if (type == TYPE_FLOAT)
{
return state_push_float(
self,
state_as_real(self, lhs) + state_as_real(self, rhs),
state_line(self, lhs)
);
}
else
{
errors_push(state_line(self, lhs),
"cannot addition");
return 0;
}
}
SK state_sub(struct state* self)
@ -166,27 +233,60 @@ SK state_sub(struct state* self)
SK rhs = state_pop(self);
SK lhs = state_pop(self);
struct value* left = state_try_get_value(self, lhs);
struct value* right = state_try_get_value(self, rhs);
TypeKind type = state_common_num_type(self, lhs, rhs);
return state_push_int(
self,
left->val.integer - right->val.integer,
left->line
);
if (type == TYPE_INT)
{
return state_push_int(
self,
state_as_real(self, lhs) - state_as_real(self, rhs),
state_line(self, lhs)
);
}
else if (type == TYPE_FLOAT)
{
return state_push_float(
self,
state_as_real(self, lhs) - state_as_real(self, rhs),
state_line(self, lhs)
);
}
else
{
errors_push(state_line(self, lhs),
"cannot substract");
return 0;
}
}
SK state_usub(struct state* self)
{
SK lhs = state_pop(self);
struct value const* value = state_try_get_value(self, lhs);
TypeKind type = value->type;
struct value* left = state_try_get_value(self, lhs);
return state_push_int(
self,
-left->val.integer,
left->line
);
if (type == TYPE_INT)
{
return state_push_int(
self,
-state_as_real(self, lhs),
state_line(self, lhs)
);
}
else if (type == TYPE_FLOAT)
{
return state_push_float(
self,
-state_as_real(self, lhs),
state_line(self, lhs)
);
}
else
{
errors_push(state_line(self, lhs),
"cannot apply unary substraction");
return 0;
}
}
SK state_mul(struct state* self)
@ -194,14 +294,30 @@ SK state_mul(struct state* self)
SK rhs = state_pop(self);
SK lhs = state_pop(self);
struct value* left = state_try_get_value(self, lhs);
struct value* right = state_try_get_value(self, rhs);
TypeKind type = state_common_num_type(self, lhs, rhs);
return state_push_int(
self,
left->val.integer * right->val.integer,
left->line
);
if (type == TYPE_INT)
{
return state_push_int(
self,
state_as_real(self, lhs) * state_as_real(self, rhs),
state_line(self, lhs)
);
}
else if (type == TYPE_FLOAT)
{
return state_push_float(
self,
state_as_real(self, lhs) * state_as_real(self, rhs),
state_line(self, lhs)
);
}
else
{
errors_push(state_line(self, lhs),
"cannot multiply");
return 0;
}
}
SK state_div(struct state* self)
@ -209,14 +325,30 @@ SK state_div(struct state* self)
SK rhs = state_pop(self);
SK lhs = state_pop(self);
struct value* left = state_try_get_value(self, lhs);
struct value* right = state_try_get_value(self, rhs);
TypeKind type = state_common_num_type(self, lhs, rhs);
return state_push_int(
self,
left->val.integer / right->val.integer,
left->line
);
if (type == TYPE_INT)
{
return state_push_int(
self,
state_as_real(self, lhs) / state_as_real(self, rhs),
state_line(self, lhs)
);
}
else if (type == TYPE_FLOAT)
{
return state_push_float(
self,
state_as_real(self, lhs) / state_as_real(self, rhs),
state_line(self, lhs)
);
}
else
{
errors_push(state_line(self, lhs),
"cannot divide");
return 0;
}
}
SK state_mod(struct state* self)
@ -224,14 +356,32 @@ SK state_mod(struct state* self)
SK rhs = state_pop(self);
SK lhs = state_pop(self);
struct value* left = state_try_get_value(self, lhs);
struct value* right = state_try_get_value(self, rhs);
TypeKind type = state_common_num_type(self, lhs, rhs);
return state_push_int(
self,
fmod(left->val.integer, right->val.integer),
left->line
);
if (type == TYPE_INT)
{
return state_push_int(
self,
fmod(state_as_real(self, lhs),
state_as_real(self, rhs)),
state_line(self, lhs)
);
}
else if (type == TYPE_FLOAT)
{
return state_push_float(
self,
fmod(state_as_real(self, lhs),
state_as_real(self, rhs)),
state_line(self, lhs)
);
}
else
{
errors_push(state_line(self, lhs),
"cannot apply mod");
return 0;
}
}
SK state_pow(struct state* self)
@ -239,14 +389,32 @@ SK state_pow(struct state* self)
SK rhs = state_pop(self);
SK lhs = state_pop(self);
struct value* left = state_try_get_value(self, lhs);
struct value* right = state_try_get_value(self, rhs);
TypeKind type = state_common_num_type(self, lhs, rhs);
return state_push_int(
self,
powf(left->val.integer, right->val.integer),
left->line
);
if (type == TYPE_INT)
{
return state_push_int(
self,
powf(state_as_real(self, lhs),
state_as_real(self, rhs)),
state_line(self, lhs)
);
}
else if (type == TYPE_FLOAT)
{
return state_push_float(
self,
powf(state_as_real(self, lhs),
state_as_real(self, rhs)),
state_line(self, lhs)
);
}
else
{
errors_push(state_line(self, lhs),
"cannot apply pow");
return 0;
}
}
SK state_and(struct state* self)

View File

@ -47,6 +47,10 @@ void value_str(struct value* self, struct str* dest)
str_format(dest, "%d", self->val.integer);
} break;
case TYPE_FLOAT: {
str_format(dest, "%f", self->val.real);
} break;
case TYPE_BOOL: {
str_format(dest, "%s",
self->val.boolean ? "true" : "false");

View File

@ -70,12 +70,24 @@ static void test_lexer_bool()
"NOT"
);
}
static void test_lexer_float()
{
test_lexer(".4 7. 2.3 -6.12", 4,
"FLOAT[.4]",
"FLOAT[7.]",
"FLOAT[2.3]",
"FLOAT[-6.12]"
);
}
void register_lexer()
{
CU_pSuite suite = CU_add_suite("Lexer", 0, 0);
CU_add_test(suite, "Integers", test_lexer_int);
CU_add_test(suite, "Assertions", test_lexer_assert);
CU_add_test(suite, "Booleans", test_lexer_bool);
CU_add_test(suite, "Floats", test_lexer_float);
}
#endif