diff options
| author | WormHeamer | 2025-08-03 18:48:20 -0400 |
|---|---|---|
| committer | WormHeamer | 2025-08-03 18:48:20 -0400 |
| commit | 62e4b45143e4ff24a1758a2ccd3af5dfe69706ec (patch) | |
| tree | 2949a720e278da21254fdf72e3faab8bd55688b9 | |
| parent | c4594891b79e305c661e74d495f78b1d143b4d8a (diff) | |
factor out node stuff into ir.c & ir.h
| -rw-r--r-- | ir.c | 308 | ||||
| -rw-r--r-- | ir.h | 105 | ||||
| -rw-r--r-- | main.c | 376 | ||||
| -rw-r--r-- | test.lang | 8 |
4 files changed, 426 insertions, 371 deletions
@@ -0,0 +1,308 @@ +#include <stdarg.h> +#include "ir.h" + +extern int no_opt; + +const char *node_type_name(NodeType t) { + const char *names[] = { + "start", + "return", + "keepalive", + "literal", + "add", "sub", "mul", "div", + "and", "or", "xor", + "lshift", "rshift", + "neg", "not", + "value" + }; + return names[t]; +} + +void node_die(Node *n, Proc *p) { + n->prev_free = p->free_list; + p->free_list = n; +} + +void node_del_out(Node *n, Node *p) { + for (int i = 0; i < n->out.len; i++) { + if (n->out.data[i] == p) { + p->refs--; + if (i + 1 < n->out.len) { + memmove(&n->out.data[i], &n->out.data[i + 1], sizeof(Node*) * (n->out.len - i - 1)); + } + n->out.len--; + i--; + } + } +} + +void node_del_in(Node *n, Node *p) { + for (int i = 0; i < n->in.len; i++) { + if (n->in.data[i] == p) { + p->refs--; + if (i + 1 < n->in.len) { + memmove(&n->in.data[i], &n->in.data[i + 1], sizeof(Node*) * (n->in.len - i - 1)); + } + n->in.len--; + i--; + } + } +} + +void node_kill(Node *n, Proc *p) { + for (int i = 0; i < n->in.len; i++) { + node_del_out(n->in.data[i], n); + n->in.data[i]->refs--; + if (n->in.data[i]->out.len < 1) node_kill(n->in.data[i], p); + } + for (int i = 0; i < n->out.len; i++) { + node_del_in(n->out.data[i], n); + n->out.data[i]->refs--; + if (n->out.data[i]->refs < 1) node_die(n->out.data[i], p); + } + n->in.len = 0; + n->out.len = 0; + node_die(n, p); +} + +void node_add(Proc *p, Node *src, Node *dest) { + ZDA_PUSH(&src->out, dest, &p->arena); + ZDA_PUSH(&dest->in, src, &p->arena); + src->refs++; + dest->refs++; + if (dest->src_pos.n == 0) dest->src_pos = src->src_pos; +} + +void node_remove(Proc *p, Node *src, Node *dest) { + node_del_out(src, dest); + node_del_in(dest, src); + if (dest->refs < 1) node_die(dest, p); + if (src->refs < 1) node_die(src, p); + else if (src->out.len < 1) node_kill(src, p); +} + +static int global_node_count = 0; + +Node *node_new_empty(Proc *p, NodeType t) { + Node *n; + if (p->free_list) { + n = p->free_list; + p->free_list = n->prev_free; + memset(n, 0, sizeof(Node)); + } else { + n = new(&p->arena, Node); + } + n->type = t; + n->id = global_node_count++; + return n; +} + +Node *node_newv(Proc *p, NodeType t, ...) { + Node *node = node_new_empty(p, t); + va_list ap; + va_start(ap, t); + for (;;) { + Node *n = va_arg(ap, Node *); + if (!n) break; + node_add(p, n, node); + } + va_end(ap); + return node; +} + +Node *node_dedup_lit(Proc *p, Value v) { + /* TODO: this is probably real inefficient for large procedure graphs, + * but does it matter? how many nodes are direct children of the start node? + * how many literals even usually occur in a procedure? */ + for (int i = 0; i < p->start->out.len; i++) { + Node *t = p->start->out.data[i]; + if (t->type == N_LIT && t->val.type == v.type && t->val.i == v.i) { + return t; + } + } + return NULL; +} + +Node *node_new_lit_i64(Proc *p, int64_t i) { + Value v = (Value) { T_INT, { .i = i } }; + Node *t = node_dedup_lit(p, v); + if (t) return t; + Node *n = node_new(p, N_LIT, p->start); + n->val = v; + return n; +} + +static inline int node_op_communative(NodeType t) { + NodeType ops[] = { N_OP_ADD, N_OP_MUL, N_OP_AND, N_OP_XOR, N_OP_OR }; + for (unsigned i = 0; i < sizeof ops / sizeof *ops; i++) { + if (ops[i] == t) return 1; + } + return 0; +} + +Value node_compute(Node *n, Lexer *l) { + Type lit_type = T_BOT; + Node **in = n->in.data; + for (int i = 0; i < n->in.len; i++) { + Node *p = in[i]; + if (p->type != N_LIT) break; + if (p->val.type != lit_type) { + if (lit_type == T_BOT) { + lit_type = p->val.type; + } else { + lit_type = T_BOT; + break; + } + } + } + if (lit_type == T_INT) { + Value v = { .type = lit_type }; + switch (n->type) { + case N_OP_NEG: v.i = -in[0]->val.i; break; + case N_OP_NOT: v.i = ~in[0]->val.i; break; + case N_OP_ADD: v.i = in[0]->val.i + in[1]->val.i; break; + case N_OP_SUB: v.i = in[0]->val.i - in[1]->val.i; break; + case N_OP_MUL: v.i = in[0]->val.i * in[1]->val.i; break; + case N_OP_DIV: + if (in[1]->val.i == 0) { + lex_error_at(l, in[1]->src_pos, LE_ERROR, S("divisor always evaluates to zero")); + } + v.i = in[0]->val.i / in[1]->val.i; + break; + case N_OP_AND: v.i = in[0]->val.i & in[1]->val.i; break; + case N_OP_OR: v.i = in[0]->val.i | in[1]->val.i; break; + case N_OP_XOR: v.i = in[0]->val.i ^ in[1]->val.i; break; + case N_OP_SHL: v.i = in[0]->val.u << in[1]->val.u; break; + case N_OP_SHR: v.i = in[0]->val.u >> in[1]->val.u; break; + default: return n->val; + } + return v; + } + return n->val; +} + +/* needs lexer for error reporting */ +Node *node_peephole(Node *n, Proc *p, Lexer *l) { + if (no_opt) return n; + + if (n->type != N_LIT) { + Value v = node_compute(n, l); + if (v.type > T_CONST) { + node_kill(n, p); + Node *t = node_dedup_lit(p, v); + if (t) return t; + Node *r = node_new(p, N_LIT, p->start); + r->val = v; + r->src_pos = n->src_pos; + return r; + } + } + + Node **in = n->in.data; + /* TODO: figure out to do peepholes recursively, without fucking up the graph or having to clone everything */ + if (node_op_communative(n->type)) { + /* transformations to help encourage constant folding */ + /* the overall trend is to move them rightwards */ + if (in[0]->type == N_LIT + && in[1]->type == n->type + && in[1]->in.data[0]->type != N_LIT + && in[1]->in.data[1]->type == N_LIT) { + /* op(lit, op(X, lit)) -> op(X, op(lit, lit)) */ + Node *tmp = in[1]->in.data[0]; + in[1]->in.data[0] = in[0]; + in[0] = tmp; + /* TODO: ...would it break anything at all to just do in[1] = node_peephole(in[1], p, l)? + * probably not, right? */ + } else if (in[0]->type == n->type + && in[0]->in.data[0]->type != N_LIT + && in[0]->in.data[1]->type == N_LIT + && in[1]->type != N_LIT) { + /* op(op(X, lit), Y) -> op(op(X, Y), lit) */ + Node *tmp = in[0]->in.data[1]; + in[0]->in.data[1] = in[1]; + in[1] = tmp; + } else if (in[0]->type == N_LIT && in[1]->type != N_LIT) { + /* op(lit, X) -> op(X, lit) */ + Node *tmp = in[0]; + in[0] = in[1]; + in[1] = tmp; + } + } + + return n; +} + +/* procedures */ + +void proc_init(Proc *proc, Str name) { + memset(proc, 0, sizeof(Proc)); + proc->start = node_new_empty(proc, N_START); + proc->keepalive = node_new_empty(proc, N_KEEPALIVE); + proc->name = name; +} + +void proc_free(Proc *proc) { + arena_free(&proc->arena); +} + +/* scope */ + +NameBinding *scope_find(Scope *scope, Str name) { + for (ScopeFrame *f = scope->tail; f; f = f->prev) { + for (NameBinding *b = f->latest; b; b = b->prev) { + if (str_eql(b->name, name)) { + return b; + } + } + } + return NULL; +} + +ScopeFrame *scope_push(Scope *scope, Proc *proc) { + ScopeFrame *f; + if (scope->free_scope) { + f = scope->free_scope; + *f = (ScopeFrame) { 0 }; + scope->free_scope = f->prev; + } else { + f = new(&proc->arena, ScopeFrame); + } + f->prev = scope->tail; + scope->tail = f; + return f; +} + +ScopeFrame *scope_pop(Scope *scope, Proc *proc) { + ScopeFrame *f = scope->tail; + scope->tail = f->prev; + f->prev = scope->free_scope; + scope->free_scope = f; + for (NameBinding *b = f->latest; b; ) { + NameBinding *p = b->prev; + b->prev = scope->free_bind; + scope->free_bind = b; + node_remove(proc, b->node, proc->keepalive); + b = p; + } + return scope->tail; +} + +/* returns previous value */ +NameBinding *scope_bind(Scope *scope, Str name, Node *value, LexSpan pos, Proc *proc) { + NameBinding *prev = scope_find(scope, name); + NameBinding *b; + if (scope->free_bind) { + b = scope->free_bind; + *b = (NameBinding) { 0 }; + scope->free_bind = b->prev; + } else { + b = new(&proc->arena, NameBinding); + } + b->name = name; + b->prev = scope->tail->latest; + scope->tail->latest = b; + b->node = value; + b->src_pos = pos; + node_add(proc, value, proc->keepalive); + return prev; +} @@ -0,0 +1,105 @@ +#ifndef IR_H +#define IR_H + +#include "arena.h" +#include "dynarr.h" +#include "lex.h" /* for error reporting only */ +#include "str.h" + +/* nodes */ + +typedef enum { + N_START, + N_RETURN, + N_KEEPALIVE, + N_LIT, + N_OP_ADD, N_OP_SUB, N_OP_MUL, N_OP_DIV, + N_OP_AND, N_OP_OR, N_OP_XOR, + N_OP_SHL, N_OP_SHR, + N_OP_NEG, N_OP_NOT, + N_VALUE +} NodeType; + +const char *node_type_name(NodeType t); + +typedef enum { + T_BOT, + T_TOP, + T_CONST, + T_INT +} Type; + +typedef struct { + Type type; + union { + int64_t i; + uint64_t u; + }; +} Value; + +typedef struct Node { + union { + struct Node *prev_free; + struct { + int id, refs; + int walked; + NodeType type; + LexSpan src_pos; + DYNARR(struct Node *) in, out; + Value val; + }; + }; +} Node; + +/* procedure graph */ + +typedef struct NameBinding { + struct NameBinding *prev; + LexSpan src_pos; + Str name; + Node *node; +} NameBinding; + +typedef struct ScopeFrame { + struct ScopeFrame *prev; + NameBinding *latest; +} ScopeFrame; + +typedef struct { + ScopeFrame *tail, *free_scope; + NameBinding *free_bind; +} Scope; + +typedef struct { + Arena arena; + Str name; + Node *start, *stop, *keepalive; + Node *free_list; + Scope scope; +} Proc; + +void node_kill(Node *n, Proc *p); +void node_die(Node *n, Proc *p); +void node_del_out(Node *n, Node *p); +void node_del_in(Node *n, Node *p); +void node_kill(Node *n, Proc *p); +void node_add(Proc *p, Node *src, Node *dest); +void node_remove(Proc *p, Node *src, Node *dest); +Node *node_new_empty(Proc *p, NodeType t); +Node *node_newv(Proc *p, NodeType t, ...); +Node *node_dedup_lit(Proc *p, Value v); +Node *node_new_lit_i64(Proc *p, int64_t i); +Value node_compute(Node *n, Lexer *l); +Node *node_peephole(Node *n, Proc *p, Lexer *l); + +#define node_new(...) node_newv(__VA_ARGS__, NULL) + +void proc_init(Proc *proc, Str name); +void proc_free(Proc *proc); + +ScopeFrame *scope_push(Scope *scope, Proc *proc); +ScopeFrame *scope_pop(Scope *scope, Proc *proc); +NameBinding *scope_find(Scope *scope, Str name); +NameBinding *scope_bind(Scope *scope, Str name, Node *value, LexSpan pos, Proc *proc); + +#endif @@ -9,89 +9,10 @@ #include "lex.h" #include "arena.h" #include "dynarr.h" +#include "ir.h" int no_opt = 1; -/* node graph */ - -typedef enum { - N_START, - N_RETURN, - N_KEEPALIVE, - N_LIT, - N_OP_ADD, N_OP_SUB, N_OP_MUL, N_OP_DIV, - N_OP_AND, N_OP_OR, N_OP_XOR, - N_OP_SHL, N_OP_SHR, - N_OP_NEG, N_OP_NOT, - N_VALUE -} NodeType; - -const char *node_type_name[] = { - "start", - "return", - "keepalive", - "literal", - "add", "sub", "mul", "div", - "and", "or", "xor", - "lshift", "rshift", - "neg", "not", - "value" -}; - -typedef enum { - T_BOT, - T_TOP, - T_CONST, - T_INT -} Type; - -typedef struct { - Type type; - union { - int64_t i; - uint64_t u; - }; -} Value; - -typedef struct Node { - union { - struct Node *prev_free; - struct { - int id, refs; - int walked; - NodeType type; - LexSpan src_pos; - DYNARR(struct Node *) in, out; - Value val; - }; - }; -} Node; - -typedef struct NameBinding { - struct NameBinding *prev; - LexSpan src_pos; - Str name; - Node *node; -} NameBinding; - -typedef struct ScopeFrame { - struct ScopeFrame *prev; - NameBinding *latest; -} ScopeFrame; - -typedef struct { - ScopeFrame *tail, *free_scope; - NameBinding *free_bind; -} Scope; - -typedef struct { - Arena arena; - Str name; - Node *start, *stop, *keepalive; - Node *free_list; - Scope scope; -} Proc; - typedef struct { DYNARR(Proc) procs; } Unit; @@ -100,111 +21,18 @@ void unit_init(Unit *u) { (void)u; } -void unit_fini(Unit *u) { - free(u->procs.data); -} - -void node_kill(Node *n, Proc *p); - -void node_die(Node *n, Proc *p) { - /*n->prev_free = p->free_list; - p->free_list = n;*/ -} - -void node_del_out(Node *n, Node *p) { - for (int i = 0; i < n->out.len; i++) { - if (n->out.data[i] == p) { - p->refs--; - if (i + 1 < n->out.len) { - memmove(&n->out.data[i], &n->out.data[i + 1], sizeof(Node*) * (n->out.len - i - 1)); - } - n->out.len--; - i--; - } - } -} - -void node_del_in(Node *n, Node *p) { - for (int i = 0; i < n->in.len; i++) { - if (n->in.data[i] == p) { - p->refs--; - if (i + 1 < n->in.len) { - memmove(&n->in.data[i], &n->in.data[i + 1], sizeof(Node*) * (n->in.len - i - 1)); - } - n->in.len--; - i--; - } - } -} - -void node_kill(Node *n, Proc *p) { - for (int i = 0; i < n->in.len; i++) { - node_del_out(n->in.data[i], n); - n->in.data[i]->refs--; - if (n->in.data[i]->out.len < 1) node_kill(n->in.data[i], p); - } - for (int i = 0; i < n->out.len; i++) { - node_del_in(n->out.data[i], n); - n->out.data[i]->refs--; - if (n->out.data[i]->refs < 1) node_die(n->out.data[i], p); - } - n->in.len = 0; - n->out.len = 0; - node_die(n, p); -} - -void node_add(Proc *p, Node *src, Node *dest) { - ZDA_PUSH(&src->out, dest, &p->arena); - ZDA_PUSH(&dest->in, src, &p->arena); - src->refs++; - dest->refs++; - if (dest->src_pos.n == 0) dest->src_pos = src->src_pos; -} - -void node_remove(Proc *p, Node *src, Node *dest) { - node_del_out(src, dest); - node_del_in(dest, src); - if (dest->refs < 1) node_die(dest, p); - if (src->refs < 1) node_die(src, p); - else if (src->out.len < 1) node_kill(src, p); -} - -static int global_node_count = 0; - -Node *node_new_empty(Proc *p, NodeType t) { - Node *n; - if (p->free_list) { - n = p->free_list; - p->free_list = n->prev_free; - memset(n, 0, sizeof(Node)); - } else { - n = new(&p->arena, Node); - } - n->type = t; - n->id = global_node_count++; - return n; -} - -Node *node_new(Proc *p, NodeType t, ...) { - Node *node = node_new_empty(p, t); - va_list ap; - va_start(ap, t); - for (;;) { - Node *n = va_arg(ap, Node *); - if (!n) break; - node_add(p, n, node); +void unit_free(Unit *u) { + for (int i = 0; i < u->procs.len; i++) { + proc_free(&u->procs.data[i]); } - va_end(ap); - return node; + free(u->procs.data); } -#define node_new(...) node_new(__VA_ARGS__, NULL) - void node_print(Node *n) { if (n->type == N_LIT) { printf("\t%d [label=\"%ld\"]\n", n->id, n->val.i); } else { - printf("\t%d [label=\"%s\", shape=record]\n", n->id, node_type_name[n->type]); + printf("\t%d [label=\"%s\", shape=record]\n", n->id, node_type_name(n->type)); } if (n->walked) { return; @@ -244,191 +72,6 @@ void unit_print(Unit *u) { puts("}"); } -Node *node_dedup_lit(Proc *p, Value v) { - /* TODO: this is probably real inefficient for large procedure graphs, - * but does it matter? how many nodes are direct children of the start node? - * how many literals even usually occur in a procedure? */ - for (int i = 0; i < p->start->out.len; i++) { - Node *t = p->start->out.data[i]; - if (t->type == N_LIT && t->val.type == v.type && t->val.i == v.i) { - fprintf(stderr, "deduplicated a node\n"); - return t; - } - } - return NULL; -} - -Node *node_new_lit_i64(Proc *p, int64_t i) { - Value v = (Value) { T_INT, { .i = i } }; - Node *t = node_dedup_lit(p, v); - if (t) return t; - Node *n = node_new(p, N_LIT, p->start); - n->val = v; - return n; -} - -static inline int node_op_communative(NodeType t) { - NodeType ops[] = { N_OP_ADD, N_OP_MUL, N_OP_AND, N_OP_XOR, N_OP_OR }; - for (unsigned i = 0; i < sizeof ops / sizeof *ops; i++) { - if (ops[i] == t) return 1; - } - return 0; -} - -Value node_compute(Node *n, Lexer *l) { - Type lit_type = T_BOT; - Node **in = n->in.data; - for (int i = 0; i < n->in.len; i++) { - Node *p = in[i]; - if (p->type != N_LIT) break; - if (p->val.type != lit_type) { - if (lit_type == T_BOT) { - lit_type = p->val.type; - } else { - lit_type = T_BOT; - break; - } - } - } - if (lit_type == T_INT) { - Value v = { .type = lit_type }; - switch (n->type) { - case N_OP_NEG: v.i = -in[0]->val.i; break; - case N_OP_NOT: v.i = ~in[0]->val.i; break; - case N_OP_ADD: v.i = in[0]->val.i + in[1]->val.i; break; - case N_OP_SUB: v.i = in[0]->val.i - in[1]->val.i; break; - case N_OP_MUL: v.i = in[0]->val.i * in[1]->val.i; break; - case N_OP_DIV: - if (in[1]->val.i == 0) { - lex_error_at(l, in[1]->src_pos, LE_ERROR, S("divisor always evaluates to zero")); - } - v.i = in[0]->val.i / in[1]->val.i; - break; - case N_OP_AND: v.i = in[0]->val.i & in[1]->val.i; break; - case N_OP_OR: v.i = in[0]->val.i | in[1]->val.i; break; - case N_OP_XOR: v.i = in[0]->val.i ^ in[1]->val.i; break; - case N_OP_SHL: v.i = in[0]->val.u << in[1]->val.u; break; - case N_OP_SHR: v.i = in[0]->val.u >> in[1]->val.u; break; - default: return n->val; - } - return v; - } - return n->val; -} - -/* needs lexer for error reporting */ -Node *node_peephole(Node *n, Proc *p, Lexer *l) { - if (no_opt) return n; - - if (n->type != N_LIT) { - Value v = node_compute(n, l); - if (v.type > T_CONST) { - node_kill(n, p); - Node *t = node_dedup_lit(p, v); - if (t) return t; - Node *r = node_new(p, N_LIT, p->start); - r->val = v; - r->src_pos = n->src_pos; - return r; - } - } - - Node **in = n->in.data; - /* TODO: figure out to do peepholes recursively, without fucking up the graph or having to clone everything */ - if (node_op_communative(n->type)) { - /* transformations to help encourage constant folding */ - /* the overall trend is to move them rightwards */ - if (in[0]->type == N_LIT - && in[1]->type == n->type - && in[1]->in.data[0]->type != N_LIT - && in[1]->in.data[1]->type == N_LIT) { - /* op(lit, op(X, lit)) -> op(X, op(lit, lit)) */ - Node *tmp = in[1]->in.data[0]; - in[1]->in.data[0] = in[0]; - in[0] = tmp; - /* TODO: ...would it break anything at all to just do in[1] = node_peephole(in[1], p, l)? - * probably not, right? */ - } else if (in[0]->type == n->type - && in[0]->in.data[0]->type != N_LIT - && in[0]->in.data[1]->type == N_LIT - && in[1]->type != N_LIT) { - /* op(op(X, lit), Y) -> op(op(X, Y), lit) */ - Node *tmp = in[0]->in.data[1]; - in[0]->in.data[1] = in[1]; - in[1] = tmp; - } else if (in[0]->type == N_LIT && in[1]->type != N_LIT) { - /* op(lit, X) -> op(X, lit) */ - Node *tmp = in[0]; - in[0] = in[1]; - in[1] = tmp; - } - } - - return n; -} - -/* scope */ - -NameBinding *scope_find(Scope *scope, Str name) { - for (ScopeFrame *f = scope->tail; f; f = f->prev) { - for (NameBinding *b = f->latest; b; b = b->prev) { - if (str_eql(b->name, name)) { - return b; - } - } - } - return NULL; -} - -ScopeFrame *scope_push(Scope *scope, Proc *proc) { - ScopeFrame *f; - if (scope->free_scope) { - f = scope->free_scope; - *f = (ScopeFrame) { 0 }; - scope->free_scope = f->prev; - } else { - f = new(&proc->arena, ScopeFrame); - } - f->prev = scope->tail; - scope->tail = f; - return f; -} - -ScopeFrame *scope_pop(Scope *scope, Proc *proc) { - ScopeFrame *f = scope->tail; - scope->tail = f->prev; - f->prev = scope->free_scope; - scope->free_scope = f; - for (NameBinding *b = f->latest; b; ) { - NameBinding *p = b->prev; - b->prev = scope->free_bind; - scope->free_bind = b; - node_remove(proc, b->node, proc->keepalive); - b = p; - } - return scope->tail; -} - -/* returns previous value */ -NameBinding *scope_bind(Scope *scope, Str name, Node *value, LexSpan pos, Proc *proc) { - NameBinding *prev = scope_find(scope, name); - NameBinding *b; - if (scope->free_bind) { - b = scope->free_bind; - *b = (NameBinding) { 0 }; - scope->free_bind = b->prev; - } else { - b = new(&proc->arena, NameBinding); - } - b->name = name; - b->prev = scope->tail->latest; - scope->tail->latest = b; - b->node = value; - b->src_pos = pos; - node_add(proc, value, proc->keepalive); - return prev; -} - /* parsing */ Node *parse_expr(Lexer *l, Proc *p); @@ -491,11 +134,8 @@ void parse_stmt(Lexer *l, Proc *p) { Proc *parse_proc(Lexer *l, Unit *u) { DA_FIT(&u->procs, u->procs.len + 1); Proc *proc = &u->procs.data[u->procs.len++]; - memset(proc, 0, sizeof(Proc)); - proc->start = node_new_empty(proc, N_START); - proc->keepalive = node_new_empty(proc, N_KEEPALIVE); lex_expect(l, TM_IDENT); - proc->name = l->ident; + proc_init(proc, l->ident); lex_expect(l, TM_LBRACE); lex_next(l); scope_push(&proc->scope, proc); @@ -600,7 +240,7 @@ void parse_unit(Lexer *l) { parse_toplevel(l, &u); } unit_print(&u); - unit_fini(&u); + unit_free(&u); } int main(int argc, const char **argv) { @@ -6,10 +6,12 @@ * let x = g */ +// also single-line now + proc main { let a = 2, b = 3 let c = a + b, d = a * b * c, e = d + d - let a = d - let r = e + (c * e * b * a) - return (r / (r - 27060)) + let f = e + (c * e * b * a) + let r = (((f << 16) | (f >> 16)) xor (f * 1875387131)) + return (r xor (r * 1875387131)) & 31 } |
