Improve assembler

This commit is contained in:
2025-08-03 12:54:08 +02:00
parent 6d98b4eee5
commit 0f80f95de5
9 changed files with 692 additions and 134 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
all: 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
+7 -5
View File
@@ -1,6 +1,7 @@
title = "My Website"
posts = [ let title = "My Website"
let posts = [
{ {
name: "Post Title 1", name: "Post Title 1",
date: "1 Jan 2025", date: "1 Jan 2025",
@@ -21,7 +22,7 @@ posts = [
fun render_comment(c) fun render_comment(c)
<div class="comment"> <div class="comment">
<a>\{c.author} (\c.date)</a> <a>\c.author (\c.date)</a>
<p>\c.content</p> <p>\c.content</p>
<div class="comment-children"> <div class="comment-children">
\for child in c.children: \for child in c.children:
@@ -34,11 +35,12 @@ fun render_comment(c)
<title>\title</title> <title>\title</title>
</head> </head>
<body> <body>
<a>This is regular text</a>
\for post in posts: \for post in posts:
<div class="post"> <div class="post">
<a>\{post.title} (\post.date)</a> <a>\post.title (\post.date)</a>
\for comment in post.comments: \for comment in post.comments:
render_comment(comment) render_comment(comment)
</div> </div>
</body> </body>
</html> </html>
View File
+487 -70
View File
@@ -2,15 +2,15 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h>
#ifndef WL_AMALGAMATION #ifndef WL_AMALGAMATION
#include "parse.h" #include "parse.h"
#include "assemble.h" #include "assemble.h"
#endif #endif
#define MAX_SCOPES 32 #define MAX_SCOPES 32
#define MAX_VARS 1024 #define MAX_SYMBOLS 1024
#define MAX_STRING_LITERALS 1024
typedef struct FunctionCall FunctionCall; typedef struct FunctionCall FunctionCall;
struct FunctionCall { struct FunctionCall {
@@ -19,23 +19,31 @@ struct FunctionCall {
int off; int off;
}; };
typedef enum {
SYMBOL_VAR,
SYMBOL_FUNC,
} SymbolType;
typedef struct { typedef struct {
String name; SymbolType type;
} Variable; String name;
int off;
} Symbol;
typedef enum { typedef enum {
SCOPE_GLOBAL,
SCOPE_FUNC, SCOPE_FUNC,
SCOPE_FOR, SCOPE_FOR,
SCOPE_WHILE, SCOPE_WHILE,
SCOPE_IF, SCOPE_IF,
SCOPE_ELSE, SCOPE_ELSE,
SCOPE_BLOCK,
} ScopeType; } ScopeType;
typedef struct { typedef struct {
ScopeType type; ScopeType type;
int var_base; int sym_base;
// TODO FunctionCall* calls;
FunctionCall *calls;
} Scope; } Scope;
typedef struct { typedef struct {
@@ -51,8 +59,8 @@ typedef struct {
OutputBuffer out; OutputBuffer out;
int num_vars; int num_syms;
Variable vars[MAX_VARS]; Symbol syms[MAX_SYMBOLS];
int num_scopes; int num_scopes;
Scope scopes[MAX_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)); 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) int current_offset(OutputBuffer *out)
{ {
return out->len; return out->len;
@@ -199,33 +212,63 @@ int count_nodes(Node *head)
return n; 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 = a->num_syms-1; i >= a->scopes[a->num_scopes-1].sym_base; i--)
for (int i = scope->var_base; i < a->num_vars; i++) if (streq(a->syms[i].name, name))
if (streq(name, a->vars[i].name))
return i; return i;
assembler_report(a, "Undeclared variable '%.*s'", name.len, name.ptr);
return -1; return -1;
} }
int declare_var(Assembler *a, String name) int find_symbol_in_function(Assembler *a, String name)
{ {
if (a->num_vars == MAX_VARS) { assert(a->num_scopes > 0);
assembler_report(a, "Variable limit reached");
// 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; return -1;
} }
Scope *scope = &a->scopes[a->num_scopes-1]; if (find_symbol_in_local_scope(a, name) >= 0) {
for (int i = scope->var_base; i < a->num_vars; i++) assembler_report(a, "Symbol '%.*s' already declared in this scope",
if (streq(name, a->vars[i].name)) { name.len, name.ptr);
assembler_report(a, "Variable '%.*s' declared twice", name.len, name.ptr); return -1;
return -1; }
}
int idx = a->num_vars++; a->syms[a->num_syms] = (Symbol) { SYMBOL_VAR, name, -1 };
a->vars[idx] = (Variable) { name }; return a->num_syms++;
return idx - scope->var_base; }
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; break;
case NODE_SELECT: case NODE_SELECT:
case NODE_NESTED:
case NODE_FUNC_CALL: case NODE_FUNC_CALL:
case NODE_OPER_POS: case NODE_OPER_POS:
case NODE_OPER_NEG: case NODE_OPER_NEG:
@@ -299,8 +343,70 @@ b32 is_expr(Node *node)
return false; 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) void assemble_node(Assembler *a, Node *node)
{ {
printf("Compiling [%.*s]\n", node->text.len, node->text.ptr);
switch (node->type) { switch (node->type) {
case NODE_FUNC_DECL: case NODE_FUNC_DECL:
@@ -308,30 +414,44 @@ void assemble_node(Assembler *a, Node *node)
append_u8(&a->out, OPCODE_JUMP); append_u8(&a->out, OPCODE_JUMP);
int p1 = append_u32(&a->out, 0); 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]; Node *args[32];
if (arg_count > COUNT(args)) { int arg_count = 0;
assembler_report(a, "Argument limit reached"); Node *arg = node->func_args;
return; 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--) { 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; if (idx < 0) return;
append_u8(&a->out, OPCODE_SETV); 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)) { if (is_expr(node->func_body)) {
assemble_node(a, node->func_body); assemble_node(a, node->func_body);
append_u8(&a->out, OPCODE_RET); append_u8(&a->out, OPCODE_RET);
} else } else {
assemble_node(a, node->func_body); 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); patch_with_current_offset(&a->out, p1);
} }
@@ -350,37 +470,30 @@ void assemble_node(Assembler *a, Node *node)
arg = arg->next; arg = arg->next;
} }
if (func->type == NODE_VALUE_VAR) { assert(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);
FunctionCall *call = alloc(a->a, sizeof(FunctionCall), _Alignof(FunctionCall)); append_u8(&a->out, OPCODE_CALL);
if (call == NULL) { append_u8(&a->out, arg_count);
assembler_report(a, "Out of memory"); int p = append_u32(&a->out, 0);
return;
}
call->name = func->sval;
call->off = p;
Scope *scope = &a->scopes[a->num_scopes-1]; FunctionCall *call = alloc(a->a, sizeof(FunctionCall), _Alignof(FunctionCall));
if (call == NULL) {
call->next = scope->calls; assembler_report(a, "Out of memory");
scope->calls = call; return;
} else {
assemble_node(a, func);
assemble_node(a, arg);
append_u8(&a->out, OPCODE_DCALL);
append_u8(&a->out, arg_count);
} }
call->name = func->sval;
call->off = p;
Scope *scope = &a->scopes[a->num_scopes-1];
call->next = scope->calls;
scope->calls = call;
} }
break; break;
case NODE_VAR_DECL: 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 (idx < 0) return;
if (node->var_value) { if (node->var_value) {
@@ -393,13 +506,19 @@ void assemble_node(Assembler *a, Node *node)
case NODE_BLOCK: case NODE_BLOCK:
{ {
Node *stmt = node->child; int ret = push_scope(a, SCOPE_BLOCK);
if (ret < 0) return;
Node *stmt = node->left;
while (stmt) { while (stmt) {
assemble_node(a, stmt); assemble_node(a, stmt);
if (is_expr(stmt)) if (is_expr(stmt))
append_u8(&a->out, OPCODE_POP); append_u8(&a->out, OPCODE_POP);
stmt = stmt->next; stmt = stmt->next;
} }
ret = pop_scope(a);
if (ret < 0) return;
} }
break; break;
@@ -431,15 +550,27 @@ void assemble_node(Assembler *a, Node *node)
append_u8(&a->out, OPCODE_JIFP); append_u8(&a->out, OPCODE_JIFP);
int p1 = append_u32(&a->out, 0); int p1 = append_u32(&a->out, 0);
int ret = push_scope(a, SCOPE_IF);
if (ret < 0) return;
assemble_node(a, node->left); assemble_node(a, node->left);
ret = pop_scope(a);
if (ret < 0) return;
append_u8(&a->out, OPCODE_JUMP); append_u8(&a->out, OPCODE_JUMP);
int p2 = append_u32(&a->out, 0); int p2 = append_u32(&a->out, 0);
patch_with_current_offset(&a->out, p1); patch_with_current_offset(&a->out, p1);
ret = push_scope(a, SCOPE_ELSE);
if (ret < 0) return;
assemble_node(a, node->right); assemble_node(a, node->right);
ret = pop_scope(a);
if (ret < 0) return;
patch_with_current_offset(&a->out, p2); patch_with_current_offset(&a->out, p2);
} else { } else {
@@ -449,8 +580,14 @@ void assemble_node(Assembler *a, Node *node)
append_u8(&a->out, OPCODE_JIFP); append_u8(&a->out, OPCODE_JIFP);
int p1 = append_u32(&a->out, 0); int p1 = append_u32(&a->out, 0);
int ret = push_scope(a, SCOPE_IF);
if (ret < 0) return;
assemble_node(a, node->left); assemble_node(a, node->left);
ret = pop_scope(a);
if (ret < 0) return;
patch_with_current_offset(&a->out, p1); patch_with_current_offset(&a->out, p1);
} }
} }
@@ -473,8 +610,14 @@ void assemble_node(Assembler *a, Node *node)
append_u8(&a->out, OPCODE_JIFP); append_u8(&a->out, OPCODE_JIFP);
int p = append_u32(&a->out, 0); int p = append_u32(&a->out, 0);
int ret = push_scope(a, SCOPE_WHILE);
if (ret < 0) return;
assemble_node(a, node->left); assemble_node(a, node->left);
ret = pop_scope(a);
if (ret < 0) return;
append_u8(&a->out, OPCODE_JUMP); append_u8(&a->out, OPCODE_JUMP);
append_u32(&a->out, start); append_u32(&a->out, start);
@@ -485,7 +628,16 @@ void assemble_node(Assembler *a, Node *node)
case NODE_FOR: case NODE_FOR:
{ {
assemble_node(a, node->for_set); assemble_node(a, node->for_set);
// TODO // 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; break;
@@ -572,8 +724,16 @@ void assemble_node(Assembler *a, Node *node)
break; break;
case NODE_VALUE_VAR: 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; break;
case NODE_VALUE_HTML: case NODE_VALUE_HTML:
@@ -598,7 +758,7 @@ void assemble_node(Assembler *a, Node *node)
case NODE_VALUE_MAP: case NODE_VALUE_MAP:
{ {
append_u8(&a->out, OPCODE_PUSHM); 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; Node *child = node->child;
while (child) { while (child) {
@@ -621,6 +781,10 @@ void assemble_node(Assembler *a, Node *node)
} }
break; break;
case NODE_NESTED:
assemble_node(a, node->left);
break;
case NODE_OPER_ASS: case NODE_OPER_ASS:
{ {
Node *dst = node->left; Node *dst = node->left;
@@ -628,12 +792,22 @@ void assemble_node(Assembler *a, Node *node)
if (dst->type == NODE_VALUE_VAR) { if (dst->type == NODE_VALUE_VAR) {
int idx = find_variable(a, dst->sval); String name = dst->sval;
if (idx < 0) return;
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); assemble_node(a, src);
append_u8(&a->out, OPCODE_SETV); 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) { } 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); assemble_node(&a, root);
append_u8(&a.out, OPCODE_NOPE); append_u8(&a.out, OPCODE_NOPE);
Program p; ret = pop_scope(&a);
// TODO 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 }; 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
View File
@@ -11,6 +11,7 @@ enum {
OPCODE_PUSHV = 0x04, OPCODE_PUSHV = 0x04,
OPCODE_PUSHA = 0x05, OPCODE_PUSHA = 0x05,
OPCODE_PUSHM = 0x06, OPCODE_PUSHM = 0x06,
OPCODE_PUSHN = 0x21,
OPCODE_POP = 0x07, OPCODE_POP = 0x07,
OPCODE_NEG = 0x08, OPCODE_NEG = 0x08,
OPCODE_EQL = 0x09, OPCODE_EQL = 0x09,
@@ -25,13 +26,12 @@ enum {
OPCODE_SETV = 0x12, OPCODE_SETV = 0x12,
OPCODE_JUMP = 0x13, OPCODE_JUMP = 0x13,
OPCODE_JIFP = 0x14, OPCODE_JIFP = 0x14,
OPCODE_SCALL = 0x15, OPCODE_CALL = 0x15,
OPCODE_DCALL = 0x16, OPCODE_RET = 0x16,
OPCODE_RET = 0x17, OPCODE_APPEND = 0x17,
OPCODE_APPEND = 0x18, OPCODE_INSERT1 = 0x18,
OPCODE_INSERT1 = 0x19, OPCODE_INSERT2 = 0x19,
OPCODE_INSERT2 = 0x20, OPCODE_SELECT = 0x20,
OPCODE_SELECT = 0x21,
}; };
typedef struct { typedef struct {
@@ -44,6 +44,7 @@ typedef struct {
int errlen; int errlen;
} AssembleResult; } 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 #endif // WL_ASSEMBLE_INCLUDED
+66
View File
@@ -6,6 +6,72 @@
#define FRAME_LIMIT 128 #define FRAME_LIMIT 128
#define EVAL_STACK_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 { typedef struct {
} Frame; } Frame;
+16 -5
View File
@@ -3,6 +3,7 @@
#include "file.h" #include "file.h"
#include "parse.h" #include "parse.h"
#include "assemble.h"
int main(void) int main(void)
{ {
@@ -17,14 +18,24 @@ int main(void)
char *mem = malloc(1<<20); char *mem = malloc(1<<20);
Arena a = { mem, 1<<20, 0 }; Arena a = { mem, 1<<20, 0 };
ParseResult result = parse(src, &a, err, COUNT(err)); ParseResult parse_result = parse(src, &a, err, COUNT(err));
if (result.node == NULL) { if (parse_result.node == NULL) {
printf("%.*s\n", result.errlen, err); printf("%.*s\n", parse_result.errlen, err);
return -1; return -1;
} }
print_node(result.node); print_node(parse_result.node);
fflush(stdout); 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(src.ptr);
free(mem); free(mem);
+104 -45
View File
@@ -158,7 +158,7 @@ String tok2str(Token token, char *buf, int max)
return S("???"); return S("???");
} }
void report(Parser *p, char *fmt, ...) void parser_report(Parser *p, char *fmt, ...)
{ {
if (p->errmax == 0 || p->errlen > 0) if (p->errmax == 0 || p->errlen > 0)
return; return;
@@ -192,7 +192,7 @@ Node *alloc_node(Parser *p)
{ {
Node *n = alloc(p->a, sizeof(Node), _Alignof(Node)); Node *n = alloc(p->a, sizeof(Node), _Alignof(Node));
if (n == NULL) { if (n == NULL) {
report(p, "Out of memory"); parser_report(p, "Out of memory");
return NULL; return NULL;
} }
@@ -262,7 +262,7 @@ Token next_token(Parser *p)
do { do {
int d = p->s.src[p->s.cur++] - '0'; int d = p->s.src[p->s.cur++] - '0';
if (buf > (UINT64_MAX - d) / 10) { if (buf > (UINT64_MAX - d) / 10) {
report(p, "Integer literal overflow"); parser_report(p, "Integer literal overflow");
return (Token) { .type=TOKEN_ERROR }; return (Token) { .type=TOKEN_ERROR };
} }
buf = buf * 10 + d; buf = buf * 10 + d;
@@ -296,7 +296,7 @@ Token next_token(Parser *p)
buf = NULL; buf = NULL;
if (buf == NULL) { if (buf == NULL) {
report(p, "Out of memory"); parser_report(p, "Out of memory");
return (Token) { .type=TOKEN_ERROR }; return (Token) { .type=TOKEN_ERROR };
} }
@@ -310,12 +310,12 @@ Token next_token(Parser *p)
} }
if (p->s.cur == p->s.len) { 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 }; return (Token) { .type=TOKEN_ERROR };
} }
if (!is_printable(p->s.src[p->s.cur])) { 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 }; return (Token) { .type=TOKEN_ERROR };
} }
@@ -324,7 +324,7 @@ Token next_token(Parser *p)
p->s.cur++; p->s.cur++;
if (p->s.cur == p->s.len) { 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 }; return (Token) { .type=TOKEN_ERROR };
} }
@@ -350,7 +350,7 @@ Token next_token(Parser *p)
break; break;
default: default:
report(p, "Invalid character after escape character \\"); parser_report(p, "Invalid character after escape character \\");
return (Token) { .type=TOKEN_ERROR }; 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_COMMA };
if (consume_str(&p->s, S(":"))) return (Token) { .type=TOKEN_COLON }; 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 }; return (Token) { .type=TOKEN_ERROR };
} }
@@ -411,12 +411,14 @@ Node *parse_expr(Parser *p, int opflags);
Node *parse_html(Parser *p) Node *parse_html(Parser *p)
{ {
// NOTE: The first < was already consumed // NOTE: The first < was already consumed
int node_offset = p->s.cur-1;
Token t = next_token(p); Token t = next_token(p);
if (t.type != TOKEN_IDENT) { if (t.type != TOKEN_IDENT) {
char buf[1<<8]; char buf[1<<8];
String ts = tok2str(t, buf, COUNT(buf)); 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; return NULL;
} }
String tagname = t.sval; String tagname = t.sval;
@@ -426,6 +428,8 @@ Node *parse_html(Parser *p)
for (;;) { for (;;) {
int param_offset = p->s.cur;
String attr_name; String attr_name;
Node *attr_value; Node *attr_value;
@@ -433,7 +437,7 @@ Node *parse_html(Parser *p)
if (t.type == TOKEN_OPER_GRT) if (t.type == TOKEN_OPER_GRT)
break; break;
if (t.type != TOKEN_IDENT) { if (t.type != TOKEN_IDENT) {
report(p, "Invalid token inside HTML tag"); parser_report(p, "Invalid token inside HTML tag");
return NULL; return NULL;
} }
attr_name = t.sval; attr_name = t.sval;
@@ -456,6 +460,7 @@ Node *parse_html(Parser *p)
return NULL; return NULL;
child->type = NODE_HTML_PARAM; 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_name = attr_name;
child->attr_value = attr_value; child->attr_value = attr_value;
@@ -483,6 +488,7 @@ Node *parse_html(Parser *p)
return NULL; return NULL;
child->type = NODE_VALUE_STR; 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 }; child->sval = (String) { p->s.src + off, p->s.cur - off };
*tail = child; *tail = child;
@@ -492,7 +498,7 @@ Node *parse_html(Parser *p)
if (p->s.cur == p->s.len || p->s.src[p->s.cur] == '<') if (p->s.cur == p->s.len || p->s.src[p->s.cur] == '<')
break; break;
p->s.cur++; // Consume \ p->s.cur++; // Consume "\"
{ {
Node *child = parse_stmt(p, IGNORE_LSS); Node *child = parse_stmt(p, IGNORE_LSS);
@@ -505,7 +511,7 @@ Node *parse_html(Parser *p)
} }
if (p->s.cur == p->s.len) { if (p->s.cur == p->s.len) {
report(p, "Missing closing HTML tag"); parser_report(p, "Missing closing HTML tag");
return NULL; return NULL;
} }
p->s.cur++; // Consume < p->s.cur++; // Consume <
@@ -517,7 +523,7 @@ Node *parse_html(Parser *p)
if (t.type == TOKEN_IDENT && streqcase(t.sval, tagname)) { if (t.type == TOKEN_IDENT && streqcase(t.sval, tagname)) {
t = next_token(p); t = next_token(p);
if (t.type != TOKEN_OPER_GRT) { 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; return NULL;
} }
break; break;
@@ -541,6 +547,7 @@ Node *parse_html(Parser *p)
return NULL; return NULL;
parent->type = NODE_VALUE_HTML; parent->type = NODE_VALUE_HTML;
parent->text = (String) { p->s.src + node_offset, p->s.cur - node_offset };
parent->tagname = tagname; parent->tagname = tagname;
parent->params = param_head; parent->params = param_head;
parent->child = head; parent->child = head;
@@ -552,6 +559,8 @@ Node *parse_array(Parser *p)
{ {
// Left bracket already consumed // Left bracket already consumed
int start = p->s.cur;
Node *head; Node *head;
Node **tail = &head; Node **tail = &head;
@@ -591,6 +600,7 @@ Node *parse_array(Parser *p)
return NULL; return NULL;
parent->type = NODE_VALUE_ARRAY; parent->type = NODE_VALUE_ARRAY;
parent->text = (String) { p->s.src + start, p->s.cur - start };
parent->child = head; parent->child = head;
return parent; return parent;
@@ -600,6 +610,8 @@ Node *parse_map(Parser *p)
{ {
// Left bracket already consumed // Left bracket already consumed
int start = p->s.cur;
Node *head; Node *head;
Node **tail = &head; Node **tail = &head;
@@ -622,6 +634,7 @@ Node *parse_map(Parser *p)
return NULL; return NULL;
key->type = NODE_VALUE_STR; key->type = NODE_VALUE_STR;
key->text = t.sval;
key->sval = t.sval; key->sval = t.sval;
} else { } else {
@@ -634,7 +647,7 @@ Node *parse_map(Parser *p)
t = next_token(p); t = next_token(p);
if (t.type != TOKEN_COLON) { if (t.type != TOKEN_COLON) {
report(p, "Missing ':' after key inside map literal"); parser_report(p, "Missing ':' after key inside map literal");
return NULL; return NULL;
} }
@@ -667,6 +680,7 @@ Node *parse_map(Parser *p)
return NULL; return NULL;
parent->type = NODE_VALUE_MAP; parent->type = NODE_VALUE_MAP;
parent->text = (String) { p->s.src + start, p->s.cur - start };
parent->child = head; parent->child = head;
return parent; return parent;
@@ -716,6 +730,8 @@ b32 right_associative(Token t)
Node *parse_atom(Parser *p) Node *parse_atom(Parser *p)
{ {
int start = p->s.cur;
Token t = next_token(p); Token t = next_token(p);
Node *ret; Node *ret;
@@ -731,6 +747,7 @@ Node *parse_atom(Parser *p)
return NULL; return NULL;
parent->type = NODE_OPER_POS; parent->type = NODE_OPER_POS;
parent->text = (String) { p->s.src + start, p->s.cur - start };
parent->left = child; parent->left = child;
ret = parent; ret = parent;
@@ -748,6 +765,7 @@ Node *parse_atom(Parser *p)
return NULL; return NULL;
parent->type = NODE_OPER_NEG; parent->type = NODE_OPER_NEG;
parent->text = (String) { p->s.src + start, p->s.cur - start };
parent->left = child; parent->left = child;
ret = parent; ret = parent;
@@ -761,6 +779,7 @@ Node *parse_atom(Parser *p)
return NULL; return NULL;
node->type = NODE_VALUE_VAR; node->type = NODE_VALUE_VAR;
node->text = (String) { p->s.src + start, p->s.cur - start };
node->sval = t.sval; node->sval = t.sval;
ret = node; ret = node;
@@ -774,6 +793,7 @@ Node *parse_atom(Parser *p)
return NULL; return NULL;
node->type = NODE_VALUE_INT; node->type = NODE_VALUE_INT;
node->text = (String) { p->s.src + start, p->s.cur - start };
node->ival = t.uval; node->ival = t.uval;
ret = node; ret = node;
@@ -787,6 +807,7 @@ Node *parse_atom(Parser *p)
return NULL; return NULL;
node->type = NODE_VALUE_FLOAT; node->type = NODE_VALUE_FLOAT;
node->text = (String) { p->s.src + start, p->s.cur - start };
node->dval = t.dval; node->dval = t.dval;
ret = node; ret = node;
@@ -800,6 +821,7 @@ Node *parse_atom(Parser *p)
return NULL; return NULL;
node->type = NODE_VALUE_STR; node->type = NODE_VALUE_STR;
node->text = (String) { p->s.src + start, p->s.cur - start };
node->sval = t.sval; node->sval = t.sval;
ret = node; ret = node;
@@ -824,11 +846,19 @@ Node *parse_atom(Parser *p)
Token t = next_token(p); Token t = next_token(p);
if (t.type != TOKEN_PAREN_CLOSE) { if (t.type != TOKEN_PAREN_CLOSE) {
report(p, "Missing ')' after expression"); parser_report(p, "Missing ')' after expression");
return NULL; 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; break;
@@ -856,7 +886,7 @@ Node *parse_atom(Parser *p)
{ {
char buf[1<<8]; char buf[1<<8];
String str = tok2str(t, buf, COUNT(buf)); 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; return NULL;
} }
@@ -868,7 +898,7 @@ Node *parse_atom(Parser *p)
t = next_token(p); t = next_token(p);
if (t.type != TOKEN_IDENT) { 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; return NULL;
} }
@@ -877,6 +907,7 @@ Node *parse_atom(Parser *p)
return NULL; return NULL;
child->type = NODE_VALUE_STR; child->type = NODE_VALUE_STR;
child->text = t.sval;
child->sval = t.sval; child->sval = t.sval;
Node *parent = alloc_node(p); Node *parent = alloc_node(p);
@@ -884,6 +915,7 @@ Node *parse_atom(Parser *p)
return NULL; return NULL;
parent->type = NODE_SELECT; parent->type = NODE_SELECT;
parent->text = (String) { p->s.src + start, p->s.cur - start };
parent->left = ret; parent->left = ret;
parent->right = child; parent->right = child;
@@ -897,7 +929,7 @@ Node *parse_atom(Parser *p)
t = next_token(p); t = next_token(p);
if (t.type != TOKEN_BRACKET_CLOSE) { if (t.type != TOKEN_BRACKET_CLOSE) {
report(p, "Missing token ']'"); parser_report(p, "Missing token ']'");
return NULL; return NULL;
} }
@@ -906,12 +938,13 @@ Node *parse_atom(Parser *p)
return NULL; return NULL;
parent->type = NODE_SELECT; parent->type = NODE_SELECT;
parent->text = (String) { p->s.src + start, p->s.cur - start };
parent->left = ret; parent->left = ret;
parent->right = child; parent->right = child;
ret = parent; 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_head;
Node **arg_tail = &arg_head; Node **arg_tail = &arg_head;
@@ -936,7 +969,7 @@ Node *parse_atom(Parser *p)
break; break;
if (t.type != TOKEN_COMMA) { if (t.type != TOKEN_COMMA) {
report(p, "Expected ',' after argument in function call"); parser_report(p, "Expected ',' after argument in function call");
return NULL; return NULL;
} }
} }
@@ -949,6 +982,7 @@ Node *parse_atom(Parser *p)
return NULL; return NULL;
parent->type = NODE_FUNC_CALL; parent->type = NODE_FUNC_CALL;
parent->text = (String) { p->s.src + start, p->s.cur - start };
parent->left = ret; parent->left = ret;
parent->right = arg_head; parent->right = arg_head;
@@ -963,7 +997,7 @@ Node *parse_atom(Parser *p)
return ret; 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 (;;) { for (;;) {
@@ -974,6 +1008,8 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int flags)
break; break;
} }
int right_start = p->s.cur;
Node *right = parse_atom(p); Node *right = parse_atom(p);
if (right == NULL) if (right == NULL)
return 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))) if (p2 <= p1 && (p1 != p2 || !right_associative(t2)))
break; 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) if (right == NULL)
return NULL; return NULL;
} }
@@ -1001,6 +1037,7 @@ Node *parse_expr_inner(Parser *p, Node *left, int min_prec, int flags)
if (parent == NULL) if (parent == NULL)
return NULL; return NULL;
parent->text = (String) { p->s.src + start, p->s.cur - start };
parent->left = left; parent->left = left;
parent->right = right; 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_DIV: parent->type = NODE_OPER_DIV; break;
case TOKEN_OPER_MOD: parent->type = NODE_OPER_MOD; break; case TOKEN_OPER_MOD: parent->type = NODE_OPER_MOD; break;
default: default:
report(p, "Operator not implemented"); parser_report(p, "Operator not implemented");
return NULL; 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) Node *parse_expr(Parser *p, int flags)
{ {
int start = p->s.cur;
Node *left = parse_atom(p); Node *left = parse_atom(p);
if (left == NULL) if (left == NULL)
return 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) 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) Node *parse_ifelse_stmt(Parser *p, int opflags)
{ {
int start = p->s.cur;
Token t = next_token(p); Token t = next_token(p);
if (t.type != TOKEN_KWORD_IF) { 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; return NULL;
} }
@@ -1058,7 +1099,7 @@ Node *parse_ifelse_stmt(Parser *p, int opflags)
t = next_token(p); t = next_token(p);
if (t.type != TOKEN_COLON) { if (t.type != TOKEN_COLON) {
report(p, "Missing ':' after if condition"); parser_report(p, "Missing ':' after if condition");
return NULL; return NULL;
} }
@@ -1085,6 +1126,7 @@ Node *parse_ifelse_stmt(Parser *p, int opflags)
return NULL; return NULL;
parent->type = NODE_IFELSE; parent->type = NODE_IFELSE;
parent->text = (String) { p->s.src + start, p->s.cur - start };
parent->left = if_stmt; parent->left = if_stmt;
parent->right = else_stmt; parent->right = else_stmt;
parent->cond = cond; parent->cond = cond;
@@ -1094,15 +1136,17 @@ Node *parse_ifelse_stmt(Parser *p, int opflags)
Node *parse_for_stmt(Parser *p, int opflags) Node *parse_for_stmt(Parser *p, int opflags)
{ {
int start = p->s.cur;
Token t = next_token(p); Token t = next_token(p);
if (t.type != TOKEN_KWORD_FOR) { 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; return NULL;
} }
t = next_token(p); t = next_token(p);
if (t.type != TOKEN_IDENT) { 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; return NULL;
} }
String var1 = t.sval; String var1 = t.sval;
@@ -1114,7 +1158,7 @@ Node *parse_for_stmt(Parser *p, int opflags)
t = next_token(p); t = next_token(p);
if (t.type != TOKEN_IDENT) { 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; return NULL;
} }
var2 = t.sval; var2 = t.sval;
@@ -1123,7 +1167,7 @@ Node *parse_for_stmt(Parser *p, int opflags)
} }
if (t.type != TOKEN_KWORD_IN) { 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; return NULL;
} }
@@ -1133,7 +1177,7 @@ Node *parse_for_stmt(Parser *p, int opflags)
t = next_token(p); t = next_token(p);
if (t.type != TOKEN_COLON) { if (t.type != TOKEN_COLON) {
report(p, "Missing ':' after for statement set expression"); parser_report(p, "Missing ':' after for statement set expression");
return NULL; return NULL;
} }
@@ -1146,6 +1190,7 @@ Node *parse_for_stmt(Parser *p, int opflags)
return NULL; return NULL;
parent->type = NODE_FOR; parent->type = NODE_FOR;
parent->text = (String) { p->s.src + start, p->s.cur - start };
parent->left = body; parent->left = body;
parent->for_var1 = var1; parent->for_var1 = var1;
parent->for_var2 = var2; parent->for_var2 = var2;
@@ -1156,9 +1201,11 @@ Node *parse_for_stmt(Parser *p, int opflags)
Node *parse_while_stmt(Parser *p, int opflags) Node *parse_while_stmt(Parser *p, int opflags)
{ {
int start = p->s.cur;
Token t = next_token(p); Token t = next_token(p);
if (t.type != TOKEN_KWORD_WHILE) { 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; return NULL;
} }
@@ -1168,7 +1215,7 @@ Node *parse_while_stmt(Parser *p, int opflags)
t = next_token(p); t = next_token(p);
if (t.type != TOKEN_COLON) { if (t.type != TOKEN_COLON) {
report(p, "Missing token ':' after while statement condition"); parser_report(p, "Missing token ':' after while statement condition");
return NULL; return NULL;
} }
@@ -1181,6 +1228,7 @@ Node *parse_while_stmt(Parser *p, int opflags)
return NULL; return NULL;
parent->type = NODE_WHILE; parent->type = NODE_WHILE;
parent->text = (String) { p->s.src + start, p->s.cur - start };
parent->left = stmt; parent->left = stmt;
parent->cond = cond; parent->cond = cond;
@@ -1189,10 +1237,12 @@ Node *parse_while_stmt(Parser *p, int opflags)
Node *parse_block_stmt(Parser *p, b32 curly) Node *parse_block_stmt(Parser *p, b32 curly)
{ {
int start = p->s.cur;
if (curly) { if (curly) {
Token t = next_token(p); Token t = next_token(p);
if (t.type != TOKEN_CURLY_OPEN) { 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; return NULL;
} }
} }
@@ -1228,6 +1278,7 @@ Node *parse_block_stmt(Parser *p, b32 curly)
return NULL; return NULL;
parent->type = NODE_BLOCK; parent->type = NODE_BLOCK;
parent->text = (String) { p->s.src + start, p->s.cur - start };
parent->left = head; parent->left = head;
return parent; return parent;
@@ -1235,22 +1286,24 @@ Node *parse_block_stmt(Parser *p, b32 curly)
Node *parse_func_decl(Parser *p, int opflags) Node *parse_func_decl(Parser *p, int opflags)
{ {
int start = p->s.cur;
Token t = next_token(p); Token t = next_token(p);
if (t.type != TOKEN_KWORD_FUN) { 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; return NULL;
} }
t = next_token(p); t = next_token(p);
if (t.type != TOKEN_IDENT) { if (t.type != TOKEN_IDENT) {
report(p, "Missing function name after 'fun' keyword"); parser_report(p, "Missing function name after 'fun' keyword");
return NULL; return NULL;
} }
String name = t.sval; String name = t.sval;
t = next_token(p); t = next_token(p);
if (t.type != TOKEN_PAREN_OPEN) { 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; return NULL;
} }
@@ -1264,9 +1317,11 @@ Node *parse_func_decl(Parser *p, int opflags)
for (;;) { for (;;) {
int arg_start = p->s.cur;
t = next_token(p); t = next_token(p);
if (t.type != TOKEN_IDENT) { if (t.type != TOKEN_IDENT) {
report(p, "Missing argument name in function declaration"); parser_report(p, "Missing argument name in function declaration");
return NULL; return NULL;
} }
String argname = t.sval; String argname = t.sval;
@@ -1276,6 +1331,7 @@ Node *parse_func_decl(Parser *p, int opflags)
return NULL; return NULL;
node->type = NODE_FUNC_ARG; node->type = NODE_FUNC_ARG;
node->text = (String) { p->s.src + arg_start, p->s.cur - arg_start };
node->sval = argname; node->sval = argname;
*arg_tail = node; *arg_tail = node;
@@ -1305,6 +1361,7 @@ Node *parse_func_decl(Parser *p, int opflags)
return NULL; return NULL;
parent->type = NODE_FUNC_DECL; parent->type = NODE_FUNC_DECL;
parent->text = (String) { p->s.src + start, p->s.cur - start };
parent->func_name = name; parent->func_name = name;
parent->func_args = arg_head; parent->func_args = arg_head;
parent->func_body = body; parent->func_body = body;
@@ -1314,15 +1371,17 @@ Node *parse_func_decl(Parser *p, int opflags)
Node *parse_var_decl(Parser *p, int opflags) Node *parse_var_decl(Parser *p, int opflags)
{ {
int start = p->s.cur;
Token t = next_token(p); Token t = next_token(p);
if (t.type != TOKEN_KWORD_LET) { 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; return NULL;
} }
t = next_token(p); t = next_token(p);
if (t.type != TOKEN_IDENT) { if (t.type != TOKEN_IDENT) {
report(p, "Missing variable name after 'let' keyword"); parser_report(p, "Missing variable name after 'let' keyword");
return NULL; return NULL;
} }
String name = t.sval; String name = t.sval;
@@ -1347,6 +1406,7 @@ Node *parse_var_decl(Parser *p, int opflags)
return NULL; return NULL;
parent->type = NODE_VAR_DECL; parent->type = NODE_VAR_DECL;
parent->text = (String) { p->s.src + start, p->s.cur - start };
parent->var_name = name; parent->var_name = name;
parent->var_value = value; parent->var_value = value;
@@ -1555,14 +1615,13 @@ void print_node(Node *node)
} }
printf(">"); printf(">");
Node *child = node->child; Node *child = node->child;
while (child) { while (child) {
print_node(child); print_node(child);
child = child->next; child = child->next;
} }
printf("<%.*s>", printf("</%.*s>",
node->tagname.len, node->tagname.len,
node->tagname.ptr node->tagname.ptr
); );
@@ -1676,7 +1735,7 @@ void print_node(Node *node)
node->var_name.ptr); node->var_name.ptr);
if (node->var_value) { if (node->var_value) {
printf(" = "); printf(" = ");
print_node(node); print_node(node->var_value);
} }
printf(";"); printf(";");
} }
+2
View File
@@ -17,6 +17,7 @@ typedef enum {
NODE_FOR, NODE_FOR,
NODE_WHILE, NODE_WHILE,
NODE_SELECT, NODE_SELECT,
NODE_NESTED,
NODE_OPER_POS, NODE_OPER_POS,
NODE_OPER_NEG, NODE_OPER_NEG,
NODE_OPER_ASS, NODE_OPER_ASS,
@@ -43,6 +44,7 @@ typedef struct Node Node;
struct Node { struct Node {
NodeType type; NodeType type;
Node *next; Node *next;
String text;
Node *key; Node *key;