Compare commits
No commits in common. "e7e0789cbb98fa793da8af13b19ea1feda33e594" and "e8b10498cf7b499097359fc03601e5a999b2724f" have entirely different histories.
e7e0789cbb
...
e8b10498cf
|
@ -1,20 +1,14 @@
|
||||||
ROOT ::= EXPR*
|
ROOT ::= EXPR*
|
||||||
EXPR ::=
|
EXPR ::=
|
||||||
| OR
|
| TERM
|
||||||
| ASSERT
|
| ASSERT
|
||||||
ASSERT ::= assert EXPR eq EXPR
|
ASSERT ::= assert EXPR eq EXPR
|
||||||
OR ::= AND (or AND)*
|
|
||||||
AND ::= TERM (and TERM)*
|
|
||||||
TERM ::= FACTOR ((add|sub) FACTOR)*
|
TERM ::= FACTOR ((add|sub) FACTOR)*
|
||||||
FACTOR ::= USUB ((mul|div|mod) USUB)*
|
FACTOR ::= USUB ((mul|div|mod) USUB)*
|
||||||
USUB ::= sub* NOT
|
USUB ::= sub* POW
|
||||||
NOT ::= not* POW
|
|
||||||
POW ::= LITERAL (pow LITERAL)?
|
POW ::= LITERAL (pow LITERAL)?
|
||||||
LITERAL ::=
|
LITERAL ::=
|
||||||
| BUILTIN
|
| BUILTIN
|
||||||
| opar EXPR cpar
|
| opar EXPR cpar
|
||||||
BUILTIN ::=
|
BUILTIN ::=
|
||||||
| int
|
| int
|
||||||
| bool
|
|
||||||
| float
|
|
||||||
| string
|
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
assert true eq true
|
|
||||||
assert false eq false
|
|
||||||
|
|
||||||
assert not true eq false
|
|
||||||
assert not false eq true
|
|
||||||
|
|
||||||
assert true and true eq true
|
|
||||||
assert true and false eq false
|
|
||||||
assert false and true eq false
|
|
||||||
assert false and false eq false
|
|
||||||
|
|
||||||
assert true or true eq true
|
|
||||||
assert true or false eq true
|
|
||||||
assert false or true eq true
|
|
||||||
assert false or false eq false
|
|
|
@ -1,10 +0,0 @@
|
||||||
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
|
|
|
@ -1,8 +0,0 @@
|
||||||
assert "hello" eq "hello"
|
|
||||||
|
|
||||||
assert "hello " + "world" eq "hello world"
|
|
||||||
assert "a" + "b" + "c" eq "abc"
|
|
||||||
|
|
||||||
assert "a" * 3 eq "aaa"
|
|
||||||
assert 4 * "b" eq "bbbb"
|
|
||||||
assert ("a" + "b") * 2 eq "abab"
|
|
|
@ -18,19 +18,5 @@ void compiler_compile(struct compiler* self,
|
||||||
void compiler_compile_children(struct compiler* self,
|
void compiler_compile_children(struct compiler* self,
|
||||||
struct node* node,
|
struct node* node,
|
||||||
struct prog* prog);
|
struct prog* prog);
|
||||||
|
|
||||||
void compiler_compile_value(struct compiler* self,
|
|
||||||
struct node* node,
|
|
||||||
struct prog* prog,
|
|
||||||
TypeKind type,
|
|
||||||
union val val);
|
|
||||||
|
|
||||||
void compiler_compile_and(struct compiler* self,
|
|
||||||
struct node* node,
|
|
||||||
struct prog* prog);
|
|
||||||
|
|
||||||
void compiler_compile_or(struct compiler* self,
|
|
||||||
struct node* node,
|
|
||||||
struct prog* prog);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -20,9 +20,7 @@ struct lexer
|
||||||
void lexer_init(struct lexer* self, char const* source);
|
void lexer_init(struct lexer* self, char const* source);
|
||||||
void lexer_free(struct lexer* self);
|
void lexer_free(struct lexer* self);
|
||||||
|
|
||||||
bool lexer_is_at_end(struct lexer* self);
|
|
||||||
void lexer_skip_spaces(struct lexer* self);
|
void lexer_skip_spaces(struct lexer* self);
|
||||||
void lexer_skip_comments(struct lexer* self);
|
|
||||||
bool lexer_is_sep(struct lexer* self, size_t index);
|
bool lexer_is_sep(struct lexer* self, size_t index);
|
||||||
|
|
||||||
bool lexer_next_is(struct lexer* self, TokenKind kind);
|
bool lexer_next_is(struct lexer* self, TokenKind kind);
|
||||||
|
@ -30,8 +28,6 @@ bool lexer_next_is(struct lexer* self, TokenKind kind);
|
||||||
void lexer_consume_next(struct lexer* self);
|
void lexer_consume_next(struct lexer* self);
|
||||||
struct token* lexer_try_new_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_int(struct lexer* self);
|
||||||
struct token* lexer_try_scan_float(struct lexer* self);
|
|
||||||
struct token* lexer_try_scan_string(struct lexer* self);
|
|
||||||
struct token* lexer_try_scan_text(struct lexer* self,
|
struct token* lexer_try_scan_text(struct lexer* self,
|
||||||
char const* text,
|
char const* text,
|
||||||
TokenKind kind);
|
TokenKind kind);
|
||||||
|
|
|
@ -8,9 +8,7 @@ G(NODE_ROOT), \
|
||||||
G(NODE_INT), \
|
G(NODE_INT), \
|
||||||
G(NODE_ADD), G(NODE_SUB), G(NODE_MUL),\
|
G(NODE_ADD), G(NODE_SUB), G(NODE_MUL),\
|
||||||
G(NODE_DIV), G(NODE_POW), G(NODE_MOD),\
|
G(NODE_DIV), G(NODE_POW), G(NODE_MOD),\
|
||||||
G(NODE_USUB), G(NODE_ASSERT_EQ), \
|
G(NODE_USUB), G(NODE_ASSERT_EQ)
|
||||||
G(NODE_BOOL), G(NODE_AND), G(NODE_OR), \
|
|
||||||
G(NODE_NOT), G(NODE_FLOAT), G(NODE_STRING)
|
|
||||||
|
|
||||||
SK_ENUM_H(NodeKind, NODE_KIND);
|
SK_ENUM_H(NodeKind, NODE_KIND);
|
||||||
|
|
||||||
|
|
|
@ -20,12 +20,9 @@ struct node* parser_try_parse(struct parser* self);
|
||||||
struct node* parser_try_root(struct parser* self);
|
struct node* parser_try_root(struct parser* self);
|
||||||
struct node* parser_try_expr(struct parser* self);
|
struct node* parser_try_expr(struct parser* self);
|
||||||
struct node* parser_try_assert(struct parser* self);
|
struct node* parser_try_assert(struct parser* self);
|
||||||
struct node* parser_try_or(struct parser* self);
|
|
||||||
struct node* parser_try_and(struct parser* self);
|
|
||||||
struct node* parser_try_term(struct parser* self);
|
struct node* parser_try_term(struct parser* self);
|
||||||
struct node* parser_try_factor(struct parser* self);
|
struct node* parser_try_factor(struct parser* self);
|
||||||
struct node* parser_try_usub(struct parser* self);
|
struct node* parser_try_usub(struct parser* self);
|
||||||
struct node* parser_try_not(struct parser* self);
|
|
||||||
struct node* parser_try_pow(struct parser* self);
|
struct node* parser_try_pow(struct parser* self);
|
||||||
struct node* parser_try_literal(struct parser* self);
|
struct node* parser_try_literal(struct parser* self);
|
||||||
struct node* parser_try_builtin(struct parser* self);
|
struct node* parser_try_builtin(struct parser* self);
|
||||||
|
|
|
@ -9,9 +9,7 @@
|
||||||
G(OP_PUSH), \
|
G(OP_PUSH), \
|
||||||
G(OP_ADD), G(OP_SUB), G(OP_MUL), \
|
G(OP_ADD), G(OP_SUB), G(OP_MUL), \
|
||||||
G(OP_DIV), G(OP_MOD), G(OP_POW), \
|
G(OP_DIV), G(OP_MOD), G(OP_POW), \
|
||||||
G(OP_USUB), G(OP_ASSERT_EQ), \
|
G(OP_USUB), G(OP_ASSERT_EQ)
|
||||||
G(OP_NOT), G(OP_AND), G(OP_OR), \
|
|
||||||
G(OP_BR), G(OP_BRF)
|
|
||||||
|
|
||||||
SK_ENUM_H(Opcode, OPCODE);
|
SK_ENUM_H(Opcode, OPCODE);
|
||||||
|
|
||||||
|
|
|
@ -44,20 +44,7 @@ struct value* state_try_get_value(struct state* self, SK value);
|
||||||
|
|
||||||
SK state_pop(struct state* self);
|
SK state_pop(struct state* self);
|
||||||
|
|
||||||
SK state_push(struct state* self,
|
|
||||||
TypeKind type,
|
|
||||||
union val val,
|
|
||||||
int line);
|
|
||||||
|
|
||||||
SK state_push_int(struct state* self, int integer, int line);
|
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);
|
|
||||||
SK state_push_string(struct state* self, char const* str, int line);
|
|
||||||
|
|
||||||
TypeKind state_common_num_type(struct state* self, SK lhs, SK rhs);
|
|
||||||
TypeKind state_type(struct state* self, SK value);
|
|
||||||
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_add(struct state* self);
|
||||||
SK state_sub(struct state* self);
|
SK state_sub(struct state* self);
|
||||||
|
@ -67,8 +54,4 @@ SK state_div(struct state* self);
|
||||||
SK state_mod(struct state* self);
|
SK state_mod(struct state* self);
|
||||||
SK state_pow(struct state* self);
|
SK state_pow(struct state* self);
|
||||||
|
|
||||||
SK state_and(struct state* self);
|
|
||||||
SK state_or(struct state* self);
|
|
||||||
SK state_not(struct state* self);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -9,9 +9,7 @@ G(TOKEN_INT), \
|
||||||
G(TOKEN_ADD), G(TOKEN_SUB), \
|
G(TOKEN_ADD), G(TOKEN_SUB), \
|
||||||
G(TOKEN_MUL), G(TOKEN_DIV), G(TOKEN_MOD), \
|
G(TOKEN_MUL), G(TOKEN_DIV), G(TOKEN_MOD), \
|
||||||
G(TOKEN_POW), G(TOKEN_OPAR), G(TOKEN_CPAR), \
|
G(TOKEN_POW), G(TOKEN_OPAR), G(TOKEN_CPAR), \
|
||||||
G(TOKEN_ASSERT), G(TOKEN_ASSERT_EQ), \
|
G(TOKEN_ASSERT), G(TOKEN_ASSERT_EQ)
|
||||||
G(TOKEN_BOOL), G(TOKEN_AND), G(TOKEN_OR), \
|
|
||||||
G(TOKEN_NOT), G(TOKEN_FLOAT), G(TOKEN_STRING)
|
|
||||||
|
|
||||||
SK_ENUM_H(TokenKind, TOKEN_KIND);
|
SK_ENUM_H(TokenKind, TOKEN_KIND);
|
||||||
|
|
||||||
|
|
|
@ -5,17 +5,13 @@
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
|
||||||
#define TYPE_KIND(G) \
|
#define TYPE_KIND(G) \
|
||||||
G(TYPE_INT), G(TYPE_BOOL), G(TYPE_FLOAT), \
|
G(TYPE_INT)
|
||||||
G(TYPE_STRING)
|
|
||||||
|
|
||||||
SK_ENUM_H(TypeKind, TYPE_KIND);
|
SK_ENUM_H(TypeKind, TYPE_KIND);
|
||||||
|
|
||||||
union val
|
union val
|
||||||
{
|
{
|
||||||
int integer;
|
int integer;
|
||||||
double real;
|
|
||||||
bool boolean;
|
|
||||||
char* str;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct value
|
struct value
|
||||||
|
|
|
@ -29,51 +29,19 @@ void compiler_compile(struct compiler* self,
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_NOT: {
|
|
||||||
compiler_compile_children(self, node, prog);
|
|
||||||
prog_add_instr(prog, OP_NOT, SK_NO_PARAM);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_AND: {
|
|
||||||
compiler_compile_and(self, node, prog);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_OR: {
|
|
||||||
compiler_compile_or(self, node, prog);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_ASSERT_EQ: {
|
case NODE_ASSERT_EQ: {
|
||||||
compiler_compile_children(self, node, prog);
|
compiler_compile_children(self, node, prog);
|
||||||
prog_add_instr(prog, OP_ASSERT_EQ, SK_NO_PARAM);
|
prog_add_instr(prog, OP_ASSERT_EQ, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_BOOL: {
|
|
||||||
union val val;
|
|
||||||
val.boolean =
|
|
||||||
strcmp(node->token->value, "true") == 0;
|
|
||||||
compiler_compile_value(self, node, prog, TYPE_BOOL,
|
|
||||||
val);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_INT: {
|
case NODE_INT: {
|
||||||
|
struct value* value = malloc(sizeof(struct value));
|
||||||
union val val;
|
union val val;
|
||||||
val.integer = atoi(node->token->value);
|
val.integer = atoi(node->token->value);
|
||||||
compiler_compile_value(self, node, prog, TYPE_INT,
|
value_init(value, TYPE_INT, val, node->token->line);
|
||||||
val);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_FLOAT: {
|
size_t idx = prog_add_constant(prog, value);
|
||||||
union val val;
|
prog_add_instr(prog, OP_PUSH, idx);
|
||||||
val.real = atof(node->token->value);
|
|
||||||
compiler_compile_value(self, node, prog, TYPE_FLOAT,
|
|
||||||
val);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NODE_STRING: {
|
|
||||||
union val val;
|
|
||||||
val.str = strdup(node->token->value);
|
|
||||||
compiler_compile_value(self, node, prog, TYPE_STRING,
|
|
||||||
val);
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_ADD: {
|
case NODE_ADD: {
|
||||||
|
@ -133,101 +101,3 @@ void compiler_compile_children(struct compiler* self,
|
||||||
compiler_compile(self, child, prog);
|
compiler_compile(self, child, prog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void compiler_compile_value(struct compiler* self,
|
|
||||||
struct node* node,
|
|
||||||
struct prog* prog,
|
|
||||||
TypeKind type,
|
|
||||||
union val val)
|
|
||||||
{
|
|
||||||
(void) self;
|
|
||||||
struct value* value = malloc(sizeof(struct value));
|
|
||||||
value_init(value, type, val, node->token->line);
|
|
||||||
|
|
||||||
size_t idx = prog_add_constant(prog, value);
|
|
||||||
prog_add_instr(prog, OP_PUSH, idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void compiler_compile_and(struct compiler* self,
|
|
||||||
struct node* node,
|
|
||||||
struct prog* prog)
|
|
||||||
{
|
|
||||||
assert(self);
|
|
||||||
assert(node);
|
|
||||||
assert(prog);
|
|
||||||
|
|
||||||
struct vec to_false;
|
|
||||||
vec_init(&to_false);
|
|
||||||
|
|
||||||
for (size_t i =0; i<node->children.size; i++)
|
|
||||||
{
|
|
||||||
struct node* child = node->children.data[i];
|
|
||||||
compiler_compile(self, child, prog);
|
|
||||||
size_t brf = prog_add_instr(prog, OP_BRF, 0); // to false
|
|
||||||
vec_push(&to_false, (void*) brf);
|
|
||||||
}
|
|
||||||
|
|
||||||
union val tval;
|
|
||||||
tval.boolean = true;
|
|
||||||
compiler_compile_value(self, node, prog, TYPE_BOOL, tval);
|
|
||||||
size_t to_end = prog_add_instr(prog, OP_BR, 0);
|
|
||||||
|
|
||||||
union val fval;
|
|
||||||
fval.boolean = false;
|
|
||||||
size_t false_point = prog->opcodes.size;
|
|
||||||
compiler_compile_value(self, node, prog, TYPE_BOOL, fval);
|
|
||||||
|
|
||||||
size_t end_point = prog->opcodes.size;
|
|
||||||
((size_t*)prog->params.data)[to_end] = end_point;
|
|
||||||
|
|
||||||
for (size_t i=0; i<to_false.size; i++)
|
|
||||||
{
|
|
||||||
((size_t*)prog->params.data)[(size_t)
|
|
||||||
to_false.data[i]] = false_point;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec_free(&to_false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void compiler_compile_or(struct compiler* self,
|
|
||||||
struct node* node,
|
|
||||||
struct prog* prog)
|
|
||||||
{
|
|
||||||
assert(self);
|
|
||||||
assert(node);
|
|
||||||
assert(prog);
|
|
||||||
|
|
||||||
struct vec to_true;
|
|
||||||
vec_init(&to_true);
|
|
||||||
|
|
||||||
for (size_t i =0; i<node->children.size; i++)
|
|
||||||
{
|
|
||||||
struct node* child = node->children.data[i];
|
|
||||||
compiler_compile(self, child, prog);
|
|
||||||
prog_add_instr(prog, OP_NOT, 0);
|
|
||||||
size_t brf = prog_add_instr(prog, OP_BRF, 0); // to true
|
|
||||||
vec_push(&to_true, (void*) brf);
|
|
||||||
}
|
|
||||||
|
|
||||||
union val fval;
|
|
||||||
fval.boolean = false;
|
|
||||||
compiler_compile_value(self, node, prog, TYPE_BOOL, fval);
|
|
||||||
size_t to_end = prog_add_instr(prog, OP_BR, 0);
|
|
||||||
|
|
||||||
union val tval;
|
|
||||||
tval.boolean = true;
|
|
||||||
size_t true_point = prog->opcodes.size;
|
|
||||||
compiler_compile_value(self, node, prog, TYPE_BOOL, tval);
|
|
||||||
|
|
||||||
size_t end_point = prog->opcodes.size;
|
|
||||||
((size_t*)prog->params.data)[to_end] = end_point;
|
|
||||||
|
|
||||||
for (size_t i=0; i<to_true.size; i++)
|
|
||||||
{
|
|
||||||
((size_t*)prog->params.data)[(size_t)
|
|
||||||
to_true.data[i]] = true_point;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec_free(&to_true);
|
|
||||||
}
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ void exec_execute(struct exec* self,
|
||||||
str_init(&rstr);
|
str_init(&rstr);
|
||||||
value_str(right, &rstr);
|
value_str(right, &rstr);
|
||||||
|
|
||||||
errors_push(left->line,
|
errors_push(left->line,
|
||||||
"assertion failed"
|
"assertion failed"
|
||||||
"\n\texpected: %s"
|
"\n\texpected: %s"
|
||||||
"\n\tgot: %s",
|
"\n\tgot: %s",
|
||||||
|
@ -73,31 +73,6 @@ void exec_execute(struct exec* self,
|
||||||
constant->line
|
constant->line
|
||||||
);
|
);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case TYPE_FLOAT: {
|
|
||||||
state_push_float(
|
|
||||||
state,
|
|
||||||
constant->val.real,
|
|
||||||
constant->line
|
|
||||||
);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case TYPE_STRING: {
|
|
||||||
state_push_string(
|
|
||||||
state,
|
|
||||||
constant->val.str,
|
|
||||||
constant->line
|
|
||||||
);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case TYPE_BOOL: {
|
|
||||||
state_push_bool(
|
|
||||||
state,
|
|
||||||
constant->val.boolean,
|
|
||||||
constant->line
|
|
||||||
);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
fprintf(stderr, "cannot push value '%s'\n",
|
fprintf(stderr, "cannot push value '%s'\n",
|
||||||
TypeKindStr[constant->type]);
|
TypeKindStr[constant->type]);
|
||||||
|
@ -142,41 +117,6 @@ void exec_execute(struct exec* self,
|
||||||
self->pc++;
|
self->pc++;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case OP_NOT: {
|
|
||||||
state_not(state);
|
|
||||||
self->pc++;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case OP_AND: {
|
|
||||||
state_and(state);
|
|
||||||
self->pc++;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case OP_OR: {
|
|
||||||
state_or(state);
|
|
||||||
self->pc++;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case OP_BR: {
|
|
||||||
self->pc = param;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case OP_BRF: {
|
|
||||||
SK addr = state_pop(state);
|
|
||||||
bool val =
|
|
||||||
state_try_get_value(state, addr)->val.boolean;
|
|
||||||
|
|
||||||
if (!val)
|
|
||||||
{
|
|
||||||
self->pc = param;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
self->pc++;
|
|
||||||
}
|
|
||||||
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
fprintf(stderr, "cannot execute opcode '%s'\n",
|
fprintf(stderr, "cannot execute opcode '%s'\n",
|
||||||
OpcodeStr[opcode]);
|
OpcodeStr[opcode]);
|
||||||
|
|
181
lib/src/lexer.c
181
lib/src/lexer.c
|
@ -31,13 +31,6 @@ void lexer_free(struct lexer* self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lexer_is_at_end(struct lexer* self)
|
|
||||||
{
|
|
||||||
assert(self);
|
|
||||||
lexer_skip_comments(self);
|
|
||||||
return self->context.cursor >= self->len;
|
|
||||||
}
|
|
||||||
|
|
||||||
void lexer_skip_spaces(struct lexer* self)
|
void lexer_skip_spaces(struct lexer* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -54,25 +47,6 @@ void lexer_skip_spaces(struct lexer* self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void lexer_skip_comments(struct lexer* self)
|
|
||||||
{
|
|
||||||
assert(self);
|
|
||||||
|
|
||||||
lexer_skip_spaces(self);
|
|
||||||
|
|
||||||
while (self->context.cursor < self->len
|
|
||||||
&& self->source[self->context.cursor] == '#')
|
|
||||||
{
|
|
||||||
while (self->context.cursor < self->len
|
|
||||||
&& self->source[self->context.cursor] != '\n')
|
|
||||||
{
|
|
||||||
self->context.cursor++;
|
|
||||||
}
|
|
||||||
|
|
||||||
lexer_skip_spaces(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lexer_is_sep(struct lexer* self, size_t index)
|
bool lexer_is_sep(struct lexer* self, size_t index)
|
||||||
{
|
{
|
||||||
if (index >= self->len) { return true; }
|
if (index >= self->len) { return true; }
|
||||||
|
@ -124,29 +98,20 @@ struct token* lexer_try_new_next(struct lexer* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
|
||||||
lexer_skip_comments(self);
|
|
||||||
|
|
||||||
if (!errors_ok())
|
if (!errors_ok())
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct token* tok = NULL;
|
lexer_skip_spaces(self);
|
||||||
|
|
||||||
if ( (tok=lexer_try_scan_float(self)) )
|
struct token* tok = NULL;
|
||||||
{
|
|
||||||
return tok;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( (tok=lexer_try_scan_int(self)) )
|
if ( (tok=lexer_try_scan_int(self)) )
|
||||||
{
|
{
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (tok=lexer_try_scan_string(self)) )
|
|
||||||
{
|
|
||||||
return tok;
|
|
||||||
}
|
|
||||||
SK_SCAN_TEXT("+", TOKEN_ADD);
|
SK_SCAN_TEXT("+", TOKEN_ADD);
|
||||||
SK_SCAN_TEXT("-", TOKEN_SUB);
|
SK_SCAN_TEXT("-", TOKEN_SUB);
|
||||||
SK_SCAN_TEXT("*", TOKEN_MUL);
|
SK_SCAN_TEXT("*", TOKEN_MUL);
|
||||||
|
@ -157,12 +122,6 @@ struct token* lexer_try_new_next(struct lexer* self)
|
||||||
SK_SCAN_TEXT(")", TOKEN_CPAR);
|
SK_SCAN_TEXT(")", TOKEN_CPAR);
|
||||||
SK_SCAN_KEYWORD("assert", TOKEN_ASSERT, NULL);
|
SK_SCAN_KEYWORD("assert", TOKEN_ASSERT, NULL);
|
||||||
SK_SCAN_KEYWORD("eq", TOKEN_ASSERT_EQ, NULL);
|
SK_SCAN_KEYWORD("eq", TOKEN_ASSERT_EQ, NULL);
|
||||||
SK_SCAN_KEYWORD("true", TOKEN_BOOL, "true");
|
|
||||||
SK_SCAN_KEYWORD("false", TOKEN_BOOL, "false");
|
|
||||||
SK_SCAN_KEYWORD("and", TOKEN_AND, NULL);
|
|
||||||
SK_SCAN_KEYWORD("or", TOKEN_OR, NULL);
|
|
||||||
SK_SCAN_KEYWORD("not", TOKEN_NOT, NULL);
|
|
||||||
|
|
||||||
|
|
||||||
if (self->context.cursor < self->len)
|
if (self->context.cursor < self->len)
|
||||||
{
|
{
|
||||||
|
@ -221,142 +180,6 @@ struct token* lexer_try_scan_int(struct lexer* self)
|
||||||
return tok;
|
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_string(struct lexer* self)
|
|
||||||
{
|
|
||||||
assert(self);
|
|
||||||
size_t cursor = self->context.cursor;
|
|
||||||
|
|
||||||
if (cursor >= self->len
|
|
||||||
|| self->source[cursor] != '"')
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor++;
|
|
||||||
|
|
||||||
struct str value;
|
|
||||||
str_init(&value);
|
|
||||||
bool escaped = false;
|
|
||||||
|
|
||||||
while (cursor < self->len
|
|
||||||
&& self->source[cursor] != '"')
|
|
||||||
{
|
|
||||||
if (self->source[cursor] == '\\')
|
|
||||||
{
|
|
||||||
escaped = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (escaped)
|
|
||||||
{
|
|
||||||
cursor++;
|
|
||||||
|
|
||||||
switch (self->source[cursor])
|
|
||||||
{
|
|
||||||
case '\\': {
|
|
||||||
str_push(&value, '\\');
|
|
||||||
} break;
|
|
||||||
case 'n': {
|
|
||||||
str_push(&value, '\n');
|
|
||||||
} break;
|
|
||||||
case 'r': {
|
|
||||||
str_push(&value, '\r');
|
|
||||||
} break;
|
|
||||||
case 't': {
|
|
||||||
str_push(&value, '\t');
|
|
||||||
} break;
|
|
||||||
case 'e': {
|
|
||||||
str_push(&value, '\e');
|
|
||||||
} break;
|
|
||||||
case '"': {
|
|
||||||
str_push(&value, '"');
|
|
||||||
} break;
|
|
||||||
default: {
|
|
||||||
errors_push(self->context.line,
|
|
||||||
"unknown escape symbol");
|
|
||||||
str_free(&value);
|
|
||||||
return NULL;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
|
|
||||||
escaped = false;
|
|
||||||
cursor++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
str_push(&value, self->source[cursor]);
|
|
||||||
cursor++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cursor >= self->len
|
|
||||||
|| self->source[cursor] != '"')
|
|
||||||
{
|
|
||||||
str_free(&value);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor++;
|
|
||||||
|
|
||||||
struct token* tok = malloc(sizeof(struct token));
|
|
||||||
token_init(tok, TOKEN_STRING, value.value, self->context.line);
|
|
||||||
self->context.cursor = cursor;
|
|
||||||
str_free(&value);
|
|
||||||
return tok;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct token* lexer_try_scan_text(struct lexer* self,
|
struct token* lexer_try_scan_text(struct lexer* self,
|
||||||
char const* text,
|
char const* text,
|
||||||
TokenKind kind)
|
TokenKind kind)
|
||||||
|
|
164
lib/src/parser.c
164
lib/src/parser.c
|
@ -50,40 +50,19 @@ struct node* parser_try_root(struct parser* self)
|
||||||
|
|
||||||
node_init(node, NODE_ROOT, tok);
|
node_init(node, NODE_ROOT, tok);
|
||||||
|
|
||||||
struct str error_str;
|
while (true)
|
||||||
str_init(&error_str);
|
|
||||||
|
|
||||||
while (!lexer_is_at_end(&self->lexer))
|
|
||||||
{
|
{
|
||||||
struct node* expr = SK_TRY(parser_try_expr);
|
struct node* expr = SK_TRY(parser_try_expr);
|
||||||
|
if (!expr) { break; }
|
||||||
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);
|
node_push_new_child(node, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->lexer.context.cursor < self->lexer.len)
|
if (self->lexer.context.cursor < self->lexer.len)
|
||||||
{
|
{
|
||||||
errors_push(self->lexer.context.line,
|
errors_push(self->lexer.context.line, "unexpected end");
|
||||||
"unexpected end near '%s'",
|
|
||||||
error_str.value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
str_free(&error_str);
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +73,7 @@ struct node* parser_try_expr(struct parser* self)
|
||||||
return SK_TRY(parser_try_assert);
|
return SK_TRY(parser_try_assert);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SK_TRY(parser_try_or);
|
return SK_TRY(parser_try_term);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct node* parser_try_assert(struct parser* self)
|
struct node* parser_try_assert(struct parser* self)
|
||||||
|
@ -109,31 +88,22 @@ struct node* parser_try_assert(struct parser* self)
|
||||||
struct token* tok = lexer_try_new_next(&self->lexer);
|
struct token* tok = lexer_try_new_next(&self->lexer);
|
||||||
|
|
||||||
struct node* lhs = SK_TRY(parser_try_expr);
|
struct node* lhs = SK_TRY(parser_try_expr);
|
||||||
if (!lhs)
|
if (!lhs) { return NULL; }
|
||||||
{
|
|
||||||
token_free(tok); free(tok);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lexer_next_is(&self->lexer, TOKEN_ASSERT_EQ))
|
if (!lexer_next_is(&self->lexer, TOKEN_ASSERT_EQ))
|
||||||
{
|
{
|
||||||
token_free(tok);
|
token_free(tok);
|
||||||
free(tok);
|
free(tok);
|
||||||
|
|
||||||
node_free(lhs);
|
|
||||||
free(lhs);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
lexer_consume_next(&self->lexer);
|
lexer_consume_next(&self->lexer);
|
||||||
struct node* rhs = SK_TRY(parser_try_expr);
|
struct node* rhs = SK_TRY(parser_try_expr);
|
||||||
if (!rhs)
|
if (!rhs)
|
||||||
{
|
{
|
||||||
token_free(tok);
|
token_free(tok);
|
||||||
free(tok);
|
free(tok);
|
||||||
node_free(lhs);
|
return NULL;
|
||||||
free(lhs);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct node* node = malloc(sizeof(struct node));
|
struct node* node = malloc(sizeof(struct node));
|
||||||
|
@ -143,66 +113,6 @@ struct node* parser_try_assert(struct parser* self)
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct node* parser_try_or(struct parser* self)
|
|
||||||
{
|
|
||||||
assert(self);
|
|
||||||
struct node* lhs = SK_TRY(parser_try_and);
|
|
||||||
if (!lhs) { return NULL; }
|
|
||||||
|
|
||||||
while (lexer_next_is(&self->lexer, TOKEN_OR))
|
|
||||||
{
|
|
||||||
struct node* node = malloc(sizeof(struct node));
|
|
||||||
node_init(node, NODE_OR, lexer_try_new_next(
|
|
||||||
&self->lexer
|
|
||||||
));
|
|
||||||
|
|
||||||
node_push_new_child(node, lhs);
|
|
||||||
struct node* rhs = SK_TRY(parser_try_and);
|
|
||||||
|
|
||||||
if (!rhs)
|
|
||||||
{
|
|
||||||
node_free(node);
|
|
||||||
free(node);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
node_push_new_child(node, rhs);
|
|
||||||
lhs = node;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct node* parser_try_and(struct parser* self)
|
|
||||||
{
|
|
||||||
assert(self);
|
|
||||||
struct node* lhs = SK_TRY(parser_try_term);
|
|
||||||
if (!lhs) { return NULL; }
|
|
||||||
|
|
||||||
while (lexer_next_is(&self->lexer, TOKEN_AND))
|
|
||||||
{
|
|
||||||
struct node* node = malloc(sizeof(struct node));
|
|
||||||
node_init(node, NODE_AND, lexer_try_new_next(
|
|
||||||
&self->lexer
|
|
||||||
));
|
|
||||||
|
|
||||||
node_push_new_child(node, lhs);
|
|
||||||
struct node* rhs = SK_TRY(parser_try_term);
|
|
||||||
|
|
||||||
if (!rhs)
|
|
||||||
{
|
|
||||||
node_free(node);
|
|
||||||
free(node);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
node_push_new_child(node, rhs);
|
|
||||||
lhs = node;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct node* parser_try_term(struct parser* self)
|
struct node* parser_try_term(struct parser* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -315,33 +225,6 @@ struct node* parser_try_usub(struct parser* self)
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SK_TRY(parser_try_not);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct node* parser_try_not(struct parser* self)
|
|
||||||
{
|
|
||||||
assert(self);
|
|
||||||
|
|
||||||
if (lexer_next_is(&self->lexer, TOKEN_NOT))
|
|
||||||
{
|
|
||||||
struct node* node = malloc(sizeof(struct node));
|
|
||||||
node_init(node, NODE_NOT, lexer_try_new_next(
|
|
||||||
&self->lexer
|
|
||||||
));
|
|
||||||
|
|
||||||
struct node* child = SK_TRY(parser_try_not);
|
|
||||||
|
|
||||||
if (!child)
|
|
||||||
{
|
|
||||||
node_free(node);
|
|
||||||
free(node);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
node_push_new_child(node, child);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SK_TRY(parser_try_pow);
|
return SK_TRY(parser_try_pow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,17 +290,6 @@ struct node* parser_try_literal(struct parser* self)
|
||||||
|
|
||||||
struct node* parser_try_builtin(struct parser* self)
|
struct node* parser_try_builtin(struct parser* self)
|
||||||
{
|
{
|
||||||
if (lexer_next_is(&self->lexer, TOKEN_BOOL))
|
|
||||||
{
|
|
||||||
struct node* node = malloc(sizeof(struct node));
|
|
||||||
|
|
||||||
node_init(node,
|
|
||||||
NODE_BOOL,
|
|
||||||
lexer_try_new_next(&self->lexer));
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lexer_next_is(&self->lexer, TOKEN_INT))
|
if (lexer_next_is(&self->lexer, TOKEN_INT))
|
||||||
{
|
{
|
||||||
struct node* node = malloc(sizeof(struct node));
|
struct node* node = malloc(sizeof(struct node));
|
||||||
|
@ -429,27 +301,5 @@ struct node* parser_try_builtin(struct parser* self)
|
||||||
return node;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lexer_next_is(&self->lexer, TOKEN_STRING))
|
|
||||||
{
|
|
||||||
struct node* node = malloc(sizeof(struct node));
|
|
||||||
|
|
||||||
node_init(node,
|
|
||||||
NODE_STRING,
|
|
||||||
lexer_try_new_next(&self->lexer));
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
384
lib/src/state.c
384
lib/src/state.c
|
@ -107,15 +107,14 @@ SK state_pop(struct state* self)
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
SK state_push(struct state* self,
|
SK state_push_int(struct state* self, int integer, int line)
|
||||||
TypeKind type,
|
|
||||||
union val val,
|
|
||||||
int line)
|
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
|
||||||
struct value* value = malloc(sizeof(struct value));
|
struct value* value = malloc(sizeof(struct value));
|
||||||
value_init(value, type, val, line);
|
union val val;
|
||||||
|
val.integer = integer;
|
||||||
|
value_init(value, TYPE_INT, val, line);
|
||||||
|
|
||||||
struct frame* frame = state_frame(self);
|
struct frame* frame = state_frame(self);
|
||||||
struct local* local = malloc(sizeof(struct local));
|
struct local* local = malloc(sizeof(struct local));
|
||||||
|
@ -126,134 +125,21 @@ SK state_push(struct state* self,
|
||||||
|
|
||||||
self->addr++;
|
self->addr++;
|
||||||
return self->addr - 1;
|
return self->addr - 1;
|
||||||
}
|
|
||||||
|
|
||||||
SK state_push_int(struct state* self, int integer, int line)
|
|
||||||
{
|
|
||||||
assert(self);
|
|
||||||
|
|
||||||
union val val;
|
|
||||||
val.integer = integer;
|
|
||||||
return state_push(self, TYPE_INT, val, line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SK state_push_bool(struct state* self, bool boolean, int line)
|
|
||||||
{
|
|
||||||
assert(self);
|
|
||||||
|
|
||||||
union val val;
|
|
||||||
val.boolean = boolean;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
SK state_push_string(struct state* self, char const* str, int line)
|
|
||||||
{
|
|
||||||
assert(self);
|
|
||||||
union val val;
|
|
||||||
val.str = strdup(str);
|
|
||||||
return state_push(self, TYPE_STRING, 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeKind state_type(struct state* self, SK value)
|
|
||||||
{
|
|
||||||
assert(self);
|
|
||||||
struct value const* val = state_try_get_value(self, value);
|
|
||||||
return val->type;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 state_add(struct state* self)
|
||||||
{
|
{
|
||||||
SK rhs = state_pop(self);
|
SK rhs = state_pop(self);
|
||||||
SK lhs = state_pop(self);
|
SK lhs = state_pop(self);
|
||||||
|
|
||||||
TypeKind type = state_common_num_type(self, lhs, rhs);
|
struct value* left = state_try_get_value(self, lhs);
|
||||||
|
struct value* right = state_try_get_value(self, rhs);
|
||||||
|
|
||||||
if(state_type(self, lhs) == TYPE_STRING
|
return state_push_int(
|
||||||
&& state_type(self, rhs) == TYPE_STRING)
|
self,
|
||||||
{
|
left->val.integer + right->val.integer,
|
||||||
struct value* left = state_try_get_value(self, lhs);
|
left->line
|
||||||
struct value* right = state_try_get_value(self, rhs);
|
);
|
||||||
struct str val;
|
|
||||||
str_init(&val);
|
|
||||||
str_extend(&val, left->val.str);
|
|
||||||
str_extend(&val, right->val.str);
|
|
||||||
SK res = state_push_string(self, val.value, left->line);
|
|
||||||
str_free(&val);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
else 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)
|
SK state_sub(struct state* self)
|
||||||
|
@ -261,60 +147,27 @@ SK state_sub(struct state* self)
|
||||||
SK rhs = state_pop(self);
|
SK rhs = state_pop(self);
|
||||||
SK lhs = state_pop(self);
|
SK lhs = state_pop(self);
|
||||||
|
|
||||||
TypeKind type = state_common_num_type(self, lhs, rhs);
|
struct value* left = state_try_get_value(self, lhs);
|
||||||
|
struct value* right = state_try_get_value(self, rhs);
|
||||||
|
|
||||||
if (type == TYPE_INT)
|
return state_push_int(
|
||||||
{
|
self,
|
||||||
return state_push_int(
|
left->val.integer - right->val.integer,
|
||||||
self,
|
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 state_usub(struct state* self)
|
||||||
{
|
{
|
||||||
SK lhs = state_pop(self);
|
SK lhs = state_pop(self);
|
||||||
struct value const* value = state_try_get_value(self, lhs);
|
|
||||||
TypeKind type = value->type;
|
|
||||||
|
|
||||||
if (type == TYPE_INT)
|
struct value* left = state_try_get_value(self, lhs);
|
||||||
{
|
|
||||||
return state_push_int(
|
return state_push_int(
|
||||||
self,
|
self,
|
||||||
-state_as_real(self, lhs),
|
-left->val.integer,
|
||||||
state_line(self, lhs)
|
left->line
|
||||||
);
|
);
|
||||||
}
|
|
||||||
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 state_mul(struct state* self)
|
||||||
|
@ -322,60 +175,14 @@ SK state_mul(struct state* self)
|
||||||
SK rhs = state_pop(self);
|
SK rhs = state_pop(self);
|
||||||
SK lhs = state_pop(self);
|
SK lhs = state_pop(self);
|
||||||
|
|
||||||
TypeKind type = state_common_num_type(self, lhs, rhs);
|
struct value* left = state_try_get_value(self, lhs);
|
||||||
|
struct value* right = state_try_get_value(self, rhs);
|
||||||
|
|
||||||
if(state_type(self, lhs) == TYPE_STRING
|
return state_push_int(
|
||||||
&& state_type(self, rhs) == TYPE_INT)
|
self,
|
||||||
{
|
left->val.integer * right->val.integer,
|
||||||
struct value* left = state_try_get_value(self, lhs);
|
left->line
|
||||||
struct value* right = state_try_get_value(self, rhs);
|
);
|
||||||
struct str val;
|
|
||||||
str_init(&val);
|
|
||||||
for (int i=0; i<right->val.integer; i++)
|
|
||||||
{
|
|
||||||
str_extend(&val, left->val.str);
|
|
||||||
}
|
|
||||||
SK res = state_push_string(self, val.value, left->line);
|
|
||||||
str_free(&val);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
else if(state_type(self, lhs) == TYPE_INT
|
|
||||||
&& state_type(self, rhs) == TYPE_STRING)
|
|
||||||
{
|
|
||||||
struct value* left = state_try_get_value(self, lhs);
|
|
||||||
struct value* right = state_try_get_value(self, rhs);
|
|
||||||
struct str val;
|
|
||||||
str_init(&val);
|
|
||||||
for (int i=0; i<left->val.integer; i++)
|
|
||||||
{
|
|
||||||
str_extend(&val, right->val.str);
|
|
||||||
}
|
|
||||||
SK res = state_push_string(self, val.value, left->line);
|
|
||||||
str_free(&val);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
else 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)
|
SK state_div(struct state* self)
|
||||||
|
@ -383,30 +190,14 @@ SK state_div(struct state* self)
|
||||||
SK rhs = state_pop(self);
|
SK rhs = state_pop(self);
|
||||||
SK lhs = state_pop(self);
|
SK lhs = state_pop(self);
|
||||||
|
|
||||||
TypeKind type = state_common_num_type(self, lhs, rhs);
|
struct value* left = state_try_get_value(self, lhs);
|
||||||
|
struct value* right = state_try_get_value(self, rhs);
|
||||||
|
|
||||||
if (type == TYPE_INT)
|
return state_push_int(
|
||||||
{
|
self,
|
||||||
return state_push_int(
|
left->val.integer / right->val.integer,
|
||||||
self,
|
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 state_mod(struct state* self)
|
||||||
|
@ -414,32 +205,14 @@ SK state_mod(struct state* self)
|
||||||
SK rhs = state_pop(self);
|
SK rhs = state_pop(self);
|
||||||
SK lhs = state_pop(self);
|
SK lhs = state_pop(self);
|
||||||
|
|
||||||
TypeKind type = state_common_num_type(self, lhs, rhs);
|
struct value* left = state_try_get_value(self, lhs);
|
||||||
|
struct value* right = state_try_get_value(self, rhs);
|
||||||
|
|
||||||
if (type == TYPE_INT)
|
return state_push_int(
|
||||||
{
|
self,
|
||||||
return state_push_int(
|
fmod(left->val.integer, right->val.integer),
|
||||||
self,
|
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 state_pow(struct state* self)
|
||||||
|
@ -447,73 +220,12 @@ SK state_pow(struct state* self)
|
||||||
SK rhs = state_pop(self);
|
SK rhs = state_pop(self);
|
||||||
SK lhs = state_pop(self);
|
SK lhs = state_pop(self);
|
||||||
|
|
||||||
TypeKind type = state_common_num_type(self, lhs, rhs);
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
SK rhs = state_pop(self);
|
|
||||||
SK lhs = state_pop(self);
|
|
||||||
|
|
||||||
struct value* left = state_try_get_value(self, lhs);
|
struct value* left = state_try_get_value(self, lhs);
|
||||||
struct value* right = state_try_get_value(self, rhs);
|
struct value* right = state_try_get_value(self, rhs);
|
||||||
|
|
||||||
return state_push_bool(
|
return state_push_int(
|
||||||
self,
|
self,
|
||||||
left->val.boolean && right->val.boolean,
|
powf(left->val.integer, right->val.integer),
|
||||||
left->line
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
SK state_or(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);
|
|
||||||
|
|
||||||
return state_push_bool(
|
|
||||||
self,
|
|
||||||
left->val.boolean || right->val.boolean,
|
|
||||||
left->line
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
SK state_not(struct state* self)
|
|
||||||
{
|
|
||||||
SK lhs = state_pop(self);
|
|
||||||
|
|
||||||
struct value* left = state_try_get_value(self, lhs);
|
|
||||||
|
|
||||||
return state_push_bool(
|
|
||||||
self,
|
|
||||||
!left->val.boolean,
|
|
||||||
left->line
|
left->line
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,6 @@ void value_init(struct value* self,
|
||||||
void value_free(struct value* self)
|
void value_free(struct value* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
if (self->type == TYPE_STRING)
|
|
||||||
{
|
|
||||||
free(self->val.str);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool value_equals(struct value* self, struct value* rhs)
|
bool value_equals(struct value* self, struct value* rhs)
|
||||||
|
@ -47,22 +43,9 @@ void value_str(struct value* self, struct str* dest)
|
||||||
|
|
||||||
switch (self->type)
|
switch (self->type)
|
||||||
{
|
{
|
||||||
case TYPE_STRING: {
|
|
||||||
str_format(dest, "%s", self->val.str);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case TYPE_INT: {
|
case TYPE_INT: {
|
||||||
str_format(dest, "%d", self->val.integer);
|
str_format(dest, "%d", self->val.integer);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case TYPE_FLOAT: {
|
|
||||||
str_format(dest, "%f", self->val.real);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case TYPE_BOOL: {
|
|
||||||
str_format(dest, "%s",
|
|
||||||
self->val.boolean ? "true" : "false");
|
|
||||||
} break;
|
|
||||||
default: {
|
default: {
|
||||||
fprintf(stderr, "cannot get value string of '%s'\n",
|
fprintf(stderr, "cannot get value string of '%s'\n",
|
||||||
TypeKindStr[self->type]);
|
TypeKindStr[self->type]);
|
||||||
|
|
|
@ -16,10 +16,6 @@ static void test_lexer(char const* source, int count, ...)
|
||||||
for (int i=0; i<count; i++)
|
for (int i=0; i<count; i++)
|
||||||
{
|
{
|
||||||
struct token* tok = lexer_try_new_next(&lexer);
|
struct token* tok = lexer_try_new_next(&lexer);
|
||||||
if (tok == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s == NULL\n", source);
|
|
||||||
}
|
|
||||||
CU_ASSERT_FATAL(tok != NULL);
|
CU_ASSERT_FATAL(tok != NULL);
|
||||||
struct str tok_str;
|
struct str tok_str;
|
||||||
str_init(&tok_str);
|
str_init(&tok_str);
|
||||||
|
@ -30,7 +26,7 @@ static void test_lexer(char const* source, int count, ...)
|
||||||
fprintf(stderr, "%s != %s\n", oracle, tok_str.value);
|
fprintf(stderr, "%s != %s\n", oracle, tok_str.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
CU_ASSERT_STRING_EQUAL_FATAL(tok_str.value, oracle);
|
CU_ASSERT_STRING_EQUAL(tok_str.value, oracle);
|
||||||
str_free(&tok_str);
|
str_free(&tok_str);
|
||||||
token_free(tok);
|
token_free(tok);
|
||||||
free(tok);
|
free(tok);
|
||||||
|
@ -64,46 +60,11 @@ static void test_lexer_assert()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_lexer_bool()
|
|
||||||
{
|
|
||||||
test_lexer("true false and or not", 5,
|
|
||||||
"BOOL[true]",
|
|
||||||
"BOOL[false]",
|
|
||||||
"AND",
|
|
||||||
"OR",
|
|
||||||
"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]"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_lexer_string()
|
|
||||||
{
|
|
||||||
test_lexer("\" hello \" \"\\\"world\\\"\"", 2,
|
|
||||||
"STRING[ hello ]",
|
|
||||||
"STRING[\"world\"]"
|
|
||||||
);
|
|
||||||
|
|
||||||
test_lexer("\"\\n\\r\\t\\e\"", 1,
|
|
||||||
"STRING[\n\r\t\e]"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void register_lexer()
|
void register_lexer()
|
||||||
{
|
{
|
||||||
CU_pSuite suite = CU_add_suite("Lexer", 0, 0);
|
CU_pSuite suite = CU_add_suite("Lexer", 0, 0);
|
||||||
CU_add_test(suite, "Integers", test_lexer_int);
|
CU_add_test(suite, "Integers", test_lexer_int);
|
||||||
CU_add_test(suite, "Assertions", test_lexer_assert);
|
CU_add_test(suite, "Assertions", test_lexer_assert);
|
||||||
CU_add_test(suite, "Booleans", test_lexer_bool);
|
|
||||||
CU_add_test(suite, "Floats", test_lexer_float);
|
|
||||||
CU_add_test(suite, "Strings", test_lexer_string);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -44,40 +44,15 @@ static void test_parser_int()
|
||||||
|
|
||||||
static void test_parser_assert()
|
static void test_parser_assert()
|
||||||
{
|
{
|
||||||
test_parser("ROOT(ASSERT_EQ(INT[32],INT[12]))",
|
test_parser("ROOT(ASSERT_EQ(INT[32],INT[12]))",
|
||||||
" assert 32 eq 12 ");
|
" assert 32 eq 12 ");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_parser_bool()
|
|
||||||
{
|
|
||||||
test_parser("ROOT(BOOL[true])",
|
|
||||||
"true");
|
|
||||||
|
|
||||||
test_parser("ROOT(NOT(BOOL[false]))",
|
|
||||||
"not false");
|
|
||||||
|
|
||||||
test_parser("ROOT(OR(AND(NOT(BOOL[false]),BOOL[true]),"
|
|
||||||
"BOOL[false]))",
|
|
||||||
"not false and true or false");
|
|
||||||
|
|
||||||
test_parser("ROOT(AND(NOT(BOOL[false]),OR(BOOL[true],"
|
|
||||||
"BOOL[false])))",
|
|
||||||
"not false and (true or false)");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_parser_string()
|
|
||||||
{
|
|
||||||
test_parser("ROOT(STRING[ok pizza NOW])",
|
|
||||||
"\"ok pizza NOW\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
void register_parser()
|
void register_parser()
|
||||||
{
|
{
|
||||||
CU_pSuite suite = CU_add_suite("Parser", 0, 0);
|
CU_pSuite suite = CU_add_suite("Parser", 0, 0);
|
||||||
CU_add_test(suite, "Integers", test_parser_int);
|
CU_add_test(suite, "Integers", test_parser_int);
|
||||||
CU_add_test(suite, "Assertions", test_parser_assert);
|
CU_add_test(suite, "Assertions", test_parser_assert);
|
||||||
CU_add_test(suite, "Booleans", test_parser_bool);
|
|
||||||
CU_add_test(suite, "Strings", test_parser_string);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue