Improve assembler
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
all:
|
||||
gcc src/basic.c src/file.c src/parse.c src/assemble.c src/main.c -o wl -Wall -Wextra -O0 -g3
|
||||
gcc src/basic.c src/file.c src/parse.c src/assemble.c src/eval.c src/main.c -o wl -Wall -Wextra -O0 -g3
|
||||
@@ -1,6 +1,7 @@
|
||||
title = "My Website"
|
||||
|
||||
posts = [
|
||||
let title = "My Website"
|
||||
|
||||
let posts = [
|
||||
{
|
||||
name: "Post Title 1",
|
||||
date: "1 Jan 2025",
|
||||
@@ -21,7 +22,7 @@ posts = [
|
||||
|
||||
fun render_comment(c)
|
||||
<div class="comment">
|
||||
<a>\{c.author} (\c.date)</a>
|
||||
<a>\c.author (\c.date)</a>
|
||||
<p>\c.content</p>
|
||||
<div class="comment-children">
|
||||
\for child in c.children:
|
||||
@@ -34,11 +35,12 @@ fun render_comment(c)
|
||||
<title>\title</title>
|
||||
</head>
|
||||
<body>
|
||||
<a>This is regular text</a>
|
||||
\for post in posts:
|
||||
<div class="post">
|
||||
<a>\{post.title} (\post.date)</a>
|
||||
<a>\post.title (\post.date)</a>
|
||||
\for comment in post.comments:
|
||||
render_comment(comment)
|
||||
render_comment(comment)
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+487
-70
@@ -2,15 +2,15 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef WL_AMALGAMATION
|
||||
#include "parse.h"
|
||||
#include "assemble.h"
|
||||
#endif
|
||||
|
||||
#define MAX_SCOPES 32
|
||||
#define MAX_VARS 1024
|
||||
#define MAX_STRING_LITERALS 1024
|
||||
#define MAX_SCOPES 32
|
||||
#define MAX_SYMBOLS 1024
|
||||
|
||||
typedef struct FunctionCall FunctionCall;
|
||||
struct FunctionCall {
|
||||
@@ -19,23 +19,31 @@ struct FunctionCall {
|
||||
int off;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
SYMBOL_VAR,
|
||||
SYMBOL_FUNC,
|
||||
} SymbolType;
|
||||
|
||||
typedef struct {
|
||||
String name;
|
||||
} Variable;
|
||||
SymbolType type;
|
||||
String name;
|
||||
int off;
|
||||
} Symbol;
|
||||
|
||||
typedef enum {
|
||||
SCOPE_GLOBAL,
|
||||
SCOPE_FUNC,
|
||||
SCOPE_FOR,
|
||||
SCOPE_WHILE,
|
||||
SCOPE_IF,
|
||||
SCOPE_ELSE,
|
||||
SCOPE_BLOCK,
|
||||
} ScopeType;
|
||||
|
||||
typedef struct {
|
||||
ScopeType type;
|
||||
int var_base;
|
||||
// TODO
|
||||
FunctionCall *calls;
|
||||
ScopeType type;
|
||||
int sym_base;
|
||||
FunctionCall* calls;
|
||||
} Scope;
|
||||
|
||||
typedef struct {
|
||||
@@ -51,8 +59,8 @@ typedef struct {
|
||||
|
||||
OutputBuffer out;
|
||||
|
||||
int num_vars;
|
||||
Variable vars[MAX_VARS];
|
||||
int num_syms;
|
||||
Symbol syms[MAX_SYMBOLS];
|
||||
|
||||
int num_scopes;
|
||||
Scope scopes[MAX_SCOPES];
|
||||
@@ -183,6 +191,11 @@ void patch_with_current_offset(OutputBuffer *out, int off)
|
||||
patch_mem(out, off, &x, (int) sizeof(x));
|
||||
}
|
||||
|
||||
void patch_u32(OutputBuffer *out, int off, uint32_t x)
|
||||
{
|
||||
patch_mem(out, off, &x, (int) sizeof(x));
|
||||
}
|
||||
|
||||
int current_offset(OutputBuffer *out)
|
||||
{
|
||||
return out->len;
|
||||
@@ -199,33 +212,63 @@ int count_nodes(Node *head)
|
||||
return n;
|
||||
}
|
||||
|
||||
int find_variable(Assembler *a, String name)
|
||||
int find_symbol_in_local_scope(Assembler *a, String name)
|
||||
{
|
||||
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))
|
||||
for (int i = a->num_syms-1; i >= a->scopes[a->num_scopes-1].sym_base; i--)
|
||||
if (streq(a->syms[i].name, name))
|
||||
return i;
|
||||
assembler_report(a, "Undeclared variable '%.*s'", name.len, name.ptr);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int declare_var(Assembler *a, String name)
|
||||
int find_symbol_in_function(Assembler *a, String name)
|
||||
{
|
||||
if (a->num_vars == MAX_VARS) {
|
||||
assembler_report(a, "Variable limit reached");
|
||||
assert(a->num_scopes > 0);
|
||||
|
||||
// Find the index of the parent function scope or the global scope
|
||||
int parent = a->num_scopes-1;
|
||||
while (parent > 1 && a->scopes[parent].type != SCOPE_FUNC)
|
||||
parent--;
|
||||
|
||||
for (int i = a->num_syms-1; i >= a->scopes[parent].sym_base; i--)
|
||||
if (streq(a->syms[i].name, name))
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int declare_variable(Assembler *a, String name)
|
||||
{
|
||||
if (a->num_syms == MAX_SYMBOLS) {
|
||||
assembler_report(a, "Symbol 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;
|
||||
}
|
||||
if (find_symbol_in_local_scope(a, name) >= 0) {
|
||||
assembler_report(a, "Symbol '%.*s' already declared in this scope",
|
||||
name.len, name.ptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int idx = a->num_vars++;
|
||||
a->vars[idx] = (Variable) { name };
|
||||
return idx - scope->var_base;
|
||||
a->syms[a->num_syms] = (Symbol) { SYMBOL_VAR, name, -1 };
|
||||
return a->num_syms++;
|
||||
}
|
||||
|
||||
int declare_function(Assembler *a, String name, int off)
|
||||
{
|
||||
if (a->num_syms == MAX_SYMBOLS) {
|
||||
assembler_report(a, "Symbol limit reached");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (find_symbol_in_local_scope(a, name) >= 0) {
|
||||
assembler_report(a, "Symbol '%.*s' already declared in this scope",
|
||||
name.len, name.ptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
a->syms[a->num_syms] = (Symbol) { SYMBOL_FUNC, name, off };
|
||||
return a->num_syms++;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -273,6 +316,7 @@ b32 is_expr(Node *node)
|
||||
break;
|
||||
|
||||
case NODE_SELECT:
|
||||
case NODE_NESTED:
|
||||
case NODE_FUNC_CALL:
|
||||
case NODE_OPER_POS:
|
||||
case NODE_OPER_NEG:
|
||||
@@ -299,8 +343,70 @@ b32 is_expr(Node *node)
|
||||
return false;
|
||||
}
|
||||
|
||||
int push_scope(Assembler *a, ScopeType type)
|
||||
{
|
||||
if (a->num_scopes == MAX_SCOPES) {
|
||||
assembler_report(a, "Scope limit reached");
|
||||
return -1;
|
||||
}
|
||||
Scope *scope = &a->scopes[a->num_scopes++];
|
||||
scope->type = type;
|
||||
scope->sym_base = a->num_syms;
|
||||
scope->calls = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pop_scope(Assembler *a)
|
||||
{
|
||||
Scope *scope = &a->scopes[a->num_scopes-1];
|
||||
|
||||
FunctionCall *call = scope->calls;
|
||||
FunctionCall **prev = &scope->calls;
|
||||
while (call) {
|
||||
|
||||
int idx = find_symbol_in_local_scope(a, call->name);
|
||||
|
||||
if (idx == -1) {
|
||||
prev = &call->next;
|
||||
call = call->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
Symbol *sym = &a->syms[idx];
|
||||
if (sym->type != SYMBOL_FUNC) {
|
||||
assembler_report(a, "Symbol '%.*s' is not a function", call->name.len, call->name.ptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
patch_u32(&a->out, call->off, sym->off);
|
||||
|
||||
*prev = call->next;
|
||||
call = call->next;
|
||||
}
|
||||
|
||||
if (scope->calls) {
|
||||
|
||||
if (a->num_scopes == 1) {
|
||||
assembler_report(a, "Undefined function '%.*s'",
|
||||
scope->calls->name.len,
|
||||
scope->calls->name.ptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Scope *parent_scope = &a->scopes[a->num_scopes-2];
|
||||
*prev = parent_scope->calls;
|
||||
parent_scope->calls = scope->calls;
|
||||
}
|
||||
|
||||
a->num_syms = scope->sym_base;
|
||||
a->num_scopes--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void assemble_node(Assembler *a, Node *node)
|
||||
{
|
||||
printf("Compiling [%.*s]\n", node->text.len, node->text.ptr);
|
||||
|
||||
switch (node->type) {
|
||||
|
||||
case NODE_FUNC_DECL:
|
||||
@@ -308,30 +414,44 @@ void assemble_node(Assembler *a, Node *node)
|
||||
append_u8(&a->out, OPCODE_JUMP);
|
||||
int p1 = append_u32(&a->out, 0);
|
||||
|
||||
// TODO: resolve references
|
||||
int ret = declare_function(a, node->func_name, current_offset(&a->out));
|
||||
if (ret < 0) return;
|
||||
|
||||
int arg_count = count_nodes(node->func_args);
|
||||
ret = push_scope(a, SCOPE_FUNC);
|
||||
if (ret < 0) return;
|
||||
|
||||
Node *args[32];
|
||||
if (arg_count > COUNT(args)) {
|
||||
assembler_report(a, "Argument limit reached");
|
||||
return;
|
||||
int arg_count = 0;
|
||||
Node *arg = node->func_args;
|
||||
while (arg) {
|
||||
if (arg_count == COUNT(args)) {
|
||||
assembler_report(a, "Argument limit reached");
|
||||
return;
|
||||
}
|
||||
args[arg_count++] = arg;
|
||||
arg = arg->next;
|
||||
}
|
||||
|
||||
for (int i = arg_count-1; i >= 0; i--) {
|
||||
|
||||
int idx = declare_var(a, args[i]->sval);
|
||||
int idx = declare_variable(a, args[i]->sval);
|
||||
if (idx < 0) return;
|
||||
|
||||
append_u8(&a->out, OPCODE_SETV);
|
||||
append_u8(&a->out, idx);
|
||||
append_u8(&a->out, idx); // TODO: make this relative to the frame
|
||||
}
|
||||
|
||||
if (is_expr(node->func_body)) {
|
||||
assemble_node(a, node->func_body);
|
||||
append_u8(&a->out, OPCODE_RET);
|
||||
} else
|
||||
} else {
|
||||
assemble_node(a, node->func_body);
|
||||
append_u8(&a->out, OPCODE_PUSHN);
|
||||
append_u8(&a->out, OPCODE_RET);
|
||||
}
|
||||
|
||||
ret = pop_scope(a);
|
||||
if (ret < 0) return;
|
||||
|
||||
patch_with_current_offset(&a->out, p1);
|
||||
}
|
||||
@@ -350,37 +470,30 @@ void assemble_node(Assembler *a, Node *node)
|
||||
arg = arg->next;
|
||||
}
|
||||
|
||||
if (func->type == NODE_VALUE_VAR) {
|
||||
assemble_node(a, arg);
|
||||
append_u8(&a->out, OPCODE_SCALL);
|
||||
append_u8(&a->out, arg_count);
|
||||
int p = append_u32(&a->out, 0);
|
||||
assert(func->type == NODE_VALUE_VAR);
|
||||
|
||||
FunctionCall *call = alloc(a->a, sizeof(FunctionCall), _Alignof(FunctionCall));
|
||||
if (call == NULL) {
|
||||
assembler_report(a, "Out of memory");
|
||||
return;
|
||||
}
|
||||
call->name = func->sval;
|
||||
call->off = p;
|
||||
append_u8(&a->out, OPCODE_CALL);
|
||||
append_u8(&a->out, arg_count);
|
||||
int p = append_u32(&a->out, 0);
|
||||
|
||||
Scope *scope = &a->scopes[a->num_scopes-1];
|
||||
|
||||
call->next = scope->calls;
|
||||
scope->calls = call;
|
||||
|
||||
} else {
|
||||
assemble_node(a, func);
|
||||
assemble_node(a, arg);
|
||||
append_u8(&a->out, OPCODE_DCALL);
|
||||
append_u8(&a->out, arg_count);
|
||||
FunctionCall *call = alloc(a->a, sizeof(FunctionCall), _Alignof(FunctionCall));
|
||||
if (call == NULL) {
|
||||
assembler_report(a, "Out of memory");
|
||||
return;
|
||||
}
|
||||
call->name = func->sval;
|
||||
call->off = p;
|
||||
|
||||
Scope *scope = &a->scopes[a->num_scopes-1];
|
||||
|
||||
call->next = scope->calls;
|
||||
scope->calls = call;
|
||||
}
|
||||
break;
|
||||
|
||||
case NODE_VAR_DECL:
|
||||
{
|
||||
int idx = declare_var(a, node->var_name);
|
||||
int idx = declare_variable(a, node->var_name);
|
||||
if (idx < 0) return;
|
||||
|
||||
if (node->var_value) {
|
||||
@@ -393,13 +506,19 @@ void assemble_node(Assembler *a, Node *node)
|
||||
|
||||
case NODE_BLOCK:
|
||||
{
|
||||
Node *stmt = node->child;
|
||||
int ret = push_scope(a, SCOPE_BLOCK);
|
||||
if (ret < 0) return;
|
||||
|
||||
Node *stmt = node->left;
|
||||
while (stmt) {
|
||||
assemble_node(a, stmt);
|
||||
if (is_expr(stmt))
|
||||
append_u8(&a->out, OPCODE_POP);
|
||||
stmt = stmt->next;
|
||||
}
|
||||
|
||||
ret = pop_scope(a);
|
||||
if (ret < 0) return;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -431,15 +550,27 @@ void assemble_node(Assembler *a, Node *node)
|
||||
append_u8(&a->out, OPCODE_JIFP);
|
||||
int p1 = append_u32(&a->out, 0);
|
||||
|
||||
int ret = push_scope(a, SCOPE_IF);
|
||||
if (ret < 0) return;
|
||||
|
||||
assemble_node(a, node->left);
|
||||
|
||||
ret = pop_scope(a);
|
||||
if (ret < 0) return;
|
||||
|
||||
append_u8(&a->out, OPCODE_JUMP);
|
||||
int p2 = append_u32(&a->out, 0);
|
||||
|
||||
patch_with_current_offset(&a->out, p1);
|
||||
|
||||
ret = push_scope(a, SCOPE_ELSE);
|
||||
if (ret < 0) return;
|
||||
|
||||
assemble_node(a, node->right);
|
||||
|
||||
ret = pop_scope(a);
|
||||
if (ret < 0) return;
|
||||
|
||||
patch_with_current_offset(&a->out, p2);
|
||||
|
||||
} else {
|
||||
@@ -449,8 +580,14 @@ void assemble_node(Assembler *a, Node *node)
|
||||
append_u8(&a->out, OPCODE_JIFP);
|
||||
int p1 = append_u32(&a->out, 0);
|
||||
|
||||
int ret = push_scope(a, SCOPE_IF);
|
||||
if (ret < 0) return;
|
||||
|
||||
assemble_node(a, node->left);
|
||||
|
||||
ret = pop_scope(a);
|
||||
if (ret < 0) return;
|
||||
|
||||
patch_with_current_offset(&a->out, p1);
|
||||
}
|
||||
}
|
||||
@@ -473,8 +610,14 @@ void assemble_node(Assembler *a, Node *node)
|
||||
append_u8(&a->out, OPCODE_JIFP);
|
||||
int p = append_u32(&a->out, 0);
|
||||
|
||||
int ret = push_scope(a, SCOPE_WHILE);
|
||||
if (ret < 0) return;
|
||||
|
||||
assemble_node(a, node->left);
|
||||
|
||||
ret = pop_scope(a);
|
||||
if (ret < 0) return;
|
||||
|
||||
append_u8(&a->out, OPCODE_JUMP);
|
||||
append_u32(&a->out, start);
|
||||
|
||||
@@ -485,7 +628,16 @@ void assemble_node(Assembler *a, Node *node)
|
||||
case NODE_FOR:
|
||||
{
|
||||
assemble_node(a, node->for_set);
|
||||
|
||||
// TODO
|
||||
|
||||
int ret = push_scope(a, SCOPE_FOR);
|
||||
if (ret < 0) return;
|
||||
|
||||
assemble_node(a, node->left);
|
||||
|
||||
ret = pop_scope(a);
|
||||
if (ret < 0) return;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -572,8 +724,16 @@ void assemble_node(Assembler *a, Node *node)
|
||||
break;
|
||||
|
||||
case NODE_VALUE_VAR:
|
||||
append_u8 (&a->out, OPCODE_PUSHV);
|
||||
append_u64(&a->out, node->ival);
|
||||
{
|
||||
String name = node->sval;
|
||||
int idx = find_symbol_in_function(a, name);
|
||||
if (idx < 0) {
|
||||
assembler_report(a, "Reference to undefined variable '%.*s'", name.len, name.ptr);
|
||||
return;
|
||||
}
|
||||
append_u8(&a->out, OPCODE_PUSHV);
|
||||
append_u8(&a->out, idx); // TODO: make this relative to the frame
|
||||
}
|
||||
break;
|
||||
|
||||
case NODE_VALUE_HTML:
|
||||
@@ -598,7 +758,7 @@ void assemble_node(Assembler *a, Node *node)
|
||||
case NODE_VALUE_MAP:
|
||||
{
|
||||
append_u8(&a->out, OPCODE_PUSHM);
|
||||
append_u64(&a->out, count_nodes(node->child));
|
||||
append_u32(&a->out, count_nodes(node->child));
|
||||
|
||||
Node *child = node->child;
|
||||
while (child) {
|
||||
@@ -621,6 +781,10 @@ void assemble_node(Assembler *a, Node *node)
|
||||
}
|
||||
break;
|
||||
|
||||
case NODE_NESTED:
|
||||
assemble_node(a, node->left);
|
||||
break;
|
||||
|
||||
case NODE_OPER_ASS:
|
||||
{
|
||||
Node *dst = node->left;
|
||||
@@ -628,12 +792,22 @@ void assemble_node(Assembler *a, Node *node)
|
||||
|
||||
if (dst->type == NODE_VALUE_VAR) {
|
||||
|
||||
int idx = find_variable(a, dst->sval);
|
||||
if (idx < 0) return;
|
||||
String name = dst->sval;
|
||||
|
||||
int idx = find_symbol_in_function(a, name);
|
||||
if (idx < 0) {
|
||||
assembler_report(a, "Undeclared variable '%.*s'", name.len, name.ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (a->syms[idx].type != SYMBOL_VAR) {
|
||||
assembler_report(a, "Symbol '%.*s' can't be assigned to", name.len, name.ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
assemble_node(a, src);
|
||||
append_u8(&a->out, OPCODE_SETV);
|
||||
append_u8(&a->out, idx);
|
||||
append_u8(&a->out, idx); // TODO: this index should be relative to the frame
|
||||
|
||||
} else if (dst->type == NODE_SELECT) {
|
||||
|
||||
@@ -655,14 +829,257 @@ void assemble_node(Assembler *a, Node *node)
|
||||
}
|
||||
}
|
||||
|
||||
AssembleResult assemble(Node *root, char *errbuf, int errmax)
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
uint32_t code_size;
|
||||
uint32_t data_size;
|
||||
} Header;
|
||||
|
||||
AssembleResult assemble(Node *root, Arena *arena, char *errbuf, int errmax)
|
||||
{
|
||||
Assembler a = {0, .errbuf=errbuf, .errmax=errmax, .errlen=0};
|
||||
Assembler a = {0, .a=arena, .errbuf=errbuf, .errmax=errmax, .errlen=0};
|
||||
|
||||
append_u32(&a.out, 0xFEEDBEEF); // magic
|
||||
int p1 = append_u32(&a.out, 0); // code size
|
||||
int p2 = append_u32(&a.out, 0); // data size
|
||||
|
||||
int ret = push_scope(&a, SCOPE_GLOBAL);
|
||||
if (ret < 0) {
|
||||
return (AssembleResult) { (Program) {0}, a.errlen };
|
||||
}
|
||||
|
||||
assemble_node(&a, root);
|
||||
append_u8(&a.out, OPCODE_NOPE);
|
||||
|
||||
Program p;
|
||||
// TODO
|
||||
ret = pop_scope(&a);
|
||||
if (ret < 0) {
|
||||
return (AssembleResult) { (Program) {0}, a.errlen };
|
||||
}
|
||||
|
||||
patch_u32(&a.out, p1, a.out.len - 3 * sizeof(uint32_t));
|
||||
patch_u32(&a.out, p2, a.strings_len);
|
||||
|
||||
append_mem(&a.out, a.strings, a.strings_len);
|
||||
|
||||
Program p = {
|
||||
a.out.ptr,
|
||||
a.out.len,
|
||||
};
|
||||
|
||||
return (AssembleResult) { p, a.errlen };
|
||||
}
|
||||
|
||||
void print_program(Program p)
|
||||
{
|
||||
if (p.len < 3 * sizeof(uint32_t)) {
|
||||
printf("Invalid program");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t cur = 0;
|
||||
|
||||
uint32_t magic;
|
||||
memcpy(&magic, p.ptr + cur, sizeof(uint32_t));
|
||||
cur += sizeof(uint32_t);
|
||||
|
||||
uint32_t code_size;
|
||||
memcpy(&code_size, p.ptr + cur, sizeof(uint32_t));
|
||||
cur += sizeof(uint32_t);
|
||||
|
||||
uint32_t data_size;
|
||||
memcpy(&data_size, p.ptr + cur, sizeof(uint32_t));
|
||||
cur += sizeof(uint32_t);
|
||||
|
||||
if (3 * sizeof(uint32_t) + code_size + data_size != p.len) {
|
||||
printf("Invalid program");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Program size is %d\n", p.len);
|
||||
|
||||
while (cur < code_size + 3 * sizeof(uint32_t)) {
|
||||
|
||||
printf("%d: ", cur - 3 * sizeof(uint32_t));
|
||||
|
||||
switch (((uint8_t*) p.ptr)[cur++]) {
|
||||
|
||||
case OPCODE_NOPE:
|
||||
printf("NOPE");
|
||||
break;
|
||||
|
||||
case OPCODE_PUSHI:
|
||||
{
|
||||
uint64_t x;
|
||||
memcpy(&x, p.ptr + cur, sizeof(uint64_t));
|
||||
cur += sizeof(uint64_t);
|
||||
|
||||
printf("PUSHI %" LLU, x);
|
||||
}
|
||||
break;
|
||||
|
||||
case OPCODE_PUSHF:
|
||||
{
|
||||
double x;
|
||||
memcpy(&x, p.ptr + cur, sizeof(double));
|
||||
cur += sizeof(double);
|
||||
|
||||
printf("PUSHF %lf", x);
|
||||
}
|
||||
break;
|
||||
|
||||
case OPCODE_PUSHS:
|
||||
{
|
||||
uint32_t off;
|
||||
memcpy(&off, p.ptr + cur, sizeof(uint32_t));
|
||||
cur += sizeof(uint32_t);
|
||||
|
||||
uint32_t len;
|
||||
memcpy(&len, p.ptr + cur, sizeof(uint32_t));
|
||||
cur += sizeof(uint32_t);
|
||||
|
||||
printf("PUSHS \"%.*s\"", len, (char*) p.ptr + 3 * sizeof(uint32_t) + code_size + off);
|
||||
}
|
||||
break;
|
||||
|
||||
case OPCODE_PUSHV:
|
||||
{
|
||||
uint8_t idx;
|
||||
memcpy(&idx, p.ptr + cur, sizeof(uint8_t));
|
||||
cur += sizeof(uint8_t);
|
||||
|
||||
printf("PUSHV %u", idx);
|
||||
}
|
||||
break;
|
||||
|
||||
case OPCODE_PUSHA:
|
||||
{
|
||||
uint32_t cap;
|
||||
memcpy(&cap, p.ptr + cur, sizeof(uint32_t));
|
||||
cur += sizeof(uint32_t);
|
||||
|
||||
printf("PUSHA %u", cap);
|
||||
}
|
||||
break;
|
||||
|
||||
case OPCODE_PUSHM:
|
||||
{
|
||||
uint32_t cap;
|
||||
memcpy(&cap, p.ptr + cur, sizeof(uint32_t));
|
||||
cur += sizeof(uint32_t);
|
||||
|
||||
printf("PUSHM %u", cap);
|
||||
}
|
||||
break;
|
||||
|
||||
case OPCODE_POP:
|
||||
printf("POP");
|
||||
break;
|
||||
|
||||
case OPCODE_NEG:
|
||||
printf("NEG");
|
||||
break;
|
||||
|
||||
case OPCODE_EQL:
|
||||
printf("EQL");
|
||||
break;
|
||||
|
||||
case OPCODE_NQL:
|
||||
printf("NQL");
|
||||
break;
|
||||
|
||||
case OPCODE_LSS:
|
||||
printf("LSS");
|
||||
break;
|
||||
|
||||
case OPCODE_GRT:
|
||||
printf("GRT");
|
||||
break;
|
||||
|
||||
case OPCODE_ADD:
|
||||
printf("ADD");
|
||||
break;
|
||||
|
||||
case OPCODE_SUB:
|
||||
printf("SUB");
|
||||
break;
|
||||
|
||||
case OPCODE_MUL:
|
||||
printf("MUL");
|
||||
break;
|
||||
|
||||
case OPCODE_DIV:
|
||||
printf("DIV");
|
||||
break;
|
||||
|
||||
case OPCODE_MOD:
|
||||
printf("MOD");
|
||||
break;
|
||||
|
||||
case OPCODE_SETV:
|
||||
{
|
||||
uint8_t idx;
|
||||
memcpy(&idx, p.ptr + cur, sizeof(uint8_t));
|
||||
cur += sizeof(uint8_t);
|
||||
|
||||
printf("SETV %u", idx);
|
||||
}
|
||||
break;
|
||||
|
||||
case OPCODE_JUMP:
|
||||
{
|
||||
uint32_t off;
|
||||
memcpy(&off, p.ptr + cur, sizeof(uint32_t));
|
||||
cur += sizeof(uint32_t);
|
||||
|
||||
printf("JUMP %u", off);
|
||||
}
|
||||
break;
|
||||
|
||||
case OPCODE_JIFP:
|
||||
{
|
||||
uint32_t off;
|
||||
memcpy(&off, p.ptr + cur, sizeof(uint32_t));
|
||||
cur += sizeof(uint32_t);
|
||||
|
||||
printf("JIFP %u", off);
|
||||
}
|
||||
break;
|
||||
|
||||
case OPCODE_CALL:
|
||||
{
|
||||
uint8_t num;
|
||||
memcpy(&num, p.ptr + cur, sizeof(uint8_t));
|
||||
cur += sizeof(uint8_t);
|
||||
|
||||
uint8_t off;
|
||||
memcpy(&off, p.ptr + cur, sizeof(uint8_t));
|
||||
cur += sizeof(uint8_t);
|
||||
|
||||
printf("CALL %u %u", num, off);
|
||||
}
|
||||
break;
|
||||
|
||||
case OPCODE_RET:
|
||||
printf("RET");
|
||||
break;
|
||||
|
||||
case OPCODE_APPEND:
|
||||
printf("APPEND");
|
||||
break;
|
||||
|
||||
case OPCODE_INSERT1:
|
||||
printf("INSERT1");
|
||||
break;
|
||||
|
||||
case OPCODE_INSERT2:
|
||||
printf("INSERT2");
|
||||
break;
|
||||
|
||||
case OPCODE_SELECT:
|
||||
printf("SELECT");
|
||||
break;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
+9
-8
@@ -11,6 +11,7 @@ enum {
|
||||
OPCODE_PUSHV = 0x04,
|
||||
OPCODE_PUSHA = 0x05,
|
||||
OPCODE_PUSHM = 0x06,
|
||||
OPCODE_PUSHN = 0x21,
|
||||
OPCODE_POP = 0x07,
|
||||
OPCODE_NEG = 0x08,
|
||||
OPCODE_EQL = 0x09,
|
||||
@@ -25,13 +26,12 @@ enum {
|
||||
OPCODE_SETV = 0x12,
|
||||
OPCODE_JUMP = 0x13,
|
||||
OPCODE_JIFP = 0x14,
|
||||
OPCODE_SCALL = 0x15,
|
||||
OPCODE_DCALL = 0x16,
|
||||
OPCODE_RET = 0x17,
|
||||
OPCODE_APPEND = 0x18,
|
||||
OPCODE_INSERT1 = 0x19,
|
||||
OPCODE_INSERT2 = 0x20,
|
||||
OPCODE_SELECT = 0x21,
|
||||
OPCODE_CALL = 0x15,
|
||||
OPCODE_RET = 0x16,
|
||||
OPCODE_APPEND = 0x17,
|
||||
OPCODE_INSERT1 = 0x18,
|
||||
OPCODE_INSERT2 = 0x19,
|
||||
OPCODE_SELECT = 0x20,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -44,6 +44,7 @@ typedef struct {
|
||||
int errlen;
|
||||
} AssembleResult;
|
||||
|
||||
AssembleResult assemble(Node *root, char *errbuf, int errmax);
|
||||
void print_program(Program p);
|
||||
AssembleResult assemble(Node *root, Arena *arena, char *errbuf, int errmax);
|
||||
|
||||
#endif // WL_ASSEMBLE_INCLUDED
|
||||
+66
@@ -6,6 +6,72 @@
|
||||
#define FRAME_LIMIT 128
|
||||
#define EVAL_STACK_LIMIT 128
|
||||
|
||||
#define HEAP_BASE 0xFEEDBEEFFEEDBEEF
|
||||
|
||||
/*
|
||||
int
|
||||
float
|
||||
array
|
||||
map
|
||||
html
|
||||
bool
|
||||
none
|
||||
*/
|
||||
|
||||
/*
|
||||
000 none
|
||||
001 true
|
||||
010 false
|
||||
011 short str
|
||||
100
|
||||
101
|
||||
110
|
||||
111 pointer
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint64_t data;
|
||||
} Value;
|
||||
|
||||
typedef struct {
|
||||
uint64_t data;
|
||||
} Pointer;
|
||||
|
||||
typedef enum {
|
||||
TYPE_NONE,
|
||||
TYPE_BOOL,
|
||||
TYPE_MAP,
|
||||
TYPE_ARRAY,
|
||||
TYPE_STRING,
|
||||
} Type;
|
||||
|
||||
typedef struct MapItems MapItems;
|
||||
struct MapItems {
|
||||
Pointer next;
|
||||
Value keys[8];
|
||||
Value items[8];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
Type type;
|
||||
int count;
|
||||
MapItems head;
|
||||
Pointer tail;
|
||||
} Map;
|
||||
|
||||
typedef struct ArrayItems ArrayItems;
|
||||
struct ArrayItems {
|
||||
ArrayItems *next;
|
||||
Value items[16];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
Type type;
|
||||
int count;
|
||||
ArrayItems head;
|
||||
ArrayItems *tail;
|
||||
} Array;
|
||||
|
||||
typedef struct {
|
||||
} Frame;
|
||||
|
||||
|
||||
+16
-5
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "file.h"
|
||||
#include "parse.h"
|
||||
#include "assemble.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
@@ -17,14 +18,24 @@ int main(void)
|
||||
char *mem = malloc(1<<20);
|
||||
Arena a = { mem, 1<<20, 0 };
|
||||
|
||||
ParseResult result = parse(src, &a, err, COUNT(err));
|
||||
if (result.node == NULL) {
|
||||
printf("%.*s\n", result.errlen, err);
|
||||
ParseResult parse_result = parse(src, &a, err, COUNT(err));
|
||||
if (parse_result.node == NULL) {
|
||||
printf("%.*s\n", parse_result.errlen, err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
print_node(result.node);
|
||||
fflush(stdout);
|
||||
print_node(parse_result.node);
|
||||
printf("\n");
|
||||
|
||||
AssembleResult assemble_result = assemble(parse_result.node, &a, err, COUNT(err));
|
||||
if (assemble_result.errlen) {
|
||||
printf("%.*s\n", parse_result.errlen, err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
print_program(assemble_result.program);
|
||||
|
||||
eval(assemble_result.program);
|
||||
|
||||
free(src.ptr);
|
||||
free(mem);
|
||||
|
||||
+104
-45
@@ -158,7 +158,7 @@ String tok2str(Token token, char *buf, int max)
|
||||
return S("???");
|
||||
}
|
||||
|
||||
void report(Parser *p, char *fmt, ...)
|
||||
void parser_report(Parser *p, char *fmt, ...)
|
||||
{
|
||||
if (p->errmax == 0 || p->errlen > 0)
|
||||
return;
|
||||
@@ -192,7 +192,7 @@ Node *alloc_node(Parser *p)
|
||||
{
|
||||
Node *n = alloc(p->a, sizeof(Node), _Alignof(Node));
|
||||
if (n == NULL) {
|
||||
report(p, "Out of memory");
|
||||
parser_report(p, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -262,7 +262,7 @@ Token next_token(Parser *p)
|
||||
do {
|
||||
int d = p->s.src[p->s.cur++] - '0';
|
||||
if (buf > (UINT64_MAX - d) / 10) {
|
||||
report(p, "Integer literal overflow");
|
||||
parser_report(p, "Integer literal overflow");
|
||||
return (Token) { .type=TOKEN_ERROR };
|
||||
}
|
||||
buf = buf * 10 + d;
|
||||
@@ -296,7 +296,7 @@ Token next_token(Parser *p)
|
||||
buf = NULL;
|
||||
|
||||
if (buf == NULL) {
|
||||
report(p, "Out of memory");
|
||||
parser_report(p, "Out of memory");
|
||||
return (Token) { .type=TOKEN_ERROR };
|
||||
}
|
||||
|
||||
@@ -310,12 +310,12 @@ Token next_token(Parser *p)
|
||||
}
|
||||
|
||||
if (p->s.cur == p->s.len) {
|
||||
report(p, "String literal wasn't closed");
|
||||
parser_report(p, "String literal wasn't closed");
|
||||
return (Token) { .type=TOKEN_ERROR };
|
||||
}
|
||||
|
||||
if (!is_printable(p->s.src[p->s.cur])) {
|
||||
report(p, "Invalid byte in string literal");
|
||||
parser_report(p, "Invalid byte in string literal");
|
||||
return (Token) { .type=TOKEN_ERROR };
|
||||
}
|
||||
|
||||
@@ -324,7 +324,7 @@ Token next_token(Parser *p)
|
||||
|
||||
p->s.cur++;
|
||||
if (p->s.cur == p->s.len) {
|
||||
report(p, "Missing special character after escape character \\");
|
||||
parser_report(p, "Missing special character after escape character \\");
|
||||
return (Token) { .type=TOKEN_ERROR };
|
||||
}
|
||||
|
||||
@@ -350,7 +350,7 @@ Token next_token(Parser *p)
|
||||
break;
|
||||
|
||||
default:
|
||||
report(p, "Invalid character after escape character \\");
|
||||
parser_report(p, "Invalid character after escape character \\");
|
||||
return (Token) { .type=TOKEN_ERROR };
|
||||
}
|
||||
|
||||
@@ -382,7 +382,7 @@ Token next_token(Parser *p)
|
||||
if (consume_str(&p->s, S(","))) return (Token) { .type=TOKEN_COMMA };
|
||||
if (consume_str(&p->s, S(":"))) return (Token) { .type=TOKEN_COLON };
|
||||
|
||||
report(p, "Invalid character '%c'", c);
|
||||
parser_report(p, "Invalid character '%c'", c);
|
||||
return (Token) { .type=TOKEN_ERROR };
|
||||
}
|
||||
|
||||
@@ -411,12 +411,14 @@ Node *parse_expr(Parser *p, int opflags);
|
||||
Node *parse_html(Parser *p)
|
||||
{
|
||||
// NOTE: The first < was already consumed
|
||||
|
||||
int node_offset = p->s.cur-1;
|
||||
|
||||
Token t = next_token(p);
|
||||
if (t.type != TOKEN_IDENT) {
|
||||
char buf[1<<8];
|
||||
String ts = tok2str(t, buf, COUNT(buf));
|
||||
report(p, "HTML tag doesn't start with a name (got '%.*s' instead)", ts.len, ts.ptr);
|
||||
parser_report(p, "HTML tag doesn't start with a name (got '%.*s' instead)", ts.len, ts.ptr);
|
||||
return NULL;
|
||||
}
|
||||
String tagname = t.sval;
|
||||
@@ -426,6 +428,8 @@ Node *parse_html(Parser *p)
|
||||
|
||||
for (;;) {
|
||||
|
||||
int param_offset = p->s.cur;
|
||||
|
||||
String attr_name;
|
||||
Node *attr_value;
|
||||
|
||||
@@ -433,7 +437,7 @@ Node *parse_html(Parser *p)
|
||||
if (t.type == TOKEN_OPER_GRT)
|
||||
break;
|
||||
if (t.type != TOKEN_IDENT) {
|
||||
report(p, "Invalid token inside HTML tag");
|
||||
parser_report(p, "Invalid token inside HTML tag");
|
||||
return NULL;
|
||||
}
|
||||
attr_name = t.sval;
|
||||
@@ -456,6 +460,7 @@ Node *parse_html(Parser *p)
|
||||
return NULL;
|
||||
|
||||
child->type = NODE_HTML_PARAM;
|
||||
child->text = (String) { p->s.src + param_offset, p->s.cur - param_offset };
|
||||
child->attr_name = attr_name;
|
||||
child->attr_value = attr_value;
|
||||
|
||||
@@ -483,6 +488,7 @@ Node *parse_html(Parser *p)
|
||||
return NULL;
|
||||
|
||||
child->type = NODE_VALUE_STR;
|
||||
child->text = (String) { p->s.src + off, p->s.cur - off };
|
||||
child->sval = (String) { p->s.src + off, p->s.cur - off };
|
||||
|
||||
*tail = child;
|
||||
@@ -492,7 +498,7 @@ Node *parse_html(Parser *p)
|
||||
if (p->s.cur == p->s.len || p->s.src[p->s.cur] == '<')
|
||||
break;
|
||||
|
||||
p->s.cur++; // Consume \
|
||||
p->s.cur++; // Consume "\"
|
||||
|
||||
{
|
||||
Node *child = parse_stmt(p, IGNORE_LSS);
|
||||
@@ -505,7 +511,7 @@ Node *parse_html(Parser *p)
|
||||
}
|
||||
|
||||
if (p->s.cur == p->s.len) {
|
||||
report(p, "Missing closing HTML tag");
|
||||
parser_report(p, "Missing closing HTML tag");
|
||||
return NULL;
|
||||
}
|
||||
p->s.cur++; // Consume <
|
||||
@@ -517,7 +523,7 @@ Node *parse_html(Parser *p)
|
||||
if (t.type == TOKEN_IDENT && streqcase(t.sval, tagname)) {
|
||||
t = next_token(p);
|
||||
if (t.type != TOKEN_OPER_GRT) {
|
||||
report(p, "Unexpected token in closing HTML tag");
|
||||
parser_report(p, "Unexpected token in closing HTML tag");
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
@@ -541,6 +547,7 @@ Node *parse_html(Parser *p)
|
||||
return NULL;
|
||||
|
||||
parent->type = NODE_VALUE_HTML;
|
||||
parent->text = (String) { p->s.src + node_offset, p->s.cur - node_offset };
|
||||
parent->tagname = tagname;
|
||||
parent->params = param_head;
|
||||
parent->child = head;
|
||||
@@ -552,6 +559,8 @@ Node *parse_array(Parser *p)
|
||||
{
|
||||
// Left bracket already consumed
|
||||
|
||||
int start = p->s.cur;
|
||||
|
||||
Node *head;
|
||||
Node **tail = &head;
|
||||
|
||||
@@ -591,6 +600,7 @@ Node *parse_array(Parser *p)
|
||||
return NULL;
|
||||
|
||||
parent->type = NODE_VALUE_ARRAY;
|
||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
parent->child = head;
|
||||
|
||||
return parent;
|
||||
@@ -600,6 +610,8 @@ Node *parse_map(Parser *p)
|
||||
{
|
||||
// Left bracket already consumed
|
||||
|
||||
int start = p->s.cur;
|
||||
|
||||
Node *head;
|
||||
Node **tail = &head;
|
||||
|
||||
@@ -622,6 +634,7 @@ Node *parse_map(Parser *p)
|
||||
return NULL;
|
||||
|
||||
key->type = NODE_VALUE_STR;
|
||||
key->text = t.sval;
|
||||
key->sval = t.sval;
|
||||
|
||||
} else {
|
||||
@@ -634,7 +647,7 @@ Node *parse_map(Parser *p)
|
||||
|
||||
t = next_token(p);
|
||||
if (t.type != TOKEN_COLON) {
|
||||
report(p, "Missing ':' after key inside map literal");
|
||||
parser_report(p, "Missing ':' after key inside map literal");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -667,6 +680,7 @@ Node *parse_map(Parser *p)
|
||||
return NULL;
|
||||
|
||||
parent->type = NODE_VALUE_MAP;
|
||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
parent->child = head;
|
||||
|
||||
return parent;
|
||||
@@ -716,6 +730,8 @@ b32 right_associative(Token t)
|
||||
|
||||
Node *parse_atom(Parser *p)
|
||||
{
|
||||
int start = p->s.cur;
|
||||
|
||||
Token t = next_token(p);
|
||||
|
||||
Node *ret;
|
||||
@@ -731,6 +747,7 @@ Node *parse_atom(Parser *p)
|
||||
return NULL;
|
||||
|
||||
parent->type = NODE_OPER_POS;
|
||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
parent->left = child;
|
||||
|
||||
ret = parent;
|
||||
@@ -748,6 +765,7 @@ Node *parse_atom(Parser *p)
|
||||
return NULL;
|
||||
|
||||
parent->type = NODE_OPER_NEG;
|
||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
parent->left = child;
|
||||
|
||||
ret = parent;
|
||||
@@ -761,6 +779,7 @@ Node *parse_atom(Parser *p)
|
||||
return NULL;
|
||||
|
||||
node->type = NODE_VALUE_VAR;
|
||||
node->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
node->sval = t.sval;
|
||||
|
||||
ret = node;
|
||||
@@ -774,6 +793,7 @@ Node *parse_atom(Parser *p)
|
||||
return NULL;
|
||||
|
||||
node->type = NODE_VALUE_INT;
|
||||
node->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
node->ival = t.uval;
|
||||
|
||||
ret = node;
|
||||
@@ -787,6 +807,7 @@ Node *parse_atom(Parser *p)
|
||||
return NULL;
|
||||
|
||||
node->type = NODE_VALUE_FLOAT;
|
||||
node->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
node->dval = t.dval;
|
||||
|
||||
ret = node;
|
||||
@@ -800,6 +821,7 @@ Node *parse_atom(Parser *p)
|
||||
return NULL;
|
||||
|
||||
node->type = NODE_VALUE_STR;
|
||||
node->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
node->sval = t.sval;
|
||||
|
||||
ret = node;
|
||||
@@ -824,11 +846,19 @@ Node *parse_atom(Parser *p)
|
||||
|
||||
Token t = next_token(p);
|
||||
if (t.type != TOKEN_PAREN_CLOSE) {
|
||||
report(p, "Missing ')' after expression");
|
||||
parser_report(p, "Missing ')' after expression");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = node;
|
||||
Node *parent = alloc_node(p);
|
||||
if (parent == NULL)
|
||||
return NULL;
|
||||
|
||||
parent->type = NODE_NESTED;
|
||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
parent->left = node;
|
||||
|
||||
ret = parent;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -856,7 +886,7 @@ Node *parse_atom(Parser *p)
|
||||
{
|
||||
char buf[1<<8];
|
||||
String str = tok2str(t, buf, COUNT(buf));
|
||||
report(p, "Invalid token \'%.*s\' inside expression", str.len, str.ptr);
|
||||
parser_report(p, "Invalid token \'%.*s\' inside expression", str.len, str.ptr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -868,7 +898,7 @@ Node *parse_atom(Parser *p)
|
||||
|
||||
t = next_token(p);
|
||||
if (t.type != TOKEN_IDENT) {
|
||||
report(p, "Invalid token after '.' where an identifier was expected");
|
||||
parser_report(p, "Invalid token after '.' where an identifier was expected");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -877,6 +907,7 @@ Node *parse_atom(Parser *p)
|
||||
return NULL;
|
||||
|
||||
child->type = NODE_VALUE_STR;
|
||||
child->text = t.sval;
|
||||
child->sval = t.sval;
|
||||
|
||||
Node *parent = alloc_node(p);
|
||||
@@ -884,6 +915,7 @@ Node *parse_atom(Parser *p)
|
||||
return NULL;
|
||||
|
||||
parent->type = NODE_SELECT;
|
||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
parent->left = ret;
|
||||
parent->right = child;
|
||||
|
||||
@@ -897,7 +929,7 @@ Node *parse_atom(Parser *p)
|
||||
|
||||
t = next_token(p);
|
||||
if (t.type != TOKEN_BRACKET_CLOSE) {
|
||||
report(p, "Missing token ']'");
|
||||
parser_report(p, "Missing token ']'");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -906,12 +938,13 @@ Node *parse_atom(Parser *p)
|
||||
return NULL;
|
||||
|
||||
parent->type = NODE_SELECT;
|
||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
parent->left = ret;
|
||||
parent->right = child;
|
||||
|
||||
ret = parent;
|
||||
|
||||
} else if (t.type == TOKEN_PAREN_OPEN) {
|
||||
} else if (t.type == TOKEN_PAREN_OPEN && ret->type == NODE_VALUE_VAR) {
|
||||
|
||||
Node *arg_head;
|
||||
Node **arg_tail = &arg_head;
|
||||
@@ -936,7 +969,7 @@ Node *parse_atom(Parser *p)
|
||||
break;
|
||||
|
||||
if (t.type != TOKEN_COMMA) {
|
||||
report(p, "Expected ',' after argument in function call");
|
||||
parser_report(p, "Expected ',' after argument in function call");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -949,6 +982,7 @@ Node *parse_atom(Parser *p)
|
||||
return NULL;
|
||||
|
||||
parent->type = NODE_FUNC_CALL;
|
||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
parent->left = ret;
|
||||
parent->right = arg_head;
|
||||
|
||||
@@ -963,7 +997,7 @@ Node *parse_atom(Parser *p)
|
||||
return ret;
|
||||
}
|
||||
|
||||
Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int flags)
|
||||
Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int start, int flags)
|
||||
{
|
||||
for (;;) {
|
||||
|
||||
@@ -974,6 +1008,8 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int flags)
|
||||
break;
|
||||
}
|
||||
|
||||
int right_start = p->s.cur;
|
||||
|
||||
Node *right = parse_atom(p);
|
||||
if (right == NULL)
|
||||
return NULL;
|
||||
@@ -992,7 +1028,7 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int flags)
|
||||
if (p2 <= p1 && (p1 != p2 || !right_associative(t2)))
|
||||
break;
|
||||
|
||||
right = parse_expr_inner(p, right, p1 + (p2 > p1), flags);
|
||||
right = parse_expr_inner(p, right, p1 + (p2 > p1), right_start, flags);
|
||||
if (right == NULL)
|
||||
return NULL;
|
||||
}
|
||||
@@ -1001,6 +1037,7 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int flags)
|
||||
if (parent == NULL)
|
||||
return NULL;
|
||||
|
||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
parent->left = left;
|
||||
parent->right = right;
|
||||
|
||||
@@ -1016,7 +1053,7 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int flags)
|
||||
case TOKEN_OPER_DIV: parent->type = NODE_OPER_DIV; break;
|
||||
case TOKEN_OPER_MOD: parent->type = NODE_OPER_MOD; break;
|
||||
default:
|
||||
report(p, "Operator not implemented");
|
||||
parser_report(p, "Operator not implemented");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1028,11 +1065,13 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int flags)
|
||||
|
||||
Node *parse_expr(Parser *p, int flags)
|
||||
{
|
||||
int start = p->s.cur;
|
||||
|
||||
Node *left = parse_atom(p);
|
||||
if (left == NULL)
|
||||
return NULL;
|
||||
|
||||
return parse_expr_inner(p, left, 0, flags);
|
||||
return parse_expr_inner(p, left, 0, start, flags);
|
||||
}
|
||||
|
||||
Node *parse_expr_stmt(Parser *p, int opflags)
|
||||
@@ -1046,9 +1085,11 @@ Node *parse_expr_stmt(Parser *p, int opflags)
|
||||
|
||||
Node *parse_ifelse_stmt(Parser *p, int opflags)
|
||||
{
|
||||
int start = p->s.cur;
|
||||
|
||||
Token t = next_token(p);
|
||||
if (t.type != TOKEN_KWORD_IF) {
|
||||
report(p, "Missing 'if' keyword before if statement");
|
||||
parser_report(p, "Missing 'if' keyword before if statement");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1058,7 +1099,7 @@ Node *parse_ifelse_stmt(Parser *p, int opflags)
|
||||
|
||||
t = next_token(p);
|
||||
if (t.type != TOKEN_COLON) {
|
||||
report(p, "Missing ':' after if condition");
|
||||
parser_report(p, "Missing ':' after if condition");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1085,6 +1126,7 @@ Node *parse_ifelse_stmt(Parser *p, int opflags)
|
||||
return NULL;
|
||||
|
||||
parent->type = NODE_IFELSE;
|
||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
parent->left = if_stmt;
|
||||
parent->right = else_stmt;
|
||||
parent->cond = cond;
|
||||
@@ -1094,15 +1136,17 @@ Node *parse_ifelse_stmt(Parser *p, int opflags)
|
||||
|
||||
Node *parse_for_stmt(Parser *p, int opflags)
|
||||
{
|
||||
int start = p->s.cur;
|
||||
|
||||
Token t = next_token(p);
|
||||
if (t.type != TOKEN_KWORD_FOR) {
|
||||
report(p, "Missing 'for' keyword at the start of a for statement");
|
||||
parser_report(p, "Missing 'for' keyword at the start of a for statement");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
t = next_token(p);
|
||||
if (t.type != TOKEN_IDENT) {
|
||||
report(p, "Missing iteraion variable name in for statement");
|
||||
parser_report(p, "Missing iteraion variable name in for statement");
|
||||
return NULL;
|
||||
}
|
||||
String var1 = t.sval;
|
||||
@@ -1114,7 +1158,7 @@ Node *parse_for_stmt(Parser *p, int opflags)
|
||||
|
||||
t = next_token(p);
|
||||
if (t.type != TOKEN_IDENT) {
|
||||
report(p, "Missing iteration variable name after ',' in for statement");
|
||||
parser_report(p, "Missing iteration variable name after ',' in for statement");
|
||||
return NULL;
|
||||
}
|
||||
var2 = t.sval;
|
||||
@@ -1123,7 +1167,7 @@ Node *parse_for_stmt(Parser *p, int opflags)
|
||||
}
|
||||
|
||||
if (t.type != TOKEN_KWORD_IN) {
|
||||
report(p, "Missing 'in' keyword after iteration variable name in for statement");
|
||||
parser_report(p, "Missing 'in' keyword after iteration variable name in for statement");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1133,7 +1177,7 @@ Node *parse_for_stmt(Parser *p, int opflags)
|
||||
|
||||
t = next_token(p);
|
||||
if (t.type != TOKEN_COLON) {
|
||||
report(p, "Missing ':' after for statement set expression");
|
||||
parser_report(p, "Missing ':' after for statement set expression");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1146,6 +1190,7 @@ Node *parse_for_stmt(Parser *p, int opflags)
|
||||
return NULL;
|
||||
|
||||
parent->type = NODE_FOR;
|
||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
parent->left = body;
|
||||
parent->for_var1 = var1;
|
||||
parent->for_var2 = var2;
|
||||
@@ -1156,9 +1201,11 @@ Node *parse_for_stmt(Parser *p, int opflags)
|
||||
|
||||
Node *parse_while_stmt(Parser *p, int opflags)
|
||||
{
|
||||
int start = p->s.cur;
|
||||
|
||||
Token t = next_token(p);
|
||||
if (t.type != TOKEN_KWORD_WHILE) {
|
||||
report(p, "Missing keyword 'while' at the start of a while statement");
|
||||
parser_report(p, "Missing keyword 'while' at the start of a while statement");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1168,7 +1215,7 @@ Node *parse_while_stmt(Parser *p, int opflags)
|
||||
|
||||
t = next_token(p);
|
||||
if (t.type != TOKEN_COLON) {
|
||||
report(p, "Missing token ':' after while statement condition");
|
||||
parser_report(p, "Missing token ':' after while statement condition");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1181,6 +1228,7 @@ Node *parse_while_stmt(Parser *p, int opflags)
|
||||
return NULL;
|
||||
|
||||
parent->type = NODE_WHILE;
|
||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
parent->left = stmt;
|
||||
parent->cond = cond;
|
||||
|
||||
@@ -1189,10 +1237,12 @@ Node *parse_while_stmt(Parser *p, int opflags)
|
||||
|
||||
Node *parse_block_stmt(Parser *p, b32 curly)
|
||||
{
|
||||
int start = p->s.cur;
|
||||
|
||||
if (curly) {
|
||||
Token t = next_token(p);
|
||||
if (t.type != TOKEN_CURLY_OPEN) {
|
||||
report(p, "Missing '{' at the start of a block statement");
|
||||
parser_report(p, "Missing '{' at the start of a block statement");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -1228,6 +1278,7 @@ Node *parse_block_stmt(Parser *p, b32 curly)
|
||||
return NULL;
|
||||
|
||||
parent->type = NODE_BLOCK;
|
||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
parent->left = head;
|
||||
|
||||
return parent;
|
||||
@@ -1235,22 +1286,24 @@ Node *parse_block_stmt(Parser *p, b32 curly)
|
||||
|
||||
Node *parse_func_decl(Parser *p, int opflags)
|
||||
{
|
||||
int start = p->s.cur;
|
||||
|
||||
Token t = next_token(p);
|
||||
if (t.type != TOKEN_KWORD_FUN) {
|
||||
report(p, "Missing keyword 'fun' at the start of a function declaration");
|
||||
parser_report(p, "Missing keyword 'fun' at the start of a function declaration");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
t = next_token(p);
|
||||
if (t.type != TOKEN_IDENT) {
|
||||
report(p, "Missing function name after 'fun' keyword");
|
||||
parser_report(p, "Missing function name after 'fun' keyword");
|
||||
return NULL;
|
||||
}
|
||||
String name = t.sval;
|
||||
|
||||
t = next_token(p);
|
||||
if (t.type != TOKEN_PAREN_OPEN) {
|
||||
report(p, "Missing '(' after function name in declaration");
|
||||
parser_report(p, "Missing '(' after function name in declaration");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1264,9 +1317,11 @@ Node *parse_func_decl(Parser *p, int opflags)
|
||||
|
||||
for (;;) {
|
||||
|
||||
int arg_start = p->s.cur;
|
||||
|
||||
t = next_token(p);
|
||||
if (t.type != TOKEN_IDENT) {
|
||||
report(p, "Missing argument name in function declaration");
|
||||
parser_report(p, "Missing argument name in function declaration");
|
||||
return NULL;
|
||||
}
|
||||
String argname = t.sval;
|
||||
@@ -1276,6 +1331,7 @@ Node *parse_func_decl(Parser *p, int opflags)
|
||||
return NULL;
|
||||
|
||||
node->type = NODE_FUNC_ARG;
|
||||
node->text = (String) { p->s.src + arg_start, p->s.cur - arg_start };
|
||||
node->sval = argname;
|
||||
|
||||
*arg_tail = node;
|
||||
@@ -1305,6 +1361,7 @@ Node *parse_func_decl(Parser *p, int opflags)
|
||||
return NULL;
|
||||
|
||||
parent->type = NODE_FUNC_DECL;
|
||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
parent->func_name = name;
|
||||
parent->func_args = arg_head;
|
||||
parent->func_body = body;
|
||||
@@ -1314,15 +1371,17 @@ Node *parse_func_decl(Parser *p, int opflags)
|
||||
|
||||
Node *parse_var_decl(Parser *p, int opflags)
|
||||
{
|
||||
int start = p->s.cur;
|
||||
|
||||
Token t = next_token(p);
|
||||
if (t.type != TOKEN_KWORD_LET) {
|
||||
report(p, "Missing keyword 'let' at the start of a variable declaration");
|
||||
parser_report(p, "Missing keyword 'let' at the start of a variable declaration");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
t = next_token(p);
|
||||
if (t.type != TOKEN_IDENT) {
|
||||
report(p, "Missing variable name after 'let' keyword");
|
||||
parser_report(p, "Missing variable name after 'let' keyword");
|
||||
return NULL;
|
||||
}
|
||||
String name = t.sval;
|
||||
@@ -1347,6 +1406,7 @@ Node *parse_var_decl(Parser *p, int opflags)
|
||||
return NULL;
|
||||
|
||||
parent->type = NODE_VAR_DECL;
|
||||
parent->text = (String) { p->s.src + start, p->s.cur - start };
|
||||
parent->var_name = name;
|
||||
parent->var_value = value;
|
||||
|
||||
@@ -1555,14 +1615,13 @@ void print_node(Node *node)
|
||||
}
|
||||
printf(">");
|
||||
|
||||
|
||||
Node *child = node->child;
|
||||
while (child) {
|
||||
print_node(child);
|
||||
child = child->next;
|
||||
}
|
||||
|
||||
printf("<%.*s>",
|
||||
printf("</%.*s>",
|
||||
node->tagname.len,
|
||||
node->tagname.ptr
|
||||
);
|
||||
@@ -1676,7 +1735,7 @@ void print_node(Node *node)
|
||||
node->var_name.ptr);
|
||||
if (node->var_value) {
|
||||
printf(" = ");
|
||||
print_node(node);
|
||||
print_node(node->var_value);
|
||||
}
|
||||
printf(";");
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ typedef enum {
|
||||
NODE_FOR,
|
||||
NODE_WHILE,
|
||||
NODE_SELECT,
|
||||
NODE_NESTED,
|
||||
NODE_OPER_POS,
|
||||
NODE_OPER_NEG,
|
||||
NODE_OPER_ASS,
|
||||
@@ -43,6 +44,7 @@ typedef struct Node Node;
|
||||
struct Node {
|
||||
NodeType type;
|
||||
Node *next;
|
||||
String text;
|
||||
|
||||
Node *key;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user