✨ float arithmetic.
parent
d8be5d7b0f
commit
5cb141e4cf
|
@ -16,3 +16,4 @@ LITERAL ::=
|
|||
BUILTIN ::=
|
||||
| int
|
||||
| bool
|
||||
| float
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
224
lib/src/state.c
224
lib/src/state.c
|
@ -146,108 +146,276 @@ 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);
|
||||
|
||||
if (type == TYPE_INT)
|
||||
{
|
||||
return state_push_int(
|
||||
self,
|
||||
left->val.integer + right->val.integer,
|
||||
left->line
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
if (type == TYPE_INT)
|
||||
{
|
||||
return state_push_int(
|
||||
self,
|
||||
left->val.integer - right->val.integer,
|
||||
left->line
|
||||
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);
|
||||
|
||||
if (type == TYPE_INT)
|
||||
{
|
||||
return state_push_int(
|
||||
self,
|
||||
-left->val.integer,
|
||||
left->line
|
||||
-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)
|
||||
{
|
||||
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);
|
||||
|
||||
if (type == TYPE_INT)
|
||||
{
|
||||
return state_push_int(
|
||||
self,
|
||||
left->val.integer * right->val.integer,
|
||||
left->line
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
if (type == TYPE_INT)
|
||||
{
|
||||
return state_push_int(
|
||||
self,
|
||||
left->val.integer / right->val.integer,
|
||||
left->line
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
if (type == TYPE_INT)
|
||||
{
|
||||
return state_push_int(
|
||||
self,
|
||||
fmod(left->val.integer, right->val.integer),
|
||||
left->line
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
if (type == TYPE_INT)
|
||||
{
|
||||
return state_push_int(
|
||||
self,
|
||||
powf(left->val.integer, right->val.integer),
|
||||
left->line
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue