diff options
| author | WormHeamer | 2025-08-02 06:19:21 -0400 |
|---|---|---|
| committer | WormHeamer | 2025-08-02 06:19:21 -0400 |
| commit | eb9581e4f599470748fdfdceacce61fd8e8f52c7 (patch) | |
| tree | 5b76cee59606422d3b2c973c828b611e35b16e24 | |
| parent | 828396144285492b14a6d8f5c50a4a0d9d0714ef (diff) | |
preliminary let bindings
| -rw-r--r-- | lex.c | 4 | ||||
| -rw-r--r-- | lex.h | 14 | ||||
| -rw-r--r-- | main.c | 188 | ||||
| -rw-r--r-- | test.lang | 9 |
4 files changed, 179 insertions, 36 deletions
@@ -94,7 +94,7 @@ void lex_error_at(Lexer *l, LexSpan pos, LexErr e, Str msg) { lex_err_color(e); if (e != LE_NONE) fprintf(stderr, "%s", e == LE_ERROR ? "error" : "warn"); lex_err_color(LE_NONE); - fprintf(stderr, ": %.*s\n\n", (int)msg.n, msg.s); + fprintf(stderr, ": %.*s\n", (int)msg.n, msg.s); { int ofs = pos.ofs; @@ -111,8 +111,6 @@ void lex_error_at(Lexer *l, LexSpan pos, LexErr e, Str msg) { fputc('\n', stderr); } - fputc('\n', stderr); - if (e == LE_ERROR) { exit(1); } @@ -22,10 +22,10 @@ X(EQUALS, "=")\ X(COLON, ":")\ X(COMMA, ",")\ - X(NOT, "~")\ - X(AND, "&")\ - X(OR, "|")\ - X(XOR, "^")\ + X(NOT, "not")\ + X(AND, "and")\ + X(OR, "or")\ + X(XOR, "xor")\ X(LIT_STR, "string")\ X(LIT_CHAR, "character")\ X(LIT_NUM, "number") @@ -41,11 +41,7 @@ X(TOK_SLASH, '/')\ X(TOK_EQUALS, '=')\ X(TOK_COLON, ':')\ - X(TOK_COMMA, ',')\ - X(TOK_NOT, '~')\ - X(TOK_AND, '&')\ - X(TOK_OR, '|')\ - X(TOK_XOR, '^') + X(TOK_COMMA, ',') typedef enum { @@ -10,24 +10,30 @@ #include "arena.h" #include "dynarr.h" +int no_opt = 0; + /* 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_NEG, N_OP_NOT + 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", "neg", "not", + "value" }; typedef enum { @@ -59,19 +65,27 @@ typedef struct Node { } Node; typedef struct NameBinding { - Str name; struct NameBinding *prev; + Str name; + Node *node; } NameBinding; +typedef struct ScopeFrame { + struct ScopeFrame *prev; + NameBinding *latest; +} ScopeFrame; + typedef struct { - NameBinding *last; + ScopeFrame *tail, *free_scope; + NameBinding *free_bind; } Scope; typedef struct { Arena arena; Str name; - Node *start, *stop; + Node *start, *stop, *keepalive; Node *free_list; + Scope scope; } Proc; typedef struct { @@ -210,6 +224,12 @@ void proc_print(Proc *p) { if (p->start) { printf("\t\"%.*s\" -> %d\n", (int)p->name.n, p->name.s, p->start->id); node_print(p->start); + /*if (no_opt) { + for (NameBinding *b = p->scope.free_bind; b; b = b->prev) { + printf("\t\"%.*s\" [shape=none,fontcolor=blue]\n", (int)b->name.n, b->name.s); + printf("\t\"%.*s\" -> %d [arrowhead=none,style=dotted,color=blue]\n", (int)b->name.n, b->name.s, b->node->id); + } + }*/ } } @@ -276,19 +296,24 @@ Value node_compute(Node *n, Lexer *l) { /* needs lexer for error reporting */ Node *node_peephole(Node *n, Proc *p, Lexer *l) { - Value v = node_compute(n, l); - if (n->type != N_LIT && v.type > T_CONST) { - Node *r = node_new(p, N_LIT, p->start); - r->val = v; - r->src_pos = n->src_pos; - node_kill(n, p); - return r; + if (no_opt) return n; + + if (n->type != N_LIT) { + Value v = node_compute(n, l); + if (v.type > T_CONST) { + Node *r = node_new(p, N_LIT, p->start); + r->val = v; + r->src_pos = n->src_pos; + node_kill(n, p); + 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 @@ -297,6 +322,8 @@ Node *node_peephole(Node *n, Proc *p, Lexer *l) { 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 @@ -305,30 +332,130 @@ Node *node_peephole(Node *n, Proc *p, Lexer *l) { 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, Arena *arena) { + ScopeFrame *f; + if (scope->free_scope) { + f = scope->free_scope; + scope->free_scope = f->prev; + } else { + f = new(arena, ScopeFrame); + } + f->prev = scope->tail; + scope->tail = f; + return f; +} + +ScopeFrame *scope_pop(Scope *scope) { + 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; + b = p; + } + return scope->tail; +} + +/* returns previous value */ +Node *scope_bind(Scope *scope, Str name, Node *value, Arena *arena) { + NameBinding *b = scope_find(scope, name); + Node *og = b ? b->node : NULL; + if (!b) { + if (scope->free_bind) { + b = scope->free_bind; + scope->free_bind = b->prev; + } else { + b = new(arena, NameBinding); + } + b->name = name; + b->prev = scope->tail->latest; + scope->tail->latest = b; + } + b->node = value; + return og; +} + /* parsing */ Node *parse_expr(Lexer *l, Proc *p); -Node *parse_return(Lexer *l, Proc *p) { +void parse_return(Lexer *l, Proc *p) { + lex_next(l); + p->stop = node_new(p, N_RETURN, p->start, parse_expr(l, p)); +} + +void parse_let(Lexer *l, Proc *p) { +recurse: + lex_expect(l, TM_IDENT); + Str name = l->ident; + lex_expect(l, TM_EQUALS); + lex_next(l); + Node *rhs = parse_expr(l, p); + node_add(p, rhs, p->keepalive); + Node *b = scope_bind(&p->scope, name, rhs, &p->arena); + if (b) { + lex_error_at(l, rhs->src_pos, LE_WARN, S("shadowing previous declaration")); + lex_error_at(l, b->src_pos, LE_WARN, S("declared here")); + } + if (l->tok == TOK_COMMA) goto recurse; +} + +void parse_stmt(Lexer *l, Proc *p); + +/* TODO: return node from this! */ +void parse_block(Lexer *l, Proc *p) { + lex_next(l); + scope_push(&p->scope, &p->arena); + while (l->tok != TOK_RBRACE && l->tok != TOK_EOF) { + parse_stmt(l, p); + } + scope_pop(&p->scope); + lex_expected(l, TM_RBRACE); lex_next(l); - return node_new(p, N_RETURN, p->start, parse_expr(l, p)); } -Node *parse_stmt(Lexer *l, Proc *p) { +void parse_stmt(Lexer *l, Proc *p) { /* TODO */ (void)l; switch (l->tok) { case TOK_RETURN: - return parse_return(l, p); + parse_return(l, p); + break; + case TOK_LET: + parse_let(l, p); + break; + case TOK_LBRACE: + parse_block(l, p); break; default: lex_expected(l, TM_RBRACE); - return NULL; + break; } } @@ -337,14 +464,18 @@ Proc *parse_proc(Lexer *l, Unit *u) { 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; lex_expect(l, TM_LBRACE); lex_next(l); + scope_push(&proc->scope, &proc->arena); while (l->tok != TOK_RBRACE) { lex_expected_not(l, TM_EOF); - proc->stop = parse_stmt(l, proc); + parse_stmt(l, proc); } + scope_pop(&proc->scope); + node_kill(proc->keepalive, proc); lex_expected(l, TM_RBRACE); lex_next(l); return proc; @@ -352,8 +483,13 @@ Proc *parse_proc(Lexer *l, Unit *u) { Node *parse_term(Lexer *l, Proc *p) { Node *node = NULL; - int negate_after = l->tok == TOK_MINUS; - if (TMASK(l->tok) & (TM_MINUS | TM_PLUS)) { + NodeType op_after = N_START; + if (TMASK(l->tok) & (TM_MINUS | TM_PLUS | TM_NOT)) { + switch (l->tok) { + case TOK_MINUS: op_after = N_OP_NEG; break; + case TOK_NOT: op_after = N_OP_NOT; break; + default: break; + } lex_next(l); } if (l->tok == TOK_LPAREN) { @@ -361,12 +497,20 @@ Node *parse_term(Lexer *l, Proc *p) { node = parse_expr(l, p); lex_expected(l, TM_RPAREN); lex_next(l); + } else if (l->tok == TOK_IDENT) { + NameBinding *b = scope_find(&p->scope, l->ident); + if (b) { + node = b->node; + } else { + lex_error(l, LE_ERROR, S("undeclared identifier")); + } + lex_next(l); } else { lex_expected(l, TM_LIT_NUM); int64_t val = 0; for (int i = 0; i < l->ident.n; i++) { if (!(l->ident.s[i] >= '0' && l->ident.s[i] <= '9')) { - lex_error(l, LE_ERROR, S("Not a digit")); + lex_error(l, LE_ERROR, S("not a digit")); break; } val = (val * 10) + (l->ident.s[i] - '0'); @@ -375,8 +519,8 @@ Node *parse_term(Lexer *l, Proc *p) { node->src_pos = l->pos; lex_next(l); } - if (negate_after) { - node = node_new(p, N_OP_NEG, node); + if (op_after != N_START) { + node = node_new(p, op_after, node_peephole(node, p, l)); } return node_peephole(node, p, l); } @@ -6,7 +6,12 @@ * let x = g */ - proc main { - return (3 * 5612 * -2) / (1 * (32 ^ 32) + 1 + (512 ^ 512) & (3131 + (1023 - 3131))) + let a = 31, b = a * 232, z = a * b + let gaye = a + b * a + let d = b + gaye + let sum = a + b + z + d + let nsum = -sum + let gay = d xor sum + return nsum + gay } |
