Author | Jakob Wakeling <[email protected]> |
Date | 2023-07-10 12:17:59 |
Commit | 8021c03df5a011b7a8978a9c49c21f6e97146f8f |
Parent | 2be2f4390b177036c5fa3b2ff11bf17e53003e97 |
Implement procedure argument mutability
Diffstat
M | README.md | | | 7 | +++---- |
M | src/analyse.c | | | 2 | ++ |
M | src/lex.c | | | 80 | ++++++++++++++++++++++++++++++++++++++++---------------------------------------- |
M | src/lex.h | | | 6 | +++--- |
M | src/llvm.c | | | 59 | ++++++++++++++++++++++------------------------------------- |
M | src/log.c | | | 10 | +++++++++- |
M | src/log.h | | | 10 | ++++++++++ |
M | src/parse.c | | | 43 | +++++++++++++++++++------------------------ |
8 files changed, 108 insertions, 109 deletions
diff --git a/README.md b/README.md index afcc067..6054900 100644 --- a/README.md +++ b/README.md @@ -45,10 +45,8 @@ command. The second command will output an executable file, *a.out* by default. > Not all todo items will necesarilly be implemented and sometimes I am pretty > liberal with what justifies crossing something off -- [x] Implement procedure declarations -- [x] Implement procedure calls -- [x] Implement procedure arguments - [x] Implement variables +- [x] Implement procedures - [x] Implement booleans - [x] Implement integers - [x] Implement reals @@ -58,6 +56,7 @@ command. The second command will output an executable file, *a.out* by default. - [x] Implement expressions - [x] Implement type casting - [ ] Implement type casting to pointers and arrays +- [ ] Improve type inference and implicit casting - [ ] Implement the `type` type - [ ] Implement the `error` type - [ ] Implement labels and `goto` @@ -66,6 +65,7 @@ command. The second command will output an executable file, *a.out* by default. - [ ] Implement `break` and `continue` - [ ] Implement `defer` - [ ] Implement `errdefer` (?) +- [ ] Implement variadic procedure arguments - [ ] Implement first class strings - [x] Implement syscalls - [ ] Implement generics of some kind diff --git a/src/analyse.c b/src/analyse.c index 8a83441..fb1830e 100644 --- a/src/analyse.c +++ b/src/analyse.c @@ -165,6 +165,8 @@ static void analyse_expr(ast *a, syt *st) { A.k = AK_CAST; A.t = sym->t; if (CL > 2) { note("TODO", A.ln, A.cl, 0, "Type casts must only have a single argument"); } } + + for (UINT i = 1; i < CL; i += 1) { analyse_expr(C[i], st); } } break; case AK_SUBS: { assert(CL == 2); diff --git a/src/lex.c b/src/lex.c index e3c0946..722ea95 100644 --- a/src/lex.c +++ b/src/lex.c @@ -22,14 +22,14 @@ char *tok_ks[] = { "TK_LPAREN", "TK_RPAREN", "TK_LBRACK", "TK_RBRACK", "TK_LBRACE", "TK_RBRACE", "TK_COLON", "TK_SCOLON", "TK_COMMA", "TK_PERIOD", "TK_RARROW", "TK_QMARK", "TK_HASH", - "TK_OP_ADD", "TK_OP_SUB", "TK_OP_MUL", "TK_OP_DIV", "TK_OP_MOD", + "TK_ADD", "TK_SUB", "TK_MUL", "TK_DIV", "TK_MOD", "TK_EQ", "TK_NE", "TK_LT", "TK_LE", "TK_GT", "TK_GE", "TK_EMARK", "TK_LO_AND", "TK_LO_OR", - "TK_BW_NOT", "TK_BW_AND", "TK_BW_OR", "TK_BW_XOR", "TK_BW_SHL", "TK_BW_SHR", + "TK_TILDE", "TK_BW_AND", "TK_BW_OR", "TK_BW_XOR", "TK_LSHIFT", "TK_RSHIFT", "TK_ASSIGN", "TK_AS_ADD", "TK_AS_SUB", "TK_AS_MUL", "TK_AS_DIV", "TK_AS_MOD", - "TK_AS_NOT", "TK_AS_AND", "TK_AS_OR", "TK_AS_XOR", "TK_AS_SHL", "TK_AS_SHR", + "TK_AS_NOT", "TK_AS_AND", "TK_AS_OR", "TK_AS_XOR", "TK_AS_LSHIFT", "TK_AS_RSHIFT", }; #define is_space(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') @@ -52,7 +52,6 @@ lex lex_init(const char *file, char *src, UINT len) { #define P (l->p) /* Pointer to the Current Character */ #define Q (l->q) /* Pointer to EOF */ #define C (l->p[0]) /* Current Character */ -#define D (l->p[1]) /* Next Character */ #define LN (l->ln) /* Line Index */ #define CL (l->cl) /* Column Index */ #define T (l->t) /* Current Token */ @@ -76,12 +75,12 @@ tok lex_next(lex *l) { if (P == Q) { T = (tok){ TK_EOF, LN, CL, 0 }; return t; } /* Skip single-line and (potentially nested) multi-line comments */ - if (C == '/') switch (D) { + if (C == '/') switch (P[1]) { case '/': { for (P += 2; P != Q && C != '\n'; P += 1); } goto skip; case '*': { UINT d = 1; for (P += 2, CL += 2; P != Q && d; P += 1) { - if (C == '/' && D == '*') { P += 2; CL += 2; d += 1; continue; } - if (C == '*' && D == '/') { P += d == 1 ? 1 : 2; CL += 2; d -= 1; continue; } + if (C == '/' && P[1] == '*') { P += 2; CL += 2; d += 1; continue; } + if (C == '*' && P[1] == '/') { P += d == 1 ? 1 : 2; CL += 2; d -= 1; continue; } if (C == '\n') { LN += 1; CL = 0; } else { CL += 1; } } } goto skip; @@ -143,58 +142,66 @@ tok lex_next(lex *l) { case '.': { T.k = TK_PERIOD; P += 1; CL += 1; } break; case '?': { T.k = TK_QMARK; P += 1; CL += 1; } break; case '#': { T.k = TK_HASH; P += 1; CL += 1; } break; - case '+': switch (D) { - default: { T.k = TK_OP_ADD; P += 1; CL += 1; } break; + case '+': switch (P[1]) { + default: { T.k = TK_ADD; P += 1; CL += 1; } break; case '=': { T.k = TK_AS_ADD; P += 2; CL += 2; } break; } break; - case '-': switch (D) { - default: { T.k = TK_OP_SUB; P += 1; CL += 1; } break; + case '-': switch (P[1]) { + default: { T.k = TK_SUB; P += 1; CL += 1; } break; case '>': { T.k = TK_RARROW; P += 2; CL += 2; } break; case '=': { T.k = TK_AS_SUB; P += 2; CL += 2; } break; } break; - case '*': switch (D) { - default: { T.k = TK_OP_MUL; P += 1; CL += 1; } break; + case '*': switch (P[1]) { + default: { T.k = TK_MUL; P += 1; CL += 1; } break; case '=': { T.k = TK_AS_MUL; P += 2; CL += 2; } break; } break; - case '/': switch (D) { - default: { T.k = TK_OP_DIV; P += 1; CL += 1; } break; + case '/': switch (P[1]) { + default: { T.k = TK_DIV; P += 1; CL += 1; } break; case '=': { T.k = TK_AS_DIV; P += 2; CL += 2; } break; } break; - case '%': switch (D) { - default: { T.k = TK_OP_MOD; P += 1; CL += 1; } break; + case '%': switch (P[1]) { + default: { T.k = TK_MOD; P += 1; CL += 1; } break; case '=': { T.k = TK_AS_MOD; P += 2; CL += 2; } break; } break; - case '=': switch (D) { + case '=': switch (P[1]) { default: { T.k = TK_ASSIGN; P += 1; CL += 1; } break; case '=': { T.k = TK_EQ; P += 2; CL += 2; } break; } break; - case '<': switch (D) { + case '<': switch (P[1]) { default: { T.k = TK_LT; P += 1; CL += 1; } break; case '=': { T.k = TK_LE; P += 2; CL += 2; } break; + case '<': switch (P[2]) { + default: { T.k = TK_LSHIFT; P += 2; CL += 2; } break; + case '=': { T.k = TK_AS_LSHIFT; P += 3; CL += 3; } break; + } break; } break; - case '>': switch (D) { + case '>': switch (P[1]) { default: { T.k = TK_GT; P += 1; CL += 1; } break; case '=': { T.k = TK_GE; P += 2; CL += 2; } break; + case '>': switch (P[2]) { + default: { T.k = TK_RSHIFT; P += 2; CL += 2; } break; + case '=': { T.k = TK_AS_RSHIFT; P += 3; CL += 3; } break; + } break; } break; - case '!': switch (D) { + case '!': switch (P[1]) { default: { T.k = TK_EMARK; P += 1; CL += 1; } break; case '=': { T.k = TK_NE; P += 2; CL += 2; } break; } break; - case '&': switch (D) { + case '&': switch (P[1]) { default: { T.k = TK_BW_AND; P += 1; CL += 1; } break; case '&': { T.k = TK_LO_AND; P += 2; CL += 2; } break; case '=': { T.k = TK_AS_AND; P += 2; CL += 2; } break; } break; - case '|': switch (D) { + case '|': switch (P[1]) { default: { T.k = TK_BW_OR; P += 1; CL += 1; } break; case '|': { T.k = TK_LO_OR; P += 2; CL += 2; } break; case '=': { T.k = TK_AS_OR; P += 2; CL += 2; } break; } break; - case '~': switch (D) { - default: { T.k = TK_BW_NOT; P += 1; CL += 1; } break; + case '~': switch (P[1]) { + default: { T.k = TK_TILDE; P += 1; CL += 1; } break; case '=': { T.k = TK_AS_NOT; P += 2; CL += 2; } break; } break; - case '^': switch (D) { + case '^': switch (P[1]) { default: { T.k = TK_BW_XOR; P += 1; CL += 1; } break; case '=': { T.k = TK_AS_XOR; P += 2; CL += 2; } break; } break; @@ -208,7 +215,7 @@ tok lex_next(lex *l) { if (C != '\\') { *head = C; P += 1; head += 1; } /* Escape characters are processed and re-written to head */ - else switch (D) { + else switch (P[1]) { case '0': { *head = 0x00; P += 2; head += 1; } break; case 'a': { *head = '\a'; P += 2; head += 1; } break; case 'b': { *head = '\b'; P += 2; head += 1; } break; @@ -225,8 +232,8 @@ tok lex_next(lex *l) { // case 'x': {} break; // case 'u': {} break; default: { - note(l->n, l->ln, l->cl, 1, "Unknown escape sequence: \"\\%c\"", D); - *head = D; P += 2; head += 1; + note(l->n, l->ln, l->cl, 1, "Unknown escape sequence: \"\\%c\"", P[1]); + *head = P[1]; P += 2; head += 1; } break; } } @@ -257,10 +264,7 @@ tok lex_next(lex *l) { } break; /* Handle unknown characters */ - default: { - note(l->n, LN, CL, 1, "Unknown character: %X '%c'", C, C); - P += 1; CL += 1; - } break; + default: { note(l->n, LN, CL, 1, "Unknown character: %X '%c'", C, C); P += 1; CL += 1; } break; } return t; @@ -268,10 +272,7 @@ tok lex_next(lex *l) { /* Lex the next token if the current is of a specific type. */ tok lex_kind(lex *l, tok_k k) { - if (T.k != k) { - note(l->n, T.ln, T.cl, 0, "Unexpected \"%s\", was expecting \"%s\"", tok_ks[T.k], tok_ks[k]); - } - + if (T.k != k) { note(l->n, T.ln, T.cl, 0, "Unexpected \"%s\", was expecting \"%s\"", tok_ks[T.k], tok_ks[k]); } return lex_next(l); } diff --git a/src/lex.h b/src/lex.h index 83abccd..a0e4474 100644 --- a/src/lex.h +++ b/src/lex.h @@ -18,14 +18,14 @@ typedef enum { TK_LPAREN, TK_RPAREN, TK_LBRACK, TK_RBRACK, TK_LBRACE, TK_RBRACE, TK_COLON, TK_SCOLON, TK_COMMA, TK_PERIOD, TK_RARROW, TK_QMARK, TK_HASH, - TK_OP_ADD, TK_OP_SUB, TK_OP_MUL, TK_OP_DIV, TK_OP_MOD, + TK_ADD, TK_SUB, TK_MUL, TK_DIV, TK_MOD, TK_EQ, TK_NE, TK_LT, TK_LE, TK_GT, TK_GE, TK_EMARK, TK_LO_AND, TK_LO_OR, - TK_BW_NOT, TK_BW_AND, TK_BW_OR, TK_BW_XOR, TK_BW_SHL, TK_BW_SHR, + TK_TILDE, TK_BW_AND, TK_BW_OR, TK_BW_XOR, TK_LSHIFT, TK_RSHIFT, TK_ASSIGN, TK_AS_ADD, TK_AS_SUB, TK_AS_MUL, TK_AS_DIV, TK_AS_MOD, - TK_AS_NOT, TK_AS_AND, TK_AS_OR, TK_AS_XOR, TK_AS_SHL, TK_AS_SHR, + TK_AS_NOT, TK_AS_AND, TK_AS_OR, TK_AS_XOR, TK_AS_LSHIFT, TK_AS_RSHIFT, } tok_k; /* diff --git a/src/llvm.c b/src/llvm.c index bafe6b3..b10a0da 100644 --- a/src/llvm.c +++ b/src/llvm.c @@ -136,11 +136,9 @@ static LLVMValueRef llvm_stmt_compound(ast *a, syt *st) { static LLVMValueRef llvm_stmt_decl(ast *a, syt *st) { assert(a->k == AK_DECL); - if (CL && C[0]->k == AK_PROC) { + if (CL && C[0]->k == AK_PROC) /* AK_PROC has a scope */ { LLVMTypeRef art[C[0]->c.al - 1]; - for (UINT i = 0; i < C[0]->c.al - 1; i += 1) { - art[i] = llvm_type(ast_type(C[0]->c.a[i], st)); - } + for (UINT i = 0; i < C[0]->c.al - 1; i += 1) { art[i] = llvm_type(ast_type(C[0]->c.a[i], &A.st)); } LLVMTypeRef ft = LLVMFunctionType(llvm_type(C[0]->t), art, C[0]->c.al - 1, 0); LLVMValueRef f = LLVMAddFunction(llvm_module, A.s, ft); @@ -148,20 +146,20 @@ static LLVMValueRef llvm_stmt_decl(ast *a, syt *st) { LLVMBasicBlockRef bb = LLVMAppendBasicBlock(f, ""); LLVMPositionBuilderAtEnd(llvm_builder, bb); - for (UINT i = 0; i < C[0]->c.al - 1; i += 1) { - C[0]->c.a[i]->llvm_v = LLVMGetParam(f, i); - } + /* Allocate scoped procedure arguments */ + for (UINT i = 0; i < C[0]->c.al - 1; i += 1) { C[0]->c.a[i]->llvm_v = LLVMBuildAlloca(llvm_builder, art[i], ""); } + for (UINT i = 0; i < C[0]->c.al - 1; i += 1) { LLVMBuildStore(llvm_builder, LLVMGetParam(f, i), C[0]->c.a[i]->llvm_v); } A.llvm_t = ft; A.llvm_v = f; - llvm_expr_proc(C[0], st); + llvm_expr_proc(C[0], &A.st); } else { - if (A.p->k == AK_PROG) { /* Global */ + if (A.p->k == AK_PROG) /* Global */ { LLVMValueRef v = LLVMAddGlobal(llvm_module, llvm_type(A.t), ""); LLVMSetInitializer(v, CL ? llvm_expr(C[0], st, true) : llvm_ival(A.t)); A.llvm_v = v; } - else { /* Local */ + else /* Local */ { LLVMValueRef v = LLVMBuildAlloca(llvm_builder, llvm_type(A.t), ""); LLVMBuildStore(llvm_builder, CL ? llvm_expr(C[0], st, true) : llvm_ival(A.t), v); A.llvm_v = v; @@ -250,9 +248,7 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { if (sym == NULL) { note(file_name, A.ln, A.cl, -1, "Undefined variable \"%s\"", A.s); } if (!sym->llvm_v) { note(file_name, A.ln, A.cl, -1, "Variable \"%s\" follows (llvm:llvm_expr)", A.s); } - /* TODO fix procedure argument handling, should be assignable */ - /* TODO fix array variable handling */ - if (!load || sym->k == AK_ID || sym->t->k == TY_ARR) { return sym->llvm_v; } + if (!load || sym->t->k == TY_ARR) { return sym->llvm_v; } else { return LLVMBuildLoad2(llvm_builder, llvm_type(sym->t), sym->llvm_v, ""); } } break; case AK_CALL: { @@ -260,26 +256,18 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { if (sym == NULL) { note(file_name, A.ln, A.cl, -1, "Undefined procedure \"%s\" (llvm:llvm_expr)", C[0]->s); } if (!sym->llvm_v) { note(file_name, A.ln, A.cl, -1, "Procedure \"%s\" follows (llvm:llvm_expr)", C[0]->s); } - LLVMValueRef args[CL - 1]; - for (UINT i = 1; i < CL; i += 1) { - args[i - 1] = llvm_expr(C[i], st, true); - } - + LLVMValueRef args[CL - 1]; for (UINT i = 1; i < CL; i += 1) { args[i - 1] = llvm_expr(C[i], st, true); } return LLVMBuildCall2(llvm_builder, sym->llvm_t, sym->llvm_v, args, CL - 1, ""); } break; case AK_HASH_SYSCALL: case AK_HASH: { return llvm_expr_hash(a, st); } break; case AK_SUBS: { - ast *sym = syt_search_h(st, C[0]->h, C[0]->s); - if (sym == NULL) { note(file_name, A.ln, A.cl, 0, "Undefined variable \"%s\"", C[0]->s); } - - if (!sym->llvm_v) { note(file_name, A.ln, A.cl, -1, "Variable \"%s\" follows (llvm:llvm_expr)", A.s); } - + /* FIXME subscripting does not work with pointers */ LLVMValueRef idc[1] = { llvm_expr(C[1], st, true) }; - LLVMValueRef vr = LLVMBuildGEP2(llvm_builder, llvm_type(sym->t), sym->llvm_v, idc, 1, ""); + LLVMValueRef vr = LLVMBuildInBoundsGEP2(llvm_builder, llvm_type(ast_type(C[0], st)), llvm_expr(C[0], st, false), idc, 1, ""); if (!load) { return vr; } - else { return LLVMBuildLoad2(llvm_builder, llvm_type(sym->t->base), vr, ""); } + else { return LLVMBuildLoad2(llvm_builder, llvm_type(ast_type(C[0], st)->base), vr, ""); } } case AK_OP_POS: { a = C[0]; goto reset; /* no-op */ } break; @@ -291,18 +279,14 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) { else if (is_flt(t)) { return LLVMBuildFNeg(llvm_builder, llvm_expr(C[0], st, true), "neg"); } else { note(file_name, A.ln, A.cl, -1, "Expression cannot be made negative (llvm:llvm_expr)"); } } break; - case AK_OP_ADO: { - ast *v = syt_search(st, C[0]->s); - if (v == NULL) { note(file_name, A.ln, A.cl, -1, "Undefined variable (llvm:llvm_expr)"); } - if (v->llvm_v == NULL) { note(file_name, A.ln, A.cl, -1, "Variable follows (llvm:llvm_expr)"); } - - return v->llvm_v; /* TODO handle non-variables (?) */ - } break; + case AK_OP_ADO: { return llvm_expr(C[0], st, false); } break; case AK_OP_DRF: { - if (C[0]->t == NULL) { note(file_name, A.ln, A.cl, -1, "Child is missing a type (llvm:llvm_expr)"); } - if (C[0]->t->base == NULL) { note(file_name, A.ln, A.cl, -1, "Cannot be dereferenced (llvm:llvm_expr)"); } + type *t = ast_type(C[0], st); + if (t == NULL) { note(file_name, A.ln, A.cl, -1, "Child is missing a type (llvm:llvm_expr)"); } + if (t->base == NULL) { note(file_name, A.ln, A.cl, -1, "Cannot be dereferenced (llvm:llvm_expr)"); } - return LLVMBuildLoad2(llvm_builder, llvm_type(C[0]->t->base), llvm_expr(C[0], st, true), ""); + if (!load) { return llvm_expr(C[0], st, true); } + else { return LLVMBuildLoad2(llvm_builder, llvm_type(t->base), llvm_expr(C[0], st, true), ""); } } case AK_OP_ADD: { diff --git a/src/log.c b/src/log.c index 8166eff..2d6184d 100644 --- a/src/log.c +++ b/src/log.c @@ -6,9 +6,11 @@ #include "log.h" #include "util/util.h" +#include <stdarg.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> +#include <stdnoreturn.h> bool log_waerr = false; sint log_level = 4, log_limit = 8; @@ -17,7 +19,7 @@ static sint log_count = 0; /* Log a compiler fatal (-1), error (0), warning (1-3), or note (4). */ void note(const char *file, UINT ln, UINT cl, sint level, const char *format, ...) { - if (file) { fprintf(stderr, "%s:%zu:%zu: ", file, ln + 1, cl + 1); } + if (file) { fprintf(stderr, "%s:%lu:%lu: ", file, ln + 1, cl + 1); } if (level <= -1) { fprintf(stderr, "fatal: "); } else if (level == 0) { fprintf(stderr, "error: "); } @@ -32,3 +34,9 @@ void note(const char *file, UINT ln, UINT cl, sint level, const char *format, .. /* Check if there has been an error. */ bool has_error(void) { return log_count > 0; } + +/* Print a panic message and exit. */ +noreturn void __panic(const char *file, UINT ln, const char *format, ...) { + fflush(stderr); fprintf(stderr, file != NULL ? "panic: %s:%lu: " : "panic: ", file, ln); + va_list ap; va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); fputc('\n', stderr); exit(-1); +} diff --git a/src/log.h b/src/log.h index bfb69d5..8ca274e 100644 --- a/src/log.h +++ b/src/log.h @@ -6,6 +6,8 @@ #ifndef G_LOG_H_1RPM5P9E #define G_LOG_H_1RPM5P9E +#include <stdnoreturn.h> + #include "util/util.h" extern bool log_waerr; @@ -14,4 +16,12 @@ extern sint log_level, log_limit; extern void note(const char *file, UINT ln, UINT cl, sint level, const char *format, ...); extern bool has_error(void); +#ifdef NDEBUG +#define panic(format, ...) (__panic(NULL, 0, format __VA_OPT__(,) __VA_ARGS__)) +#else +#define panic(format, ...) (__panic(__FILE__, __LINE__, format __VA_OPT__(,) __VA_ARGS__)) +#endif + +extern noreturn void __panic(const char *file, UINT ln, const char *format, ...); + #endif // G_LOG_H_1RPM5P9E diff --git a/src/parse.c b/src/parse.c index dcf206e..f96234c 100644 --- a/src/parse.c +++ b/src/parse.c @@ -199,7 +199,7 @@ static ast *parse_stmt_decl(lex *l, syt *st, bool scolon) { assert(T.k == TK_ID); lex_next(l); assert(T.k == TK_COLON); lex_next(l); /* Store the declaration's type if one is specified */ - if (T.k == TK_ID || T.k == TK_OP_MUL || T.k == TK_LBRACK) { + if (T.k == TK_ID || T.k == TK_MUL || T.k == TK_LBRACK) { ta_pair ta = parse_type(l, st); a->t = ta.t; /* TODO keep the AST component */ } @@ -314,12 +314,12 @@ static ast *parse_expr(lex *l, syt *st, s32 o) { left->h = T.h; left->s = strdup_or_fail(T.s); lex_kind(l, TK_ID); } break; case TK_LPAREN: { lex_next(l); left = parse_expr(l, st, 0); lex_kind(l, TK_RPAREN); } break; - case TK_OP_ADD: { left = ast_init(AK_OP_POS, T.ln, T.cl); } goto prefix; - case TK_OP_SUB: { left = ast_init(AK_OP_NEG, T.ln, T.cl); } goto prefix; + case TK_ADD: { left = ast_init(AK_OP_POS, T.ln, T.cl); } goto prefix; + case TK_SUB: { left = ast_init(AK_OP_NEG, T.ln, T.cl); } goto prefix; case TK_EMARK: { left = ast_init(AK_LO_NOT, T.ln, T.cl); } goto prefix; - case TK_BW_NOT: { left = ast_init(AK_BW_NOT, T.ln, T.cl); } goto prefix; + case TK_TILDE: { left = ast_init(AK_BW_NOT, T.ln, T.cl); } goto prefix; case TK_BW_AND: { left = ast_init(AK_OP_ADO, T.ln, T.cl); } goto prefix; - case TK_OP_MUL: { left = ast_init(AK_OP_DRF, T.ln, T.cl); } goto prefix; + case TK_MUL: { left = ast_init(AK_OP_DRF, T.ln, T.cl); } goto prefix; prefix: { lex_next(l); ast_push(left, parse_expr(l, st, ast_precedence(left->k))); } break; default: { note(l->n, T.ln, T.cl, 0, "Unexpected \"%s\", was expecting an expression", tok_ks[T.k]); } break; } @@ -353,17 +353,17 @@ static ast *parse_expr(lex *l, syt *st, s32 o) { case TK_AS_MUL: { a = ast_init(AK_AS_MUL, T.ln, T.cl); } goto infix; case TK_AS_DIV: { a = ast_init(AK_AS_DIV, T.ln, T.cl); } goto infix; case TK_AS_MOD: { a = ast_init(AK_AS_MOD, T.ln, T.cl); } goto infix; - case TK_OP_ADD: { a = ast_init(AK_OP_ADD, T.ln, T.cl); } goto infix; - case TK_OP_SUB: { a = ast_init(AK_OP_SUB, T.ln, T.cl); } goto infix; - case TK_OP_MUL: { a = ast_init(AK_OP_MUL, T.ln, T.cl); } goto infix; - case TK_OP_DIV: { a = ast_init(AK_OP_DIV, T.ln, T.cl); } goto infix; - case TK_OP_MOD: { a = ast_init(AK_OP_MOD, T.ln, T.cl); } goto infix; - case TK_EQ: { a = ast_init(AK_EQ, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; - case TK_NE: { a = ast_init(AK_NE, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; - case TK_LT: { a = ast_init(AK_LT, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; - case TK_LE: { a = ast_init(AK_LE, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; - case TK_GT: { a = ast_init(AK_GT, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; - case TK_GE: { a = ast_init(AK_GE, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; + case TK_ADD: { a = ast_init(AK_OP_ADD, T.ln, T.cl); } goto infix; + case TK_SUB: { a = ast_init(AK_OP_SUB, T.ln, T.cl); } goto infix; + case TK_MUL: { a = ast_init(AK_OP_MUL, T.ln, T.cl); } goto infix; + case TK_DIV: { a = ast_init(AK_OP_DIV, T.ln, T.cl); } goto infix; + case TK_MOD: { a = ast_init(AK_OP_MOD, T.ln, T.cl); } goto infix; + case TK_EQ: { a = ast_init(AK_EQ, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; + case TK_NE: { a = ast_init(AK_NE, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; + case TK_LT: { a = ast_init(AK_LT, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; + case TK_LE: { a = ast_init(AK_LE, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; + case TK_GT: { a = ast_init(AK_GT, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; + case TK_GE: { a = ast_init(AK_GE, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; case TK_LO_AND: { a = ast_init(AK_LO_AND, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; case TK_LO_OR: { a = ast_init(AK_LO_OR, T.ln, T.cl); a->t = &TYPE(TY_BOOL); } goto infix; infix: { lex_next(l); ast_push(a, left); ast_push(a, parse_expr(l, st, ast_precedence(a->k))); } break; @@ -387,7 +387,7 @@ static ast *parse_expr_compound(lex *l, syt *st) { lex_kind(l, TK_RBRACE); return a; } -/* Parse a procedure expression. */ +/* Parse a procedure expression. AK_PROC has a scope. */ static ast *parse_expr_proc(lex *l, syt *st) { assert(T.k == TK_PROC); @@ -429,7 +429,7 @@ static inline ta_pair parse_type(lex *l, syt *st) { /* Parse optional pointer and array specifiers */ for (register type *t = NULL;;) switch (T.k) { - case TK_OP_MUL: { lex_next(l); t = type_ptr(NULL, 1); } goto store; + case TK_MUL: { lex_next(l); t = type_ptr(NULL, 1); } goto store; case TK_LBRACK: { lex_next(l); @@ -496,8 +496,7 @@ static ast *parse_flt(lex *l, syt *st) { /* Expression operator precedence: 8 > expression group (parenthesis), procedure call, array subscripting - 7 > positive (prefix +), negative (prefix -), logical not (prefix !), bitwise not (prefix ~), - address-of (prefix &), dereference (prefix *) + 7 > prefix (+, -, !, ~, &, *) 6 > multiplication (*), division (/), modulo (%) 5 > addition (+), subtraction (-) 4 > comparison (==, !=, <, >, <=, >=) @@ -510,8 +509,8 @@ static ast *parse_flt(lex *l, syt *st) { static s32 tok_precedence(tok_k tk) { switch (tk) { case TK_LPAREN: case TK_LBRACK: { return 8; } - case TK_OP_MUL: case TK_OP_DIV: case TK_OP_MOD: { return 6; } - case TK_OP_ADD: case TK_OP_SUB: { return 5; } + case TK_MUL: case TK_DIV: case TK_MOD: { return 6; } + case TK_ADD: case TK_SUB: { return 5; } case TK_EQ: case TK_NE: case TK_LT: case TK_LE: case TK_GT: case TK_GE: { return 4; } case TK_LO_AND: { return 3; } case TK_LO_OR: { return 2; }