More progress on the assembler
This commit is contained in:
@@ -1,2 +1,2 @@
|
|||||||
all:
|
all:
|
||||||
gcc src/basic.c src/file.c src/parse.c src/main.c -o wl -Wall -Wextra -O0 -g3
|
gcc src/basic.c src/file.c src/parse.c src/assemble.c src/main.c -o wl -Wall -Wextra -O0 -g3
|
||||||
+130
-25
@@ -1,3 +1,8 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
#include "assemble.h"
|
#include "assemble.h"
|
||||||
|
|
||||||
@@ -54,15 +59,42 @@ typedef struct {
|
|||||||
int strings_cap;
|
int strings_cap;
|
||||||
char *strings;
|
char *strings;
|
||||||
|
|
||||||
|
char *errbuf;
|
||||||
|
int errmax;
|
||||||
|
int errlen;
|
||||||
|
|
||||||
} Assembler;
|
} Assembler;
|
||||||
|
|
||||||
|
void assembler_report(Assembler *a, char *fmt, ...)
|
||||||
|
{
|
||||||
|
if (a->errmax == 0 || a->errlen > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int len = snprintf(a->errbuf, a->errmax, "Error: ");
|
||||||
|
if (len < 0) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
int ret = vsnprintf(a->errbuf + len, a->errmax - len, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
if (ret < 0) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
len += ret;
|
||||||
|
|
||||||
|
a->errlen = len;
|
||||||
|
}
|
||||||
|
|
||||||
int add_string_literal(Assembler *a, String str)
|
int add_string_literal(Assembler *a, String str)
|
||||||
{
|
{
|
||||||
if (a->strings_cap - a->strings_len < str.len) {
|
if (a->strings_cap - a->strings_len < str.len) {
|
||||||
int c = MAX(2 * a->strings_cap, a->strings_len + str.len);
|
int c = MAX(2 * a->strings_cap, a->strings_len + str.len);
|
||||||
char *p = malloc(c);
|
char *p = malloc(c);
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
// TODO
|
assembler_report(a, "Out of memory");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
if (a->strings_cap) {
|
if (a->strings_cap) {
|
||||||
memcpy(p, a->strings, a->strings_len);
|
memcpy(p, a->strings, a->strings_len);
|
||||||
@@ -129,6 +161,13 @@ int append_u32(OutputBuffer *out, uint32_t x)
|
|||||||
return off;
|
return off;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int append_u64(OutputBuffer *out, uint64_t x)
|
||||||
|
{
|
||||||
|
int off = out->len;
|
||||||
|
append_mem(out, &x, (int) sizeof(x));
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
|
||||||
int append_f64(OutputBuffer *out, double x)
|
int append_f64(OutputBuffer *out, double x)
|
||||||
{
|
{
|
||||||
int off = out->len;
|
int off = out->len;
|
||||||
@@ -142,6 +181,11 @@ void patch_with_current_offset(OutputBuffer *out, int off)
|
|||||||
patch_mem(out, off, &x, (int) sizeof(x));
|
patch_mem(out, off, &x, (int) sizeof(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int current_offset(OutputBuffer *out)
|
||||||
|
{
|
||||||
|
return out->len;
|
||||||
|
}
|
||||||
|
|
||||||
int count_nodes(Node *head)
|
int count_nodes(Node *head)
|
||||||
{
|
{
|
||||||
int n = 0;
|
int n = 0;
|
||||||
@@ -153,16 +197,36 @@ int count_nodes(Node *head)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
int declare_var(Assembler *a, String name)
|
int find_variable(Assembler *a, String name)
|
||||||
{
|
{
|
||||||
if (a->num_vars == MAX_VARS)
|
Scope *scope = &a->scopes[a->num_scopes-1];
|
||||||
return -1;
|
for (int i = scope->var_base; i < a->num_vars; i++)
|
||||||
// TODO: check if the variable exists already
|
if (streq(name, a->vars[i].name))
|
||||||
int idx = a->num_vars++;
|
return i;
|
||||||
a->vars[idx] = (Variable) { name };
|
assembler_report(a, "Undeclared variable '%.*s'", name.len, name.ptr);
|
||||||
return idx - a->scopes[a->num_scopes-1].var_base;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int declare_var(Assembler *a, String name)
|
||||||
|
{
|
||||||
|
if (a->num_vars == MAX_VARS) {
|
||||||
|
assembler_report(a, "Variable limit reached");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scope *scope = &a->scopes[a->num_scopes-1];
|
||||||
|
for (int i = scope->var_base; i < a->num_vars; i++)
|
||||||
|
if (streq(name, a->vars[i].name)) {
|
||||||
|
assembler_report(a, "Variable '%.*s' declared twice", name.len, name.ptr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = a->num_vars++;
|
||||||
|
a->vars[idx] = (Variable) { name };
|
||||||
|
return idx - scope->var_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
void assemble_html_node_inner(Assembler *a, Node *node, OutputBuffer *tmp)
|
void assemble_html_node_inner(Assembler *a, Node *node, OutputBuffer *tmp)
|
||||||
{
|
{
|
||||||
append_u8(tmp, '<');
|
append_u8(tmp, '<');
|
||||||
@@ -197,6 +261,41 @@ void assemble_html_node(Assembler *a, Node *node)
|
|||||||
OutputBuffer tmp;
|
OutputBuffer tmp;
|
||||||
assemble_html_node_inner(a, node, &tmp);
|
assemble_html_node_inner(a, node, &tmp);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
b32 is_expr(Node *node)
|
||||||
|
{
|
||||||
|
switch (node->type) {
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NODE_SELECT:
|
||||||
|
case NODE_FUNC_CALL:
|
||||||
|
case NODE_OPER_POS:
|
||||||
|
case NODE_OPER_NEG:
|
||||||
|
case NODE_OPER_ASS:
|
||||||
|
case NODE_OPER_EQL:
|
||||||
|
case NODE_OPER_NQL:
|
||||||
|
case NODE_OPER_LSS:
|
||||||
|
case NODE_OPER_GRT:
|
||||||
|
case NODE_OPER_ADD:
|
||||||
|
case NODE_OPER_SUB:
|
||||||
|
case NODE_OPER_MUL:
|
||||||
|
case NODE_OPER_DIV:
|
||||||
|
case NODE_OPER_MOD:
|
||||||
|
case NODE_VALUE_INT:
|
||||||
|
case NODE_VALUE_FLOAT:
|
||||||
|
case NODE_VALUE_STR:
|
||||||
|
case NODE_VALUE_VAR:
|
||||||
|
case NODE_VALUE_HTML:
|
||||||
|
case NODE_VALUE_ARRAY:
|
||||||
|
case NODE_VALUE_MAP:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void assemble_node(Assembler *a, Node *node)
|
void assemble_node(Assembler *a, Node *node)
|
||||||
{
|
{
|
||||||
@@ -213,14 +312,15 @@ void assemble_node(Assembler *a, Node *node)
|
|||||||
|
|
||||||
Node *args[32];
|
Node *args[32];
|
||||||
if (arg_count > COUNT(args)) {
|
if (arg_count > COUNT(args)) {
|
||||||
// TODO
|
assembler_report(a, "Argument limit reached");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = arg_count-1; i >= 0; i--) {
|
for (int i = arg_count-1; i >= 0; i--) {
|
||||||
|
|
||||||
int idx = declare_var(a, args[i]->sval);
|
int idx = declare_var(a, args[i]->sval);
|
||||||
if (idx < 0) {
|
if (idx < 0) return;
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
append_u8(&a->out, OPCODE_SETV);
|
append_u8(&a->out, OPCODE_SETV);
|
||||||
append_u8(&a->out, idx);
|
append_u8(&a->out, idx);
|
||||||
}
|
}
|
||||||
@@ -256,7 +356,8 @@ void assemble_node(Assembler *a, Node *node)
|
|||||||
|
|
||||||
FunctionCall *call = alloc(a->a, sizeof(FunctionCall), _Alignof(FunctionCall));
|
FunctionCall *call = alloc(a->a, sizeof(FunctionCall), _Alignof(FunctionCall));
|
||||||
if (call == NULL) {
|
if (call == NULL) {
|
||||||
// TODO
|
assembler_report(a, "Out of memory");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
call->name = func->sval;
|
call->name = func->sval;
|
||||||
call->off = p;
|
call->off = p;
|
||||||
@@ -278,9 +379,7 @@ void assemble_node(Assembler *a, Node *node)
|
|||||||
case NODE_VAR_DECL:
|
case NODE_VAR_DECL:
|
||||||
{
|
{
|
||||||
int idx = declare_var(a, node->var_name);
|
int idx = declare_var(a, node->var_name);
|
||||||
if (idx < 0) {
|
if (idx < 0) return;
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node->var_value) {
|
if (node->var_value) {
|
||||||
assemble_node(a, node->var_value);
|
assemble_node(a, node->var_value);
|
||||||
@@ -375,7 +474,7 @@ void assemble_node(Assembler *a, Node *node)
|
|||||||
assemble_node(a, node->left);
|
assemble_node(a, node->left);
|
||||||
|
|
||||||
append_u8(&a->out, OPCODE_JUMP);
|
append_u8(&a->out, OPCODE_JUMP);
|
||||||
opcode_u32(&a->out, start);
|
append_u32(&a->out, start);
|
||||||
|
|
||||||
patch_with_current_offset(&a->out, p);
|
patch_with_current_offset(&a->out, p);
|
||||||
}
|
}
|
||||||
@@ -476,7 +575,8 @@ void assemble_node(Assembler *a, Node *node)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_VALUE_HTML:
|
case NODE_VALUE_HTML:
|
||||||
assemble_html_node(a, node);
|
// TODO
|
||||||
|
//assemble_html_node(a, node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_VALUE_ARRAY:
|
case NODE_VALUE_ARRAY:
|
||||||
@@ -526,10 +626,8 @@ void assemble_node(Assembler *a, Node *node)
|
|||||||
|
|
||||||
if (dst->type == NODE_VALUE_VAR) {
|
if (dst->type == NODE_VALUE_VAR) {
|
||||||
|
|
||||||
int idx = find_variable(dst->sval);
|
int idx = find_variable(a, dst->sval);
|
||||||
if (idx < 0) {
|
if (idx < 0) return;
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
assemble_node(a, src);
|
assemble_node(a, src);
|
||||||
append_u8(&a->out, OPCODE_SETV);
|
append_u8(&a->out, OPCODE_SETV);
|
||||||
@@ -544,18 +642,25 @@ void assemble_node(Assembler *a, Node *node)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// TODO ERROR
|
assembler_report(a, "Assignment left side can't be assigned to");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AssembleResult assemble(Node *root)
|
AssembleResult assemble(Node *root, char *errbuf, int errmax)
|
||||||
{
|
{
|
||||||
Assembler a = {0};
|
Assembler a = {0, .errbuf=errbuf, .errmax=errmax, .errlen=0};
|
||||||
assemble_node(&a, root);
|
assemble_node(&a, root);
|
||||||
append_u8(&a.out, OPCODE_NOPE);
|
append_u8(&a.out, OPCODE_NOPE);
|
||||||
|
|
||||||
|
Program p;
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
|
return (AssembleResult) { p, a.errlen };
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -41,8 +41,9 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Program program;
|
Program program;
|
||||||
|
int errlen;
|
||||||
} AssembleResult;
|
} AssembleResult;
|
||||||
|
|
||||||
AssembleResult assemble(Node *root);
|
AssembleResult assemble(Node *root, char *errbuf, int errmax);
|
||||||
|
|
||||||
#endif // WL_ASSEMBLE_INCLUDED
|
#endif // WL_ASSEMBLE_INCLUDED
|
||||||
@@ -25,6 +25,9 @@ typedef struct {
|
|||||||
#define S(X) (String) { (X), (int) sizeof(X)-1 }
|
#define S(X) (String) { (X), (int) sizeof(X)-1 }
|
||||||
|
|
||||||
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
|
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
|
||||||
|
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
|
||||||
|
|
||||||
|
#define COUNT(X) (int) (sizeof(X) / sizeof((X)[0]))
|
||||||
|
|
||||||
b32 is_space(char c);
|
b32 is_space(char c);
|
||||||
b32 is_digit(char c);
|
b32 is_digit(char c);
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@
|
|||||||
int file_open(String path, File *handle, int *size)
|
int file_open(String path, File *handle, int *size)
|
||||||
{
|
{
|
||||||
char zt[1<<10];
|
char zt[1<<10];
|
||||||
if (path.len >= (int) sizeof(zt))
|
if (path.len >= COUNT(zt))
|
||||||
return -1;
|
return -1;
|
||||||
memcpy(zt, path.ptr, path.len);
|
memcpy(zt, path.ptr, path.len);
|
||||||
zt[path.len] = '\0';
|
zt[path.len] = '\0';
|
||||||
|
|||||||
+2
-2
@@ -15,9 +15,9 @@ int main(void)
|
|||||||
|
|
||||||
char err[1<<9];
|
char err[1<<9];
|
||||||
char mem[1<<14];
|
char mem[1<<14];
|
||||||
Arena a = { mem, (int) sizeof(mem), 0 };
|
Arena a = { mem, COUNT(mem), 0 };
|
||||||
|
|
||||||
ParseResult result = parse(src, &a, err, (int) sizeof(err));
|
ParseResult result = parse(src, &a, err, COUNT(err));
|
||||||
if (result.node == NULL) {
|
if (result.node == NULL) {
|
||||||
printf("%.*s\n", result.errlen, err);
|
printf("%.*s\n", result.errlen, err);
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
+1
-1
@@ -837,7 +837,7 @@ Node *parse_atom(Parser *p)
|
|||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
char buf[1<<8];
|
char buf[1<<8];
|
||||||
String str = tok2str(t, buf, (int) sizeof(buf));
|
String str = tok2str(t, buf, COUNT(buf));
|
||||||
report(p, "Invalid token \'%.*s\' inside expression", str.len, str.ptr);
|
report(p, "Invalid token \'%.*s\' inside expression", str.len, str.ptr);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
Reference in New Issue
Block a user