✨ builtin types.
parent
93b7231bb1
commit
12fd626cd5
|
@ -0,0 +1,7 @@
|
|||
ROOT ::= ATOM*
|
||||
ATOM ::=
|
||||
| int
|
||||
| float
|
||||
| bool
|
||||
| string
|
||||
| symbol
|
|
@ -7,10 +7,19 @@ add_library(moka-core
|
|||
status.c
|
||||
vec.c
|
||||
str.c
|
||||
token.c
|
||||
lexer.c
|
||||
node.c
|
||||
parser.c
|
||||
prog.c
|
||||
compiler.c
|
||||
value.c
|
||||
exec.c
|
||||
moka.c
|
||||
)
|
||||
|
||||
target_compile_options(moka-core
|
||||
PUBLIC -Wall -Wextra
|
||||
PUBLIC -Wall -Wextra -g
|
||||
)
|
||||
|
||||
target_include_directories(moka-core
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define MK_STRLEN 4096
|
||||
#define MK_ENUM_ENUM(X) X
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
#include "compiler.h"
|
||||
|
||||
void compiler_init(struct compiler* self,
|
||||
struct status* status)
|
||||
{
|
||||
assert(self);
|
||||
self->status = status;
|
||||
}
|
||||
|
||||
void compiler_free(struct compiler* self)
|
||||
{
|
||||
assert(self);
|
||||
}
|
||||
|
||||
void compiler_compile(struct compiler* self,
|
||||
struct node* node,
|
||||
struct prog* prog)
|
||||
{
|
||||
assert(self); assert(node); assert(prog);
|
||||
|
||||
switch (node->kind)
|
||||
{
|
||||
case NODE_ROOT: {
|
||||
for (size_t i=0; i<node->children.size; i++)
|
||||
{
|
||||
struct node* child = node->children.data[i];
|
||||
compiler_compile(self, child, prog);
|
||||
}
|
||||
} break;
|
||||
|
||||
case NODE_INT: {
|
||||
struct value* value = malloc(sizeof(struct value));
|
||||
int val = atoi(node->token->value);
|
||||
value_init_int(value, val, node->line);
|
||||
ssize_t addr = prog_add_new_value(prog, value);
|
||||
prog_add_instruction(prog, OP_PUSH, addr);
|
||||
} break;
|
||||
|
||||
case NODE_FLOAT: {
|
||||
struct value* value = malloc(sizeof(struct value));
|
||||
float val = atof(node->token->value);
|
||||
value_init_float(value, val, node->line);
|
||||
ssize_t addr = prog_add_new_value(prog, value);
|
||||
prog_add_instruction(prog, OP_PUSH, addr);
|
||||
} break;
|
||||
|
||||
case NODE_BOOL: {
|
||||
struct value* value = malloc(sizeof(struct value));
|
||||
bool val = strcmp("true", node->token->value) == 0;
|
||||
value_init_bool(value, val, node->line);
|
||||
ssize_t addr = prog_add_new_value(prog, value);
|
||||
prog_add_instruction(prog, OP_PUSH, addr);
|
||||
} break;
|
||||
|
||||
case NODE_STRING: {
|
||||
struct value* value = malloc(sizeof(struct value));
|
||||
value_init_string(value, node->token->value, node->line);
|
||||
ssize_t addr = prog_add_new_value(prog, value);
|
||||
prog_add_instruction(prog, OP_PUSH, addr);
|
||||
} break;
|
||||
|
||||
case NODE_SYMBOL: {
|
||||
struct value* value = malloc(sizeof(struct value));
|
||||
value_init_symbol(value, node->token->value, node->line);
|
||||
ssize_t addr = prog_add_new_value(prog, value);
|
||||
prog_add_instruction(prog, OP_PUSH, addr);
|
||||
} break;
|
||||
default: {
|
||||
fprintf(stderr, "cannot compile node %s\n",
|
||||
NodeKindStr[node->kind]);
|
||||
abort();
|
||||
} break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef MK_COMPILER_H
|
||||
#define MK_COMPILER_H
|
||||
|
||||
#include "commons.h"
|
||||
#include "status.h"
|
||||
#include "prog.h"
|
||||
#include "node.h"
|
||||
|
||||
struct compiler
|
||||
{
|
||||
struct status* status;
|
||||
};
|
||||
|
||||
void compiler_init(struct compiler* self,
|
||||
struct status* status);
|
||||
void compiler_free(struct compiler* self);
|
||||
|
||||
void compiler_compile(struct compiler* self,
|
||||
struct node* node,
|
||||
struct prog* prog);
|
||||
#endif
|
|
@ -0,0 +1,82 @@
|
|||
#include "exec.h"
|
||||
|
||||
void exec_init(struct exec* self)
|
||||
{
|
||||
assert(self);
|
||||
self->pc = 0;
|
||||
}
|
||||
|
||||
void exec_free(struct exec* self)
|
||||
{
|
||||
assert(self);
|
||||
}
|
||||
|
||||
void exec_prog(struct exec* self,
|
||||
struct moka* moka,
|
||||
struct prog* prog)
|
||||
{
|
||||
assert(self); assert(moka); assert(prog);
|
||||
self->pc = 0;
|
||||
|
||||
while (self->pc < prog->instructions.size)
|
||||
{
|
||||
exec_instr(self,
|
||||
moka,
|
||||
prog,
|
||||
prog->instructions.data[self->pc]);
|
||||
}
|
||||
}
|
||||
|
||||
void exec_instr(struct exec* self,
|
||||
struct moka* moka,
|
||||
struct prog* prog,
|
||||
struct instruction* instr)
|
||||
{
|
||||
assert(self); assert(moka); assert(instr);
|
||||
int param = instr->param;
|
||||
|
||||
switch (instr->opcode)
|
||||
{
|
||||
case OP_PUSH: {
|
||||
struct value* value = prog->values.data[param];
|
||||
switch (value->type)
|
||||
{
|
||||
case TY_INT: {
|
||||
moka_push_int(moka, value->data.integer, value->line);
|
||||
} break;
|
||||
|
||||
case TY_FLOAT: {
|
||||
moka_push_float(moka, value->data.real, value->line);
|
||||
} break;
|
||||
|
||||
case TY_BOOL: {
|
||||
moka_push_bool(moka, value->data.boolean, value->line);
|
||||
} break;
|
||||
|
||||
case TY_STRING: {
|
||||
moka_push_string(moka, value->data.str, value->line);
|
||||
} break;
|
||||
|
||||
case TY_SYMBOL: {
|
||||
moka_push_symbol(moka, value->data.sym, value->line);
|
||||
} break;
|
||||
|
||||
default: {
|
||||
fprintf(stderr,
|
||||
"cannot push value of type <%s>\n",
|
||||
TypeKindStr[value->type]
|
||||
);
|
||||
|
||||
abort();
|
||||
} break;
|
||||
}
|
||||
self->pc++;
|
||||
} break;
|
||||
|
||||
default: {
|
||||
fprintf(stderr, "cannot execute opcode <%s>\n",
|
||||
OpcodeKindStr[instr->opcode]);
|
||||
abort();
|
||||
} break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef MK_EXEC_H
|
||||
#define MK_EXEC_H
|
||||
|
||||
#include "commons.h"
|
||||
#include "moka.h"
|
||||
#include "prog.h"
|
||||
|
||||
struct exec
|
||||
{
|
||||
size_t pc;
|
||||
};
|
||||
|
||||
void exec_init(struct exec* self);
|
||||
void exec_free(struct exec* self);
|
||||
|
||||
void exec_prog(struct exec* self,
|
||||
struct moka* moka,
|
||||
struct prog* prog);
|
||||
|
||||
void exec_instr(struct exec* self,
|
||||
struct moka* moka,
|
||||
struct prog* prog,
|
||||
struct instruction* instr);
|
||||
#endif
|
|
@ -0,0 +1,427 @@
|
|||
#include "lexer.h"
|
||||
#include "str.h"
|
||||
|
||||
void lexer_init(struct lexer* self,
|
||||
char const* source,
|
||||
struct status* status)
|
||||
{
|
||||
assert(self);
|
||||
self->status = status;
|
||||
self->source = NULL;
|
||||
self->len = 0;
|
||||
if (source)
|
||||
{
|
||||
self->source = strdup(source);
|
||||
self->len = strlen(self->source);
|
||||
}
|
||||
self->context.line = 1;
|
||||
self->context.cursor = 0;
|
||||
}
|
||||
|
||||
void lexer_free(struct lexer* self)
|
||||
{
|
||||
assert(self);
|
||||
free(self->source);
|
||||
}
|
||||
|
||||
struct token* lexer_try_new_next(struct lexer* self)
|
||||
{
|
||||
assert(self);
|
||||
struct token* tok = NULL;
|
||||
|
||||
lexer_skip_spaces(self);
|
||||
|
||||
if ( (tok=lexer_try_new_float(self)) )
|
||||
{
|
||||
return tok;
|
||||
}
|
||||
|
||||
if ( (tok=lexer_try_new_int(self)) )
|
||||
{
|
||||
return tok;
|
||||
}
|
||||
|
||||
if ( (tok=lexer_try_new_string(self)) )
|
||||
{
|
||||
return tok;
|
||||
}
|
||||
|
||||
if ( (tok=lexer_try_new_symbol(self)) )
|
||||
{
|
||||
return tok;
|
||||
}
|
||||
|
||||
if ( (tok=lexer_try_new_keyword(self, TOKEN_BOOL, "true", "true")) )
|
||||
{
|
||||
return tok;
|
||||
}
|
||||
|
||||
if ( (tok=lexer_try_new_keyword(self, TOKEN_BOOL, "false", "false")) )
|
||||
{
|
||||
return tok;
|
||||
}
|
||||
|
||||
if (self->context.cursor < self->len)
|
||||
{
|
||||
struct str str;
|
||||
str_init(&str);
|
||||
size_t cursor = self->context.cursor;
|
||||
|
||||
while (cursor < self->len
|
||||
&& !isspace(self->source[cursor]))
|
||||
{
|
||||
str_push(&str, self->source[cursor]);
|
||||
cursor++;
|
||||
}
|
||||
|
||||
status_push(
|
||||
self->status,
|
||||
STATUS_ERROR,
|
||||
self->context.line,
|
||||
"unknown literal <%s>",
|
||||
str.value
|
||||
);
|
||||
|
||||
str_free(&str);
|
||||
}
|
||||
|
||||
return tok;
|
||||
}
|
||||
|
||||
void lexer_skip_spaces(struct lexer* self)
|
||||
{
|
||||
assert(self);
|
||||
|
||||
while (self->context.cursor < self->len
|
||||
&& isspace(self->source[self->context.cursor]))
|
||||
{
|
||||
if (self->source[self->context.cursor] == '\n')
|
||||
{
|
||||
self->context.line++;
|
||||
}
|
||||
|
||||
self->context.cursor++;
|
||||
}
|
||||
}
|
||||
|
||||
struct token* lexer_try_new_int(struct lexer* self)
|
||||
{
|
||||
assert(self);
|
||||
size_t cursor = self->context.cursor;
|
||||
struct str str;
|
||||
str_init(&str);
|
||||
|
||||
if (cursor < self->len
|
||||
&& self->source[cursor] == '-')
|
||||
{
|
||||
str_push(&str, '-');
|
||||
cursor++;
|
||||
}
|
||||
|
||||
while (cursor < self->len
|
||||
&& isdigit(self->source[cursor]))
|
||||
{
|
||||
str_push(&str, self->source[cursor]);
|
||||
cursor++;
|
||||
}
|
||||
|
||||
if (str.size > 0
|
||||
&& (str.value[0] != '-' || str.size > 1))
|
||||
{
|
||||
self->context.cursor = cursor;
|
||||
struct token* tok = malloc(sizeof(struct token));
|
||||
token_init(tok, TOKEN_INT, str.value);
|
||||
str_free(&str);
|
||||
return tok;
|
||||
}
|
||||
|
||||
str_free(&str);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct token* lexer_try_new_float(struct lexer* self)
|
||||
{
|
||||
assert(self);
|
||||
size_t cursor = self->context.cursor;
|
||||
struct str str;
|
||||
str_init(&str);
|
||||
|
||||
if (cursor < self->len
|
||||
&& self->source[cursor] == '-')
|
||||
{
|
||||
str_push(&str, '-');
|
||||
cursor++;
|
||||
}
|
||||
|
||||
while (cursor < self->len
|
||||
&& isdigit(self->source[cursor]))
|
||||
{
|
||||
str_push(&str, self->source[cursor]);
|
||||
cursor++;
|
||||
}
|
||||
|
||||
if (cursor >= self->len
|
||||
|| self->source[cursor] != '.')
|
||||
{
|
||||
str_free(&str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
str_push(&str, '.');
|
||||
cursor++;
|
||||
|
||||
while (cursor < self->len
|
||||
&& isdigit(self->source[cursor]))
|
||||
{
|
||||
str_push(&str, self->source[cursor]);
|
||||
cursor++;
|
||||
}
|
||||
|
||||
if (str.size > 0
|
||||
&& (str.value[0] != '-' || str.size > 1))
|
||||
{
|
||||
self->context.cursor = cursor;
|
||||
struct token* tok = malloc(sizeof(struct token));
|
||||
token_init(tok, TOKEN_FLOAT, str.value);
|
||||
str_free(&str);
|
||||
return tok;
|
||||
}
|
||||
|
||||
str_free(&str);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct token* lexer_try_new_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);
|
||||
|
||||
while (cursor < self->len
|
||||
&& self->source[cursor] != '"')
|
||||
{
|
||||
char c = self->source[cursor];
|
||||
|
||||
if (c == '\\')
|
||||
{
|
||||
char c_next = self->source[cursor + 1];
|
||||
|
||||
switch (c_next)
|
||||
{
|
||||
case '"':
|
||||
case '\\':
|
||||
str_push(&value, c_next);
|
||||
break;
|
||||
case 'n': str_push(&value, '\n'); break;
|
||||
case 't': str_push(&value, '\t'); break;
|
||||
case 'r': str_push(&value, '\r'); break;
|
||||
case 'e': str_push(&value, '\e'); break;
|
||||
default: {
|
||||
fprintf(stderr, "unknown escaped char %c\n", c_next);
|
||||
abort();
|
||||
} break;
|
||||
}
|
||||
|
||||
cursor += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
str_push(&value, c);
|
||||
cursor++;
|
||||
}
|
||||
|
||||
if (cursor >= self->len)
|
||||
{
|
||||
str_free(&value);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cursor++;
|
||||
|
||||
struct token* tok = malloc(sizeof(struct token));
|
||||
token_init(tok, TOKEN_STRING, value.value);
|
||||
str_free(&value);
|
||||
|
||||
self->context.cursor = cursor;
|
||||
return tok;
|
||||
}
|
||||
|
||||
struct token* lexer_try_new_symbol(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);
|
||||
|
||||
while (cursor < self->len
|
||||
&& !lexer_is_sep(self, cursor))
|
||||
{
|
||||
char c = self->source[cursor];
|
||||
str_push(&value, c);
|
||||
cursor++;
|
||||
}
|
||||
|
||||
struct token* tok = malloc(sizeof(struct token));
|
||||
token_init(tok, TOKEN_SYMBOL, value.value);
|
||||
str_free(&value);
|
||||
|
||||
self->context.cursor = cursor;
|
||||
return tok;
|
||||
}
|
||||
|
||||
bool lexer_is_sep(struct lexer* self, size_t index)
|
||||
{
|
||||
assert(self);
|
||||
|
||||
if (index >= self->len)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
char c = self->source[index];
|
||||
return isspace(c);
|
||||
}
|
||||
|
||||
struct token* lexer_try_new_text(struct lexer* self,
|
||||
TokenKind kind,
|
||||
char const* text)
|
||||
{
|
||||
size_t cursor = self->context.cursor;
|
||||
|
||||
if (strlen(text) + cursor > self->len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t text_len = strlen(text);
|
||||
|
||||
for (size_t i=0; i<text_len; i++)
|
||||
{
|
||||
if (text[i] != self->source[cursor + i])
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct token* token = malloc(sizeof(struct token));
|
||||
token_init(token, kind, text);
|
||||
self->context.cursor += strlen(text);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
struct token* lexer_try_new_keyword(struct lexer* self,
|
||||
TokenKind kind,
|
||||
char const* keyword,
|
||||
char const* value)
|
||||
{
|
||||
size_t cursor = self->context.cursor;
|
||||
|
||||
if (strlen(keyword) + cursor > self->len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t kw_len = strlen(keyword);
|
||||
|
||||
for (size_t i=0; i<kw_len; i++)
|
||||
{
|
||||
if (keyword[i] != self->source[cursor + i])
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((cursor == 0 || lexer_is_sep(self, cursor - 1))
|
||||
&& (cursor + kw_len == self->len
|
||||
|| lexer_is_sep(self, cursor + kw_len)))
|
||||
|
||||
{
|
||||
struct token* token = malloc(sizeof(struct token));
|
||||
token_init(token, kind, value);
|
||||
self->context.cursor += strlen(keyword);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct lex_context lexer_state(struct lexer* self)
|
||||
{
|
||||
assert(self);
|
||||
return self->context;
|
||||
}
|
||||
|
||||
void lexer_restore(struct lexer* self,
|
||||
struct lex_context context)
|
||||
{
|
||||
assert(self);
|
||||
self->context = context;
|
||||
}
|
||||
|
||||
bool lexer_next_is(struct lexer* self,
|
||||
TokenKind kind,
|
||||
int lookahead)
|
||||
{
|
||||
assert(self);
|
||||
struct lex_context ctx = lexer_state(self);
|
||||
|
||||
for (int i=0; i<lookahead; i++)
|
||||
{
|
||||
struct token* tok = lexer_try_new_next(self);
|
||||
if(tok)
|
||||
{
|
||||
token_free(tok);
|
||||
free(tok);
|
||||
}
|
||||
else
|
||||
{
|
||||
lexer_restore(self, ctx);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
struct token* tok = lexer_try_new_next(self);
|
||||
bool res = tok && tok->kind == kind;
|
||||
|
||||
if(tok)
|
||||
{
|
||||
token_free(tok);
|
||||
free(tok);
|
||||
}
|
||||
else
|
||||
{
|
||||
lexer_restore(self, ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
lexer_restore(self, ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool lexer_end(struct lexer* self)
|
||||
{
|
||||
assert(self);
|
||||
lexer_skip_spaces(self);
|
||||
return self->context.cursor >= self->len;
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef MK_LEXER_H
|
||||
#define MK_LEXER_H
|
||||
|
||||
#include "token.h"
|
||||
#include "commons.h"
|
||||
#include "status.h"
|
||||
#include "str.h"
|
||||
|
||||
struct lex_context
|
||||
{
|
||||
size_t cursor;
|
||||
int line;
|
||||
};
|
||||
|
||||
struct lexer
|
||||
{
|
||||
struct status* status;
|
||||
char* source;
|
||||
size_t len;
|
||||
struct lex_context context;
|
||||
struct str separators;
|
||||
};
|
||||
|
||||
void lexer_init(struct lexer* self,
|
||||
char const* source,
|
||||
struct status* status);
|
||||
|
||||
void lexer_free(struct lexer* self);
|
||||
|
||||
struct token* lexer_try_new_next(struct lexer* self);
|
||||
void lexer_skip_spaces(struct lexer* self);
|
||||
|
||||
struct token* lexer_try_new_int(struct lexer* self);
|
||||
struct token* lexer_try_new_float(struct lexer* self);
|
||||
struct token* lexer_try_new_string(struct lexer* self);
|
||||
struct token* lexer_try_new_symbol(struct lexer* self);
|
||||
|
||||
bool lexer_is_sep(struct lexer* self, size_t index);
|
||||
struct token* lexer_try_new_text(struct lexer* self,
|
||||
TokenKind kind,
|
||||
char const* text);
|
||||
struct token* lexer_try_new_keyword(struct lexer* self,
|
||||
TokenKind kind,
|
||||
char const* keyword,
|
||||
char const* value);
|
||||
|
||||
struct lex_context lexer_state(struct lexer* self);
|
||||
void lexer_restore(struct lexer* self,
|
||||
struct lex_context context);
|
||||
|
||||
bool lexer_next_is(struct lexer* self,
|
||||
TokenKind kind,
|
||||
int lookahead);
|
||||
|
||||
bool lexer_end(struct lexer* self);
|
||||
#endif
|
||||
|
|
@ -0,0 +1,216 @@
|
|||
#include "moka.h"
|
||||
|
||||
void moka_init(struct moka* self)
|
||||
{
|
||||
assert(self);
|
||||
vec_init(&self->frame_stack);
|
||||
vec_init(&self->global_values);
|
||||
|
||||
struct frame* frame = malloc(sizeof(struct frame));
|
||||
frame_init(frame);
|
||||
vec_push(&self->frame_stack, frame);
|
||||
}
|
||||
|
||||
void frame_init(struct frame* self)
|
||||
{
|
||||
vec_init(&self->local_values);
|
||||
vec_init(&self->stack);
|
||||
}
|
||||
|
||||
void frame_free(struct frame* self)
|
||||
{
|
||||
assert(self);
|
||||
vec_free_elements(&self->local_values, (void*)value_free);
|
||||
vec_free(&self->local_values);
|
||||
vec_free(&self->stack);
|
||||
}
|
||||
|
||||
void moka_free(struct moka* self)
|
||||
{
|
||||
assert(self);
|
||||
vec_free_elements(&self->frame_stack, (void*) frame_free);
|
||||
vec_free(&self->frame_stack);
|
||||
vec_free(&self->global_values);
|
||||
}
|
||||
|
||||
struct frame* moka_frame(struct moka* self)
|
||||
{
|
||||
assert(self);
|
||||
assert(self->frame_stack.size > 0);
|
||||
return self->frame_stack.data[
|
||||
self->frame_stack.size - 1
|
||||
];
|
||||
}
|
||||
|
||||
bool moka_has_top(struct moka* self)
|
||||
{
|
||||
assert(self);
|
||||
struct frame* frame = moka_frame(self);
|
||||
return frame->stack.size > 0;
|
||||
}
|
||||
|
||||
MOKA moka_top(struct moka* self)
|
||||
{
|
||||
assert(self);
|
||||
struct frame* frame = moka_frame(self);
|
||||
assert(frame->stack.size > 0);
|
||||
MOKA val = (MOKA) frame->stack.data[frame->stack.size - 1];
|
||||
return val;
|
||||
}
|
||||
|
||||
bool moka_is(struct moka* self, MOKA value, TypeKind type)
|
||||
{
|
||||
return moka_type_of(self, value) == type;
|
||||
}
|
||||
|
||||
TypeKind moka_type_of(struct moka* self, MOKA value)
|
||||
{
|
||||
assert(self);
|
||||
struct frame* frame = moka_frame(self);
|
||||
struct value const* val = frame->local_values.data[value];
|
||||
return val->type;
|
||||
}
|
||||
|
||||
void moka_dump(struct moka* self, MOKA value)
|
||||
{
|
||||
if (moka_is(self, value, TY_INT))
|
||||
{
|
||||
printf("%d", moka_get_int(self, value));
|
||||
return;
|
||||
}
|
||||
|
||||
if (moka_is(self, value, TY_FLOAT))
|
||||
{
|
||||
printf("%f", moka_get_float(self, value));
|
||||
return;
|
||||
}
|
||||
|
||||
if (moka_is(self, value, TY_BOOL))
|
||||
{
|
||||
printf("%s", moka_get_bool(self, value) ? "true" : "false");
|
||||
return;
|
||||
}
|
||||
|
||||
if (moka_is(self, value, TY_STRING))
|
||||
{
|
||||
printf("%s", moka_get_string(self, value));
|
||||
return;
|
||||
}
|
||||
|
||||
if (moka_is(self, value, TY_SYMBOL))
|
||||
{
|
||||
printf("'%s", moka_get_symbol(self, value));
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr, "cannot dump value of type <%s>\n",
|
||||
TypeKindStr[moka_type_of(self, value)]
|
||||
);
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
MOKA moka_push_int(struct moka* self, int value, int line)
|
||||
{
|
||||
assert(self);
|
||||
struct frame* frame = moka_frame(self);
|
||||
struct value* val = malloc(sizeof(struct value));
|
||||
value_init_int(val, value, line);
|
||||
vec_push(&frame->local_values, val);
|
||||
size_t addr = frame->local_values.size - 1;
|
||||
vec_push(&frame->stack, (void*) addr);
|
||||
return addr;
|
||||
}
|
||||
|
||||
int moka_get_int(struct moka* self, MOKA value)
|
||||
{
|
||||
assert(self);
|
||||
struct frame* frame = moka_frame(self);
|
||||
struct value* val = frame->local_values.data[value];
|
||||
assert(val->type == TY_INT);
|
||||
return val->data.integer;
|
||||
}
|
||||
|
||||
MOKA moka_push_float(struct moka* self, float value, int line)
|
||||
{
|
||||
assert(self);
|
||||
struct frame* frame = moka_frame(self);
|
||||
struct value* val = malloc(sizeof(struct value));
|
||||
value_init_float(val, value, line);
|
||||
vec_push(&frame->local_values, val);
|
||||
size_t addr = frame->local_values.size - 1;
|
||||
vec_push(&frame->stack, (void*) addr);
|
||||
return addr;
|
||||
}
|
||||
|
||||
float moka_get_float(struct moka* self, MOKA value)
|
||||
{
|
||||
assert(self);
|
||||
struct frame* frame = moka_frame(self);
|
||||
struct value* val = frame->local_values.data[value];
|
||||
assert(val->type == TY_FLOAT);
|
||||
return val->data.real;
|
||||
}
|
||||
|
||||
MOKA moka_push_bool(struct moka* self, bool value, int line)
|
||||
{
|
||||
assert(self);
|
||||
struct frame* frame = moka_frame(self);
|
||||
struct value* val = malloc(sizeof(struct value));
|
||||
value_init_bool(val, value, line);
|
||||
vec_push(&frame->local_values, val);
|
||||
size_t addr = frame->local_values.size - 1;
|
||||
vec_push(&frame->stack, (void*) addr);
|
||||
return addr;
|
||||
}
|
||||
|
||||
float moka_get_bool(struct moka* self, MOKA value)
|
||||
{
|
||||
assert(self);
|
||||
struct frame* frame = moka_frame(self);
|
||||
struct value* val = frame->local_values.data[value];
|
||||
assert(val->type == TY_BOOL);
|
||||
return val->data.boolean;
|
||||
}
|
||||
|
||||
MOKA moka_push_string(struct moka* self, char const* value, int line)
|
||||
{
|
||||
assert(self);
|
||||
struct frame* frame = moka_frame(self);
|
||||
struct value* val = malloc(sizeof(struct value));
|
||||
value_init_string(val, value, line);
|
||||
vec_push(&frame->local_values, val);
|
||||
size_t addr = frame->local_values.size - 1;
|
||||
vec_push(&frame->stack, (void*) addr);
|
||||
return addr;
|
||||
}
|
||||
|
||||
char* moka_get_string(struct moka* self, MOKA value)
|
||||
{
|
||||
assert(self);
|
||||
struct frame* frame = moka_frame(self);
|
||||
struct value* val = frame->local_values.data[value];
|
||||
assert(val->type == TY_STRING);
|
||||
return val->data.str;
|
||||
}
|
||||
|
||||
MOKA moka_push_symbol(struct moka* self, char const* value, int line)
|
||||
{
|
||||
assert(self);
|
||||
struct frame* frame = moka_frame(self);
|
||||
struct value* val = malloc(sizeof(struct value));
|
||||
value_init_symbol(val, value, line);
|
||||
vec_push(&frame->local_values, val);
|
||||
size_t addr = frame->local_values.size - 1;
|
||||
vec_push(&frame->stack, (void*) addr);
|
||||
return addr;
|
||||
}
|
||||
|
||||
char* moka_get_symbol(struct moka* self, MOKA value)
|
||||
{
|
||||
assert(self);
|
||||
struct frame* frame = moka_frame(self);
|
||||
struct value* val = frame->local_values.data[value];
|
||||
assert(val->type == TY_SYMBOL);
|
||||
return val->data.sym;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
#ifndef MK_MOKA_H
|
||||
#define MK_MOKA_H
|
||||
|
||||
#include "commons.h"
|
||||
#include "vec.h"
|
||||
#include "value.h"
|
||||
|
||||
typedef size_t MOKA;
|
||||
|
||||
struct frame
|
||||
{
|
||||
struct vec stack;
|
||||
struct vec local_values;
|
||||
};
|
||||
|
||||
struct moka
|
||||
{
|
||||
struct vec frame_stack;
|
||||
struct vec global_values;
|
||||
};
|
||||
|
||||
void moka_init(struct moka* self);
|
||||
void frame_init(struct frame* self);
|
||||
void frame_free(struct frame* self);
|
||||
void moka_free(struct moka* self);
|
||||
|
||||
struct frame* moka_frame(struct moka* self);
|
||||
bool moka_has_top(struct moka* self);
|
||||
MOKA moka_top(struct moka* self);
|
||||
|
||||
bool moka_is(struct moka* self, MOKA value, TypeKind type);
|
||||
TypeKind moka_type_of(struct moka* self, MOKA value);
|
||||
|
||||
void moka_dump(struct moka* self, MOKA value);
|
||||
|
||||
MOKA moka_push_int(struct moka* self, int value, int line);
|
||||
int moka_get_int(struct moka* self, MOKA value);
|
||||
|
||||
MOKA moka_push_float(struct moka* self, float value, int line);
|
||||
float moka_get_float(struct moka* self, MOKA value);
|
||||
|
||||
MOKA moka_push_bool(struct moka* self, bool value, int line);
|
||||
float moka_get_bool(struct moka* self, MOKA value);
|
||||
|
||||
MOKA moka_push_string(struct moka* self, char const* value, int line);
|
||||
char* moka_get_string(struct moka* self, MOKA value);
|
||||
|
||||
MOKA moka_push_symbol(struct moka* self, char const* value, int line);
|
||||
char* moka_get_symbol(struct moka* self, MOKA value);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,69 @@
|
|||
#include "node.h"
|
||||
|
||||
MK_ENUM_C(NodeKind, NODE_KIND);
|
||||
|
||||
void node_init(struct node* self,
|
||||
NodeKind kind,
|
||||
struct token* token,
|
||||
int line)
|
||||
{
|
||||
assert(self);
|
||||
self->kind = kind;
|
||||
self->token = token;
|
||||
vec_init(&self->children);
|
||||
self->line = line;
|
||||
}
|
||||
|
||||
void node_free(struct node* self)
|
||||
{
|
||||
if (self->token)
|
||||
{
|
||||
token_free(self->token);
|
||||
free(self->token);
|
||||
}
|
||||
|
||||
vec_free_elements(&self->children, (void*) node_free);
|
||||
vec_free(&self->children);
|
||||
}
|
||||
|
||||
void node_str(struct node* self, struct str* str)
|
||||
{
|
||||
assert(self);
|
||||
assert(str);
|
||||
|
||||
str_format(str, "%s", NodeKindStr[self->kind] + strlen("NODE_"));
|
||||
|
||||
if (self->token && self->token->value)
|
||||
{
|
||||
str_format(str, "[%s]", self->token->value);
|
||||
}
|
||||
|
||||
if (self->children.size > 0)
|
||||
{
|
||||
str_push(str, '(');
|
||||
|
||||
for (size_t i=0; i<self->children.size; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
str_push(str, ',');
|
||||
}
|
||||
|
||||
struct str child_str;
|
||||
str_init(&child_str);
|
||||
|
||||
node_str(self->children.data[i], &child_str);
|
||||
str_extend(str, child_str.value);
|
||||
str_free(&child_str);
|
||||
}
|
||||
|
||||
str_push(str, ')');
|
||||
}
|
||||
}
|
||||
|
||||
void node_add_new_child(struct node* self, struct node* child)
|
||||
{
|
||||
assert(self);
|
||||
assert(child);
|
||||
vec_push(&self->children, child);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef MK_NODE_H
|
||||
#define MK_NODE_H
|
||||
|
||||
#include "commons.h"
|
||||
#include "token.h"
|
||||
#include "vec.h"
|
||||
#include "str.h"
|
||||
|
||||
#define NODE_KIND(G) \
|
||||
G(NODE_ROOT), \
|
||||
G(NODE_INT), G(NODE_FLOAT), G(NODE_BOOL), \
|
||||
G(NODE_STRING), G(NODE_SYMBOL)
|
||||
|
||||
MK_ENUM_H(NodeKind, NODE_KIND);
|
||||
|
||||
struct node
|
||||
{
|
||||
NodeKind kind;
|
||||
struct token* token;
|
||||
struct vec children;
|
||||
int line;
|
||||
};
|
||||
|
||||
void node_init(struct node* self,
|
||||
NodeKind kind,
|
||||
struct token* token,
|
||||
int line);
|
||||
|
||||
void node_free(struct node* self);
|
||||
|
||||
void node_str(struct node* self, struct str* str);
|
||||
|
||||
void node_add_new_child(struct node* self, struct node* child);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,118 @@
|
|||
#include "parser.h"
|
||||
|
||||
|
||||
#define MK_TRY(func) parser_try(self, func)
|
||||
|
||||
void parser_init(struct parser* self, struct lexer* lexer)
|
||||
{
|
||||
assert(self);
|
||||
assert(lexer);
|
||||
self->lexer = lexer;
|
||||
}
|
||||
|
||||
void parser_free(struct parser* self)
|
||||
{
|
||||
assert(self);
|
||||
}
|
||||
|
||||
struct node* parser_try_new_parse(struct parser* self)
|
||||
{
|
||||
assert(self);
|
||||
return MK_TRY(parser_try_new_root);
|
||||
}
|
||||
|
||||
struct node* parser_try(struct parser* self,
|
||||
struct node* (*rule)(struct parser*))
|
||||
{
|
||||
assert(self);
|
||||
assert(rule);
|
||||
struct lex_context ctx = lexer_state(self->lexer);
|
||||
|
||||
struct node* node = rule(self);
|
||||
|
||||
if (node == NULL)
|
||||
{
|
||||
lexer_restore(self->lexer, ctx);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
struct node* parser_try_new_root(struct parser* self)
|
||||
{
|
||||
assert(self);
|
||||
struct node* root = malloc(sizeof(struct node));
|
||||
node_init(root, NODE_ROOT, NULL, self->lexer->context.line);
|
||||
|
||||
while (!lexer_end(self->lexer))
|
||||
{
|
||||
struct node* atom = MK_TRY(parser_try_new_atom);
|
||||
if (!atom && !lexer_end(self->lexer))
|
||||
{
|
||||
node_free(root);
|
||||
free(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node_add_new_child(root, atom);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
struct node* parser_try_new_atom(struct parser* self)
|
||||
{
|
||||
assert(self);
|
||||
|
||||
if (lexer_next_is(self->lexer, TOKEN_FLOAT, 0))
|
||||
{
|
||||
struct node* node = malloc(sizeof(struct node));
|
||||
struct token* tok = lexer_try_new_next(self->lexer);
|
||||
assert(tok);
|
||||
node_init(node, NODE_FLOAT, tok,
|
||||
self->lexer->context.line);
|
||||
return node;
|
||||
}
|
||||
|
||||
if (lexer_next_is(self->lexer, TOKEN_INT, 0))
|
||||
{
|
||||
struct node* node = malloc(sizeof(struct node));
|
||||
struct token* tok = lexer_try_new_next(self->lexer);
|
||||
assert(tok);
|
||||
node_init(node, NODE_INT, tok,
|
||||
self->lexer->context.line);
|
||||
return node;
|
||||
}
|
||||
|
||||
if (lexer_next_is(self->lexer, TOKEN_BOOL, 0))
|
||||
{
|
||||
struct node* node = malloc(sizeof(struct node));
|
||||
struct token* tok = lexer_try_new_next(self->lexer);
|
||||
assert(tok);
|
||||
node_init(node, NODE_BOOL, tok,
|
||||
self->lexer->context.line);
|
||||
return node;
|
||||
}
|
||||
|
||||
if (lexer_next_is(self->lexer, TOKEN_STRING, 0))
|
||||
{
|
||||
struct node* node = malloc(sizeof(struct node));
|
||||
struct token* tok = lexer_try_new_next(self->lexer);
|
||||
assert(tok);
|
||||
node_init(node, NODE_STRING, tok,
|
||||
self->lexer->context.line);
|
||||
return node;
|
||||
}
|
||||
|
||||
if (lexer_next_is(self->lexer, TOKEN_SYMBOL, 0))
|
||||
{
|
||||
struct node* node = malloc(sizeof(struct node));
|
||||
struct token* tok = lexer_try_new_next(self->lexer);
|
||||
assert(tok);
|
||||
node_init(node, NODE_SYMBOL, tok,
|
||||
self->lexer->context.line);
|
||||
return node;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef MK_PARSER_H
|
||||
#define MK_PARSER_H
|
||||
|
||||
#include "commons.h"
|
||||
#include "node.h"
|
||||
#include "lexer.h"
|
||||
|
||||
struct parser
|
||||
{
|
||||
struct lexer* lexer;
|
||||
};
|
||||
|
||||
void parser_init(struct parser* self, struct lexer* lexer);
|
||||
void parser_free(struct parser* self);
|
||||
|
||||
struct node* parser_try_new_parse(struct parser* self);
|
||||
|
||||
struct node* parser_try(struct parser* self,
|
||||
struct node* (*rule)(struct parser*));
|
||||
|
||||
struct node* parser_try_new_root(struct parser* self);
|
||||
struct node* parser_try_new_atom(struct parser* self);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,60 @@
|
|||
#include "prog.h"
|
||||
|
||||
MK_ENUM_C(OpcodeKind, OPCODE_KIND);
|
||||
|
||||
void prog_init(struct prog* self)
|
||||
{
|
||||
assert(self);
|
||||
vec_init(&self->instructions);
|
||||
vec_init(&self->values);
|
||||
}
|
||||
|
||||
void prog_free(struct prog* self)
|
||||
{
|
||||
assert(self);
|
||||
vec_free_elements(&self->instructions, NULL);
|
||||
vec_free(&self->instructions);
|
||||
|
||||
vec_free_elements(&self->values, (void*) value_free);
|
||||
vec_free(&self->values);
|
||||
}
|
||||
|
||||
size_t prog_add_instruction(struct prog* self,
|
||||
OpcodeKind opcode,
|
||||
ssize_t param)
|
||||
{
|
||||
assert(self);
|
||||
struct instruction* instr = malloc(sizeof(struct instruction));
|
||||
instr->opcode = opcode;
|
||||
instr->param = param;
|
||||
|
||||
vec_push(&self->instructions, instr);
|
||||
|
||||
return self->instructions.size - 1;
|
||||
}
|
||||
|
||||
size_t prog_add_new_value(struct prog* self,
|
||||
struct value* value)
|
||||
{
|
||||
assert(self);
|
||||
assert(value);
|
||||
|
||||
vec_push(&self->values, value);
|
||||
|
||||
return self->values.size - 1;
|
||||
}
|
||||
|
||||
void prog_dump(struct prog* self)
|
||||
{
|
||||
assert(self);
|
||||
|
||||
printf("--- PROG ---\n");
|
||||
for (size_t i=0; i<self->instructions.size; i++)
|
||||
{
|
||||
struct instruction const* instr = self->instructions.data[i];
|
||||
printf("%zu\t%s %zd\n",
|
||||
i,
|
||||
OpcodeKindStr[instr->opcode],
|
||||
instr->param);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef MK_PROG_H
|
||||
#define MK_PROG_H
|
||||
|
||||
#include "commons.h"
|
||||
#include "vec.h"
|
||||
#include "value.h"
|
||||
|
||||
#define OPCODE_KIND(G) \
|
||||
G(OP_PUSH)
|
||||
|
||||
MK_ENUM_H(OpcodeKind, OPCODE_KIND);
|
||||
|
||||
struct instruction
|
||||
{
|
||||
OpcodeKind opcode;
|
||||
ssize_t param;
|
||||
};
|
||||
|
||||
struct prog
|
||||
{
|
||||
struct vec instructions;
|
||||
struct vec values;
|
||||
};
|
||||
|
||||
void prog_init(struct prog* self);
|
||||
void prog_free(struct prog* self);
|
||||
|
||||
size_t prog_add_instruction(struct prog* self,
|
||||
OpcodeKind opcode,
|
||||
ssize_t param);
|
||||
|
||||
size_t prog_add_new_value(struct prog* self,
|
||||
struct value* value);
|
||||
|
||||
void prog_dump(struct prog* self);
|
||||
|
||||
#endif
|
10
lib/status.c
10
lib/status.c
|
@ -4,13 +4,15 @@ MK_ENUM_C(Status, STATUS_KIND);
|
|||
|
||||
void message_init(struct message* self,
|
||||
Status kind,
|
||||
char const* what)
|
||||
char const* what,
|
||||
int where)
|
||||
{
|
||||
assert(self);
|
||||
assert(what);
|
||||
|
||||
self->kind = kind;
|
||||
self->what = strdup(what);
|
||||
self->where = where;
|
||||
}
|
||||
|
||||
void message_free(struct message* self)
|
||||
|
@ -33,6 +35,7 @@ void status_free(struct status* self)
|
|||
}
|
||||
void status_push(struct status* self,
|
||||
Status kind,
|
||||
int where,
|
||||
char const* format,
|
||||
...)
|
||||
{
|
||||
|
@ -43,7 +46,7 @@ void status_push(struct status* self,
|
|||
vsnprintf(msg, MK_STRLEN, format, lst);
|
||||
|
||||
struct message* message = malloc(sizeof(struct message));
|
||||
message_init(message, kind, msg);
|
||||
message_init(message, kind, msg, where);
|
||||
|
||||
vec_push(&self->messages, message);
|
||||
va_end(lst);
|
||||
|
@ -57,8 +60,9 @@ void status_dump(struct status* self)
|
|||
{
|
||||
struct message const* msg = self->messages.data[i];
|
||||
|
||||
printf("%s| %s\n",
|
||||
printf("[%s:%d] %s\n",
|
||||
StatusStr[msg->kind] + strlen("STATUS_"),
|
||||
msg->where,
|
||||
msg->what
|
||||
);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ struct message
|
|||
{
|
||||
Status kind;
|
||||
char* what;
|
||||
int where;
|
||||
};
|
||||
|
||||
struct status
|
||||
|
@ -23,7 +24,8 @@ struct status
|
|||
|
||||
void message_init(struct message* self,
|
||||
Status kind,
|
||||
char const* what);
|
||||
char const* what,
|
||||
int where);
|
||||
void message_free(struct message* self);
|
||||
|
||||
void status_init(struct status* self);
|
||||
|
@ -31,6 +33,7 @@ void status_free(struct status* self);
|
|||
|
||||
void status_push(struct status* self,
|
||||
Status kind,
|
||||
int where,
|
||||
char const* format,
|
||||
...);
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
#include "token.h"
|
||||
|
||||
MK_ENUM_C(TokenKind, TOKEN_KIND);
|
||||
|
||||
void token_init(struct token* self, TokenKind kind, char const* value)
|
||||
{
|
||||
assert(self);
|
||||
self->kind = kind;
|
||||
self->value = strdup(value);
|
||||
}
|
||||
|
||||
void token_free(struct token* self)
|
||||
{
|
||||
assert(self);
|
||||
free(self->value);
|
||||
self->value = NULL;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef MK_TOKEN_H
|
||||
#define MK_TOKEN_H
|
||||
|
||||
#include "commons.h"
|
||||
|
||||
#define TOKEN_KIND(G) \
|
||||
G(TOKEN_INT), G(TOKEN_FLOAT), \
|
||||
G(TOKEN_BOOL), G(TOKEN_STRING), \
|
||||
G(TOKEN_SYMBOL)
|
||||
|
||||
MK_ENUM_H(TokenKind, TOKEN_KIND);
|
||||
|
||||
struct token
|
||||
{
|
||||
TokenKind kind;
|
||||
char* value;
|
||||
int line;
|
||||
};
|
||||
|
||||
void token_init(struct token* self,
|
||||
TokenKind kind,
|
||||
char const* value);
|
||||
void token_free(struct token* self);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,61 @@
|
|||
#include "value.h"
|
||||
|
||||
MK_ENUM_C(TypeKind, TYPE_KIND);
|
||||
|
||||
void value_init_int(struct value* self, int value, int line)
|
||||
{
|
||||
assert(self);
|
||||
self->data.integer = value;
|
||||
self->type = TY_INT;
|
||||
self->line = line;
|
||||
}
|
||||
|
||||
void value_init_float(struct value* self, float value, int line)
|
||||
{
|
||||
assert(self);
|
||||
self->data.real = value;
|
||||
self->type = TY_FLOAT;
|
||||
self->line = line;
|
||||
}
|
||||
|
||||
void value_init_bool(struct value* self, bool value, int line)
|
||||
{
|
||||
assert(self);
|
||||
self->data.boolean = value;
|
||||
self->type = TY_BOOL;
|
||||
self->line = line;
|
||||
}
|
||||
|
||||
void value_init_string(struct value* self, char const* value, int line)
|
||||
{
|
||||
assert(self);
|
||||
assert(value);
|
||||
self->data.str = strdup(value);
|
||||
self->type = TY_STRING;
|
||||
self->line = line;
|
||||
}
|
||||
|
||||
void value_init_symbol(struct value* self, char const* value, int line)
|
||||
{
|
||||
assert(self);
|
||||
assert(value);
|
||||
self->data.sym = strdup(value);
|
||||
self->type = TY_SYMBOL;
|
||||
self->line = line;
|
||||
}
|
||||
|
||||
void value_free(struct value* self)
|
||||
{
|
||||
assert(self);
|
||||
|
||||
if (self->type == TY_STRING)
|
||||
{
|
||||
free(self->data.str);
|
||||
}
|
||||
|
||||
if (self->type == TY_SYMBOL)
|
||||
{
|
||||
free(self->data.sym);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef MK_VALUE_H
|
||||
#define MK_VALUE_H
|
||||
|
||||
#include "commons.h"
|
||||
|
||||
#define TYPE_KIND(G) \
|
||||
G(TY_INT), G(TY_FLOAT), G(TY_BOOL), \
|
||||
G(TY_STRING), G(TY_SYMBOL)
|
||||
|
||||
MK_ENUM_H(TypeKind, TYPE_KIND);
|
||||
|
||||
union value_data
|
||||
{
|
||||
int integer;
|
||||
float real;
|
||||
bool boolean;
|
||||
char* str;
|
||||
char* sym;
|
||||
};
|
||||
|
||||
struct value
|
||||
{
|
||||
union value_data data;
|
||||
TypeKind type;
|
||||
int line;
|
||||
};
|
||||
|
||||
void value_init_int(struct value* self, int value, int line);
|
||||
void value_init_float(struct value* self, float value, int line);
|
||||
void value_init_bool(struct value* self, bool value, int line);
|
||||
void value_init_string(struct value* self, char const* value, int line);
|
||||
void value_init_symbol(struct value* self, char const* value, int line);
|
||||
void value_free(struct value* self);
|
||||
|
||||
#endif
|
|
@ -35,7 +35,6 @@ void vec_free(struct vec* self)
|
|||
void vec_push(struct vec* self, void* element)
|
||||
{
|
||||
assert(self);
|
||||
assert(element);
|
||||
|
||||
if (self->capacity == 0)
|
||||
{
|
||||
|
|
88
src/main.c
88
src/main.c
|
@ -1,4 +1,88 @@
|
|||
int main()
|
||||
#include <status.h>
|
||||
#include <str.h>
|
||||
#include <lexer.h>
|
||||
#include <parser.h>
|
||||
#include <compiler.h>
|
||||
#include <exec.h>
|
||||
#include <moka.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
return 0;
|
||||
if (argc <= 1) { return EXIT_FAILURE; }
|
||||
|
||||
struct status status;
|
||||
status_init(&status);
|
||||
|
||||
struct str source;
|
||||
str_init(&source);
|
||||
|
||||
{
|
||||
FILE* file = fopen(argv[1], "r+");
|
||||
size_t sz;
|
||||
char buf;
|
||||
while ( (sz=fread(&buf, sizeof(char), 1, file)) )
|
||||
{
|
||||
str_push(&source, buf);
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
struct lexer lex;
|
||||
lexer_init(&lex, source.value, &status);
|
||||
|
||||
struct parser parser;
|
||||
parser_init(&parser, &lex);
|
||||
struct node* root = parser_try_new_root(&parser);
|
||||
|
||||
if (!root || !status_is_ok(&status))
|
||||
{
|
||||
status_dump(&status);
|
||||
goto free_parser;
|
||||
}
|
||||
|
||||
struct compiler compiler;
|
||||
compiler_init(&compiler, &status);
|
||||
|
||||
struct prog prog;
|
||||
prog_init(&prog);
|
||||
|
||||
compiler_compile(&compiler, root, &prog);
|
||||
|
||||
if (!status_is_ok(&status))
|
||||
{
|
||||
status_dump(&status);
|
||||
goto free_compiler;
|
||||
}
|
||||
|
||||
struct moka moka;
|
||||
moka_init(&moka);
|
||||
|
||||
struct exec exec;
|
||||
exec_init(&exec);
|
||||
|
||||
exec_prog(&exec, &moka, &prog);
|
||||
|
||||
if (moka_has_top(&moka))
|
||||
{
|
||||
MOKA value = moka_top(&moka);
|
||||
moka_dump(&moka, value);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
exec_free(&exec);
|
||||
moka_free(&moka);
|
||||
prog_free(&prog);
|
||||
free_compiler:
|
||||
compiler_free(&compiler);
|
||||
node_free(root);
|
||||
free(root);
|
||||
free_parser:
|
||||
parser_free(&parser);
|
||||
lexer_free(&lex);
|
||||
str_free(&source);
|
||||
|
||||
int ret = status_is_ok(&status) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
status_free(&status);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
#ifndef MK_TEST_LEXER_H
|
||||
#define MK_TEST_LEXER_H
|
||||
#include <commons.h>
|
||||
#include <lexer.h>
|
||||
#include <check.h>
|
||||
|
||||
static void test_lexer(char const* source, int n, ...)
|
||||
{
|
||||
va_list lst;
|
||||
va_start(lst, n);
|
||||
|
||||
struct status status;
|
||||
status_init(&status);
|
||||
|
||||
struct lexer lex;
|
||||
lexer_init(&lex, source, &status);
|
||||
|
||||
for (int i=0; i<n; i++)
|
||||
{
|
||||
TokenKind kind = va_arg(lst, TokenKind);
|
||||
char const* oracle = va_arg(lst, char const*);
|
||||
|
||||
struct token* tok;
|
||||
tok = lexer_try_new_next(&lex);
|
||||
bool ok = status_is_ok(&status);
|
||||
if (!ok)
|
||||
{
|
||||
status_dump(&status);
|
||||
}
|
||||
ck_assert(ok);
|
||||
ck_assert_msg(tok != NULL, "expected %s of value %s, got nothing",
|
||||
TokenKindStr[kind] + strlen("TOKEN_"),
|
||||
oracle);
|
||||
ck_assert_str_eq(oracle, tok->value);
|
||||
ck_assert_int_eq(kind, tok->kind);
|
||||
token_free(tok);
|
||||
free(tok);
|
||||
}
|
||||
|
||||
status_free(&status);
|
||||
|
||||
lexer_free(&lex);
|
||||
va_end(lst);
|
||||
}
|
||||
|
||||
START_TEST(lexer_atom)
|
||||
{
|
||||
test_lexer(" 34 -2 0 ", 3,
|
||||
TOKEN_INT, "34",
|
||||
TOKEN_INT, "-2",
|
||||
TOKEN_INT, "0"
|
||||
);
|
||||
|
||||
test_lexer(" 3.4 -2.2 .6 7. ", 4,
|
||||
TOKEN_FLOAT, "3.4",
|
||||
TOKEN_FLOAT, "-2.2",
|
||||
TOKEN_FLOAT, ".6",
|
||||
TOKEN_FLOAT, "7."
|
||||
);
|
||||
|
||||
test_lexer(" true false ", 2,
|
||||
TOKEN_BOOL, "true",
|
||||
TOKEN_BOOL, "false"
|
||||
);
|
||||
|
||||
test_lexer(" \"\\\\hel\\rlo\" \"wo\\trld\\n\" \" \\\"bim\\\" \" ", 3,
|
||||
TOKEN_STRING, "\\hel\rlo",
|
||||
TOKEN_STRING, "wo\trld\n",
|
||||
TOKEN_STRING, " \"bim\" "
|
||||
);
|
||||
|
||||
test_lexer(" 'hello ", 1,
|
||||
TOKEN_SYMBOL, "hello"
|
||||
);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void register_lexer(Suite* suite)
|
||||
{
|
||||
TCase* tcase = tcase_create("Lexer");
|
||||
tcase_add_test(tcase, lexer_atom);
|
||||
suite_add_tcase(suite, tcase);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,11 +1,14 @@
|
|||
#include <commons.h>
|
||||
#include <check.h>
|
||||
|
||||
#include "lexer.h"
|
||||
#include "parser.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
Suite* s = suite_create("Moka Frontend");
|
||||
|
||||
register_lexer(s);
|
||||
register_parser(s);
|
||||
|
||||
SRunner* runner = srunner_create(s);
|
||||
srunner_run_all(runner, CK_VERBOSE);
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
#ifndef MK_TEST_PARSER_H
|
||||
#define MK_TEST_PARSER_H
|
||||
#include <check.h>
|
||||
#include <commons.h>
|
||||
#include <lexer.h>
|
||||
#include <parser.h>
|
||||
|
||||
void test_parser(char const* oracle, char const* source)
|
||||
{
|
||||
struct status status;
|
||||
status_init(&status);
|
||||
|
||||
struct lexer lex;
|
||||
lexer_init(&lex, source, &status);
|
||||
|
||||
struct parser parser;
|
||||
parser_init(&parser, &lex);
|
||||
|
||||
struct node* ast = parser_try_new_parse(&parser);
|
||||
ck_assert(ast);
|
||||
|
||||
struct str my_node_str;
|
||||
str_init(&my_node_str);
|
||||
node_str(ast, &my_node_str);
|
||||
|
||||
ck_assert_str_eq(oracle, my_node_str.value);
|
||||
|
||||
bool ok = status_is_ok(&status);
|
||||
if (!ok)
|
||||
{
|
||||
status_dump(&status);
|
||||
}
|
||||
ck_assert(ok);
|
||||
|
||||
str_free(&my_node_str);
|
||||
node_free(ast);
|
||||
free(ast);
|
||||
parser_free(&parser);
|
||||
lexer_free(&lex);
|
||||
status_free(&status);
|
||||
}
|
||||
|
||||
START_TEST(parser_atom)
|
||||
{
|
||||
test_parser("ROOT(INT[34])",
|
||||
" 34 ");
|
||||
|
||||
test_parser("ROOT(FLOAT[0.8])",
|
||||
" 0.8 ");
|
||||
|
||||
test_parser("ROOT(BOOL[true],BOOL[false])",
|
||||
" true false ");
|
||||
|
||||
test_parser("ROOT(STRING[pizza!])",
|
||||
" \"pizza!\" ");
|
||||
|
||||
test_parser("ROOT(SYMBOL[tea])",
|
||||
" 'tea ");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void register_parser(Suite* suite)
|
||||
{
|
||||
TCase* tcase = tcase_create("Parser");
|
||||
tcase_add_test(tcase, parser_atom);
|
||||
|
||||
suite_add_tcase(suite, tcase);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue