Aria

A low-level systems programming language
git clone git://git.m21c.me/Aria.git
Log | Files | Refs | LICENSE

commit 3ffc6b6c22cbaac8f8d11d344e13fbd195551dc9
parent 0701d61e320ece485efb05e86b4d69f87cc6c88e
Author: m21c  <ho*******@gmail.com>
Date:   Thu, 15 Jul 2021 10:55:43 +0200

re-organized global vars into struct + added SrcLoc

Diffstat:
Maria.c | 1273+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
1 file changed, 754 insertions(+), 519 deletions(-)

diff --git a/aria.c b/aria.c @@ -7,6 +7,8 @@ #include <stdbool.h> #include <string.h> +typedef unsigned int uint; + /* - forward declarations - */ @@ -185,8 +187,14 @@ enum { /* - type definitions - */ +typedef struct SrcLoc { + uint line, column; + const char *filename; +} SrcLoc; + struct Node { Kind kind; + SrcLoc loc; Type *type; @@ -208,6 +216,7 @@ struct Node { struct Type { TypeKind kind; + SrcLoc loc; size_t size, align; @@ -227,6 +236,7 @@ struct Type { struct Decl { DeclKind kind; + SrcLoc loc; Type *type; @@ -239,6 +249,7 @@ struct Decl { struct Env { EnvKind kind; + SrcLoc loc; uint8_t keycache[64]; @@ -253,35 +264,73 @@ struct Env { Env *pendingnext, *pendingprev; }; +typedef struct Source { + SrcLoc currloc; + + /* pre-lexer state */ + + char line[4096]; + long linepos; + + bool handlereplprompt; + + /* error-reporting and lexer state */ + + FILE *filein; + int tabwidth; + char stringbuf[1024]; + + int lastindent, lastkind; + Node tok; + + + /* environment */ + + Env *headenv, *currenv; + Env *pendingenvhead, *pendingenvtail; + + /* parser state */ + + Node *lastis; +} Source; + + + +/* - global-vars - */ + +Source testsource; + /* - look-up tables - */ +#define defaultloc {0, 1, "<builtin>"} + Type prim[] = { - [TERRTYPE] = {TERRTYPE, 0, 0, {0}, NULL}, - [TUNDEFINED] = {TUNDEFINED, 0, 0, {0}, NULL}, + [TERRTYPE] = {TERRTYPE, defaultloc, 0, 0, {0}, NULL}, + [TUNDEFINED] = {TUNDEFINED, defaultloc, 0, 0, {0}, NULL}, - [TVOID] = {TVOID, 0, 0, {0}, NULL}, + [TVOID] = {TVOID, defaultloc, 0, 0, {0}, NULL}, - [TBOOL] = {TBOOL, 1, 1, {0}, NULL}, + [TBOOL] = {TBOOL, defaultloc, 1, 1, {0}, NULL}, - [TINFER] = {TINFER, 4, 4, {0}, NULL}, - [TUINFER] = {TUINFER, 4, 4, {0}, NULL}, + [TINFER] = {TINFER, defaultloc, 4, 4, {0}, NULL}, + [TUINFER] = {TUINFER, defaultloc, 4, 4, {0}, NULL}, - [TS8] = {TS8, 1, 1, {0}, NULL}, - [TU8] = {TU8, 1, 1, {0}, NULL}, - [TS16] = {TS16, 2, 2, {0}, NULL}, - [TU16] = {TU16, 2, 2, {0}, NULL}, - [TS32] = {TS32, 4, 4, {0}, NULL}, - [TU32] = {TU32, 4, 4, {0}, NULL}, - [TS64] = {TS64, 8, 8, {0}, NULL}, - [TU64] = {TU64, 8, 8, {0}, NULL}, + [TS8] = {TS8, defaultloc, 1, 1, {0}, NULL}, + [TU8] = {TU8, defaultloc, 1, 1, {0}, NULL}, + [TS16] = {TS16, defaultloc, 2, 2, {0}, NULL}, + [TU16] = {TU16, defaultloc, 2, 2, {0}, NULL}, + [TS32] = {TS32, defaultloc, 4, 4, {0}, NULL}, + [TU32] = {TU32, defaultloc, 4, 4, {0}, NULL}, + [TS64] = {TS64, defaultloc, 8, 8, {0}, NULL}, + [TU64] = {TU64, defaultloc, 8, 8, {0}, NULL}, - [TF32] = {TF32, 4, 4, {0}, NULL}, - [TF64] = {TF64, 8, 8, {0}, NULL}, + [TF32] = {TF32, defaultloc, 4, 4, {0}, NULL}, + [TF64] = {TF64, defaultloc, 8, 8, {0}, NULL}, - [TPTR] = {TPTR, 8, 8, {0}, NULL}, - [TARRAY] = {TARRAY, 0, 0, {0}, NULL}, + [TPTR] = {TPTR, defaultloc, 8, 8, {0}, NULL}, + [TARRAY] = {TARRAY, defaultloc, 0, 0, {0}, NULL}, }; int keywordlengths[OSTART - KSTART]; @@ -535,65 +584,60 @@ mystrcasecmp(const char *str1, const char *str2) { /* - pre-lexer - */ -char line[4096]; -int currline, lastline; -long linepos; - -bool handlereplprompt; - void -tryprompt(FILE *in, const char ch) { - if (handlereplprompt) { +tryprompt(Source *source, const char ch) { + if (source->handlereplprompt) { fprintf(stdout, "\e[35m%c \e[0m", ch); - } else if (in == stdin) { - handlereplprompt = true; + } else if (source->filein == stdin) { + source->handlereplprompt = true; } } bool -mygetline(FILE *in) { +mygetline(Source *source) { int i, l, c; + FILE *in = source->filein; - tryprompt(in, '.'); + tryprompt(source, '.'); c = getc(in); - linepos = ftell(in); + source->linepos = ftell(in); advance: - ++currline; + ++source->currloc.line; i = 0, l = 0; while (c == '\r' || c == '\n') { - tryprompt(in, '.'); + tryprompt(source, '.'); l = c, c = getc(in); if (l == '\r' && c == '\n') c = getc(in); - ++currline; + ++source->currloc.line; } - lastline = currline; + source->tok.loc.line = source->currloc.line; while (c != EOF && c != '\n' && c != '\r') { - line[i++] = c; + source->line[i++] = c; c = getc(in); if (c == '\\') { int x = getc(in); if (x == '\n') { - tryprompt(in, '\\'); + tryprompt(source, '\\'); c = getc(in); - ++currline; + ++source->currloc.line; } else if (x == '\r') { int y; - tryprompt(in, '\\'); + tryprompt(source, '\\'); y = getc(in); c = (y == '\n') ? getc(in) : y; - ++currline; + ++source->currloc.line; } else if (x == EOF) { c = x; } else { @@ -605,7 +649,7 @@ advance: if (c == '\r') { int x; - tryprompt(in, '.'); + tryprompt(source, '.'); x = getc(in); if (x != '\n') ungetc(x, in); @@ -614,7 +658,7 @@ advance: if (c != EOF && i == 0) goto advance; - line[i] = 0; + source->line[i] = 0; return c != EOF || i; } @@ -639,7 +683,8 @@ initkeywords(void) { int i, j, h; for (i = 0; i < lengthof(keywordlengths); ++i) { int n = keywordlengths[i] = strlen(nodestrings[i + KSTART]); - h = strnhash(nodestrings[i + KSTART], n) & (lengthof(keywordkeys) - 8); + h = strnhash(nodestrings[i + KSTART], n) & + (lengthof(keywordkeys) - 8); for (j = 0; j < 8; ++j, ++h) { if (!keywordkeys[h]) { keywordkeys[h] = nodestrings[i + KSTART]; @@ -799,28 +844,20 @@ getstringkey(StringMap *map, const char *str, int n) { -/* - global-vars - */ - -FILE *filein; -const char *filename; -const int tabwidth = 8; -char stringbuf[1024]; - -int currcol, lastcol, lastindent, lastkind; -Node tok; - - - /* - error reporting - */ int -warn(const char *fmt, ...) { +warn(SrcLoc *loc, const char *fmt, ...) { va_list ap; int n; + const char *filename = loc ? loc->filename : "<unknown-source>"; + int line = loc ? loc->line : 1; + int column = loc ? loc->column : 0; + va_start(ap, fmt); n = fprintf(stderr, "%s:%i:%i: warning: ", - filename, lastline, lastcol + 1); + filename, line, column + 1); n += vfprintf(stderr, fmt, ap); n += fprintf(stderr, "\n"); va_end(ap); @@ -829,13 +866,17 @@ warn(const char *fmt, ...) { } int -error(const char *fmt, ...) { +error(SrcLoc *loc, const char *fmt, ...) { va_list ap; int n; + const char *filename = loc ? loc->filename : "<unknown-source>"; + int line = loc ? loc->line : 1; + int column = loc ? loc->column : 0; + va_start(ap, fmt); n = fprintf(stderr, "%s:%i:%i: error: ", - filename, lastline, lastcol + 1); + filename, line, column + 1); n += vfprintf(stderr, fmt, ap); n += fprintf(stderr, "\n"); va_end(ap); @@ -847,48 +888,51 @@ error(const char *fmt, ...) { /* - lexer - */ -#define nextindent(indent) \ - ((indent) + tabwidth - ((indent) % tabwidth)) +#define nextindent(source, indent) \ + ((indent) + (source)->tabwidth - ((indent) % (source)->tabwidth)) int -gettok(bool haslhs) { - register int c0 = line[currcol]; +gettok(Source *source, bool haslhs) { + register int c0 = source->line[source->currloc.column]; static bool hasnewline = false; - lastkind = tok.kind; + source->lastkind = source->tok.kind; skipwhite: if (hasnewline) { - if (!mygetline(filein)) { - lastindent = 0; - return tok.kind = 0; + if (!mygetline(source)) { + source->lastindent = 0; + return source->tok.kind = 0; } - c0 = line[(currcol = 0)]; + c0 = source->line[(source->currloc.column = 0)]; } - if (currcol) { + if (source->currloc.column) { while (isspace(c0)) - c0 = line[++currcol]; + c0 = source->line[++source->currloc.column]; } else { - lastindent = 0; + source->lastindent = 0; while (isspace(c0)) { if (c0 == '\t') { - lastindent = nextindent(lastindent); + source->lastindent = nextindent( + source, + source->lastindent + ); } else { - ++lastindent; + ++source->lastindent; } - c0 = line[++currcol]; + c0 = source->line[++source->currloc.column]; } } - tok.type = prim + TUNDEFINED; - tok.u.u = 0; - tok.lhs = NULL; - tok.rhs = NULL; - tok.prev = NULL; - tok.next = NULL; - lastcol = currcol; + source->tok.type = prim + TUNDEFINED; + source->tok.u.u = 0; + source->tok.lhs = NULL; + source->tok.rhs = NULL; + source->tok.prev = NULL; + source->tok.next = NULL; + source->tok.loc.column = source->currloc.column; /* get line */ if (!c0 || c0 == '#') { @@ -896,7 +940,7 @@ skipwhite: goto skipwhite; } else { hasnewline = true; - return tok.kind = '\n'; + return source->tok.kind = '\n'; } } @@ -907,108 +951,159 @@ skipwhite: int keyword; while (isalnum(c0) || c0 == '_') - c0 = line[++currcol]; + c0 = source->line[++source->currloc.column]; + + keyword = getkeyword( + source->line + source->tok.loc.column, + source->currloc.column - source->tok.loc.column + ); - keyword = getkeyword(line + lastcol, currcol - lastcol); - if (tok.kind != '@' && keyword >= 0 && tok.kind != ODISP) { - if (keyword == KOR - KSTART || keyword == KAND - KSTART) { - return tok.kind = keyword == KOR - KSTART ? OLOR : OLAND; + if (source->tok.kind != '@' && + keyword >= 0 && + source->tok.kind != ODISP) + { + if (keyword == KOR - KSTART || + keyword == KAND - KSTART) + { + return source->tok.kind = + keyword == KOR - KSTART ? OLOR : OLAND; } else if (keywordtypeids[keyword + KSTART]) { - tok.u.key = keywordtypeids[keyword + KSTART]; - tok.type = prim + tok.u.key; - return tok.kind = 'T'; + source->tok.u.key = + keywordtypeids[keyword + KSTART]; + source->tok.type = prim + source->tok.u.key; + + return source->tok.kind = 'T'; } - return tok.kind = keyword + KSTART; + + return source->tok.kind = keyword + KSTART; } - tok.u.key = getstringkey(&idents, - line + lastcol, currcol - lastcol); - return tok.kind = 'I'; + source->tok.u.key = getstringkey(&idents, + source->line + source->tok.loc.column, + source->currloc.column - source->tok.loc.column + ); + + return source->tok.kind = 'I'; } /* number literal */ - if (isdigit(c0) || c0 == '.' && isdigit(line[currcol+1])) { - int l = c0, t = line[currcol+1], i, j; + if (isdigit(c0) || + c0 == '.' && + isdigit(source->line[source->currloc.column+1])) + { + int l = c0, t = source->line[source->currloc.column+1], i, j; bool hasdec = false, hasexp = false; char *end; + advancenum: while (isalnum(c0) || c0 == '_' || - c0 == '.' && line[currcol+1] != '.' && !hasdec) + c0 == '.' && + source->line[source->currloc.column+1] != '.' && + !hasdec) { if (c0 != '_') l = c0; if (c0 == '.') hasdec = true; - c0 = line[++currcol]; + + c0 = source->line[++source->currloc.column]; } if (hasdec && !hasexp && (c0 == '+' || c0 == '-')) { t = tolower(t); l = tolower(l); + if (l == 'e' && t != 'x' || l == 'p' && t == 'x') { - c0 = line[++currcol]; + c0 = source->line[++source->currloc.column]; hasexp = true; + goto advancenum; } } /* remove underscores */ - for (j = 0, i = lastcol; i < currcol; ++i) { - if (line[i] != '_') { - if (j >= lengthof(stringbuf) - 1) { - error("number-literal is too long"); - tok.u.u = 0; - tok.type = prim + TINT; - return tok.kind = 'N'; + for (j = 0, i = source->tok.loc.column; + i < source->currloc.column; + ++i) + { + if (source->line[i] != '_') { + if (j >= lengthof(source->stringbuf) - 1) { + error(&source->currloc, + "number-literal is too long" + ); + + source->tok.u.u = 0; + source->tok.type = prim + TINT; + + return source->tok.kind = 'N'; } - stringbuf[j++] = line[i]; + + source->stringbuf[j++] = source->line[i]; } } - stringbuf[j] = 0; + source->stringbuf[j] = 0; - if (strpbrk(stringbuf, ".pPrR") || - !strpbrk(stringbuf, "xX") && strpbrk(stringbuf, "eEfF")) + if (strpbrk(source->stringbuf, ".pPrR") || + !strpbrk(source->stringbuf, "xX") && + strpbrk(source->stringbuf, "eEfF")) { - tok.u.d = strtod(stringbuf, &end); - tok.type = prim + TDOUBLE; + source->tok.u.d = strtod(source->stringbuf, &end); + source->tok.type = prim + TDOUBLE; if (*end != 0) { /* FIXME(m21c): r-suffix might conflict with radix */ if ((*end == 'f' || *end == 'F') && !end[1]) { - tok.type = prim + TFLOAT; + source->tok.type = prim + TFLOAT; + } else if (*end == 'l' || *end == 'L') { - tok.type = prim + TDOUBLE; + source->tok.type = prim + TDOUBLE; if (end[1]) goto errorfloat; + } else if (!mystrcasecmp(end, "f32") || !mystrcasecmp(end, "r32")) { - tok.type = prim + TF32; + source->tok.type = prim + TF32; + } else if (!mystrcasecmp(end, "f64") || !mystrcasecmp(end, "r64")) { - tok.type = prim + TF64; + source->tok.type = prim + TF64; + } else { errorfloat: - error("invalid floating-point format"); + error( + &source->currloc, + "invalid floating-point format" + ); } } } else { int typeid = TUINT - TINT; - if (mystrncasecmp(stringbuf, "0b", 2) == 0) { - tok.u.u = strtoull(stringbuf + 2, &end, 2); + if (mystrncasecmp(source->stringbuf, "0b", 2) == 0) { + source->tok.u.u = strtoull( + source->stringbuf + 2, + &end, 2 + ); + } else { - tok.u.u = strtoull(stringbuf, &end, 0); + source->tok.u.u = strtoull( + source->stringbuf, + &end, 0 + ); + } switch (*end) { case 0: typeid = TINFER; break; + case 's': case 'S': case 'i': case 'I': typeid = 0; + case 'u': case 'U': ++end; if (*end == 0) { @@ -1032,6 +1127,7 @@ skipwhite: typeid += TSSIZE; break; } + default: if (!mystrcasecmp(end, "ll")) { typeid += TLLONG; @@ -1041,26 +1137,31 @@ skipwhite: goto errorint; } else { errorint: - error("invalid integer format"); + error( + &source->currloc, + "invalid integer format" + ); typeid = TINT; } } - tok.type = prim + typeid; + + source->tok.type = prim + typeid; } - return tok.kind = 'N'; + return source->tok.kind = 'N'; } /* string & character-literal */ if (c0 == '"' || c0 == '\'') { int delim = c0, j; - c0 = line[++currcol]; - lastcol = currcol; + c0 = source->line[++source->currloc.column]; + source->tok.loc.column = source->currloc.column; - j = currcol; + j = source->currloc.column; while (c0 != delim && c0 != 0) { if (c0 == '\\') { - switch ((c0 = line[++currcol])) { + c0 = source->line[++source->currloc.column]; + switch (c0) { case '\\': c0 = '\\'; break; @@ -1083,25 +1184,35 @@ skipwhite: case 0: goto stringeol; default: - error("invalid escape sequence '\\%c'", c0); + error( + &source->currloc, + "invalid escape sequence '\\%c'", + c0 + ); } } - line[j++] = c0; - c0 = line[++currcol]; + source->line[j++] = c0; + c0 = source->line[++source->currloc.column]; } - ++currcol; - line[j++] = 0; + ++source->currloc.column; + source->line[j++] = 0; if (c0 == 0) { stringeol: - error("unexpected end-of-line"); - return tok.kind = '\n'; + error( + &source->currloc, + "unexpected end-of-line" + ); + return source->tok.kind = '\n'; } /* TODO(m21c): read '\''-token as character-literal 'C' */ - tok.u.key = getstringkey(&strings, line + lastcol, j - lastcol); - return tok.kind = 'S'; + source->tok.u.key = getstringkey(&strings, + source->line + source->tok.loc.column, + j - source->tok.loc.column + ); + return source->tok.kind = 'S'; } /* delimiters */ @@ -1123,35 +1234,38 @@ skipwhite: if (haslhs) c0 = OCALL; joindelim: - ++currcol; - return tok.kind = c0; + ++source->currloc.column; + return source->tok.kind = c0; } /* operators */ -#define select(ch, then, otherwise) \ - (line[currcol] == (ch) ? ++currcol, (then) : (otherwise)) - switch (line[currcol++]) { +#define select(ch, then, otherwise) ( \ + source->line[source->currloc.column] == (ch) ? \ + ++source->currloc.column, (then) : \ + (otherwise) \ + ) + switch (source->line[source->currloc.column++]) { case '.': /* tok.kind = select('.', ORANGE, ODISP); */ - tok.kind = ODISP; + source->tok.kind = ODISP; goto joinop; case '*': - tok.kind = select('=', OMULA, (haslhs ? OMUL : OLPTR)); + source->tok.kind = select('=', OMULA, (haslhs ? OMUL : OLPTR)); goto joinop; case '/': - tok.kind = select('=', ODIVA, ODIV); + source->tok.kind = select('=', ODIVA, ODIV); goto joinop; case '%': - tok.kind = select('=', OMODA, OMOD); + source->tok.kind = select('=', OMODA, OMOD); goto joinop; case '<': - tok.kind = select('=', OLEQ, + source->tok.kind = select('=', OLEQ, select('<', select('=', OLSHA, OLSH), OLET)); goto joinop; case '>': - tok.kind = select('=', OGEQ, + source->tok.kind = select('=', OGEQ, select('>', select('>', select('=', OARSHA, OARSH), @@ -1159,45 +1273,45 @@ skipwhite: OGRT)); goto joinop; case '&': - tok.kind = select('=', OANDA, select('&', OLAND, + source->tok.kind = select('=', OANDA, select('&', OLAND, /*(haslhs ? OBAND : ORPTR)*/ OBAND)); goto joinop; case '+': - tok.kind = select('=', OADDA, select('+', + source->tok.kind = select('=', OADDA, select('+', (haslhs ? OSUFINC : OINC), (haslhs ? OADD : OPLUS))); goto joinop; case '-': - tok.kind = select('=', OSUBA, select('-', + source->tok.kind = select('=', OSUBA, select('-', (haslhs ? OSUFDEC : ODEC), (haslhs ? OSUB : OMINUS))); goto joinop; case '|': - tok.kind = select('=', OORA, select('|', OLOR, OBOR)); + source->tok.kind = select('=', OORA, select('|', OLOR, OBOR)); goto joinop; case '^': - tok.kind = select('=', OXORA, OXOR); + source->tok.kind = select('=', OXORA, OXOR); goto joinop; case '!': - tok.kind = select('=', ONEQ, OLNOT); + source->tok.kind = select('=', ONEQ, OLNOT); goto joinop; case '~': - tok.kind = select('=', OFLIP, OBNOT); + source->tok.kind = select('=', OFLIP, OBNOT); goto joinop; case '=': - tok.kind = select('=', select('=', OIDENT, OEQU), OASS); + source->tok.kind = select('=', select('=', OIDENT, OEQU), OASS); joinop: - return tok.kind; + return source->tok.kind; default: - error("invalid input character '%c'", c0); + error(&source->currloc, "invalid input character '%c'", c0); return 'Z'; } #undef select } -#define skipnewline() \ - (tok.kind == '\n' ? (void) gettok(false) : (void) 0) +#define skipnewline(source) \ + ((source)->tok.kind == '\n' ? (void) gettok(source, false) : (void) 0) @@ -1207,10 +1321,13 @@ Node nodebuf[4096]; int nodetop; Node * -makenode(Node *lhs) { +makenode(Node *tok, Node *lhs) { Node *node = nodebuf + nodetop++; - *node = tok; + *node = *tok; node->lhs = lhs; + node->rhs = NULL; + node->next = NULL; + node->prev = NULL; return node; } @@ -1234,10 +1351,6 @@ maketype(void) { Env envbuf[4096]; int envtop; -Env *headenv, *currenv; - -Env *pendingenvhead, *pendingenvtail; - Decl * finddeclinenv(int key, Env *env) { const int cacheindex = (key >> 3) & 0x3f; @@ -1257,13 +1370,13 @@ finddeclinenv(int key, Env *env) { } Decl * -finddeclaration(int key) { +finddeclaration(Env *startenv, int key) { const int cacheindex = (key >> 3) & 0x3f; const int cachebit = 1 << (key & 0x03); Env *env; - for (env = currenv; env; env = env->below) { + for (env = startenv; env; env = env->below) { Decl *decl; /* NOTE(m21c): look-up exclusion list first. @@ -1291,55 +1404,56 @@ finddeclaration(int key) { } Env * -setheadenv(EnvKind kind) { +setheadenv(Source *source, EnvKind kind) { /* NOTE(m21c): this might only be useful for parameter=>function env translation */ Env *env = envbuf + envtop++; env->kind = kind; - env->below = currenv; + env->below = source->currenv; - assert(headenv == NULL); - currenv = headenv = env; + assert(source->headenv == NULL); + source->currenv = source->headenv = env; return env; } Env * -pushenv(EnvKind kind) { - if (headenv) { - headenv->kind = kind; +pushenv(Source *source, EnvKind kind) { + if (source->headenv) { + source->headenv->kind = kind; - assert(headenv == currenv); - headenv = NULL; + assert(source->headenv == source->currenv); + source->headenv = NULL; - return currenv; + return source->currenv; } else { Env *env = envbuf + envtop++; env->kind = kind; - env->below = currenv; + env->below = source->currenv; - currenv = env; + source->currenv = env; return env; } } Env * -popenv(void) { +popenv(Source *source) { + Env *currenv = source->currenv; Env *env = currenv; if (currenv) - currenv = currenv->below; + source->currenv = currenv->below; return env; } Env * -getfuncenv(void) { +getfuncenv(Source *source) { Env *env; - for (env = currenv; env; env = env->below) { + for (env = source->currenv; env; env = env->below) { if (env->kind == SFUNCTION) return env; } @@ -1355,10 +1469,11 @@ Decl declbuf[4096]; int decltop; Decl * -makedecl(int key, DeclKind kind) { +makedecl(Source *source, int key, DeclKind kind) { const int cacheindex = (key >> 3) & 0x3f; const int cachebit = 1 << (key & 0x03); + Env *currenv = source->currenv; Decl *probe, *decl = declbuf + decltop++; decl->kind = kind; @@ -1371,7 +1486,12 @@ makedecl(int key, DeclKind kind) { probe = finddeclinenv(key, currenv); if (probe) { - error("'%s' already declared", getstring(idents, key)); + /* TODO(m21c): obtain SrcLoc properly */ + error( + &probe->loc, + "'%s' already declared", + getstring(idents, key) + ); } currenv->keycache[cacheindex] |= cachebit; @@ -1395,32 +1515,42 @@ makedecl(int key, DeclKind kind) { /* - parser - */ +#define getkind(source) \ + ((source)->tok.kind) + +#define getloc(source) \ + (&(source)->tok.loc) + bool -expect(int kind, bool nexthaslhs, const char *fmt, ...) { +expect(Source *source, int kind, bool nexthaslhs, const char *fmt, ...) { va_list ap; - if (tok.kind != kind) { + int line = source->tok.loc.line; + int column = source->tok.loc.column; + const char *filename = source->tok.loc.filename; + + if (getkind(source) != kind) { va_start(ap, fmt); fprintf(stderr, "%s:%i:%i: error: ", - filename, lastline, lastcol + 1); + filename, line, column + 1); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); return false; } - gettok(nexthaslhs); + gettok(source, nexthaslhs); return true; } int -qualifiers(int allowmask) { +qualifiers(Source *source, int allowmask) { int flags = 0, mask = allowmask; - while (iskeyword(tok.kind)) { + while (iskeyword(getkind(source))) { int f, m; - switch (tok.kind) { + switch (getkind(source)) { case KEXTERN: f = QEXTERN, m = ~QVISIB; break; @@ -1441,19 +1571,19 @@ qualifiers(int allowmask) { } if (f & ~allowmask) { - const char *str = nodestrings[tok.kind]; - error("invalid qualifier '%s'", str); + const char *str = nodestrings[getkind(source)]; + error(getloc(source), "invalid qualifier '%s'", str); } else if (f & flags & QTYPE) { - const char *str = nodestrings[tok.kind]; - warn("redundant qualifier '%s'", str); + const char *str = nodestrings[getkind(source)]; + warn(getloc(source), "redundant qualifier '%s'", str); } else if (f & ~mask) { - const char *str = nodestrings[tok.kind]; - error("redundant qualifier '%s'", str); + const char *str = nodestrings[getkind(source)]; + error(getloc(source), "redundant qualifier '%s'", str); } flags |= f & allowmask & mask; mask &= m; - gettok(false); + gettok(source, false); } finish: @@ -1461,51 +1591,51 @@ finish: } Node * -expr(int minprec); +expr(Source *source, int minprec); Type * -getbasetype(int flags) { +getbasetype(Source *source, int flags) { Type *result; - if (tok.kind == 'I') { + if (getkind(source) == 'I') { /* TODO(m21c): check/read type identifier */ return NULL; - } else if (tok.kind != 'T') { + } else if (getkind(source) != 'T') { return NULL; } - result = tok.type; + result = source->tok.type; - gettok(false); + gettok(source, false); return result; } Type * -gettype(Type *basetype) { +gettype(Source *source, Type *basetype) { int flags; if (!basetype) return NULL; advance: - flags = qualifiers(QTYPE); + flags = qualifiers(source, QTYPE); - if (tok.kind == '[') { + if (getkind(source) == '[') { Type *tmp = maketype(); tmp->kind = TARRAY; tmp->target = basetype, basetype = tmp; - gettok(false); - if (tok.kind != ']') - basetype->u.val = expr(PSTART); - expect(']', false, "expect ']'"); + gettok(source, false); + if (source->tok.kind != ']') + basetype->u.val = expr(source, PSTART); + expect(source, ']', false, "expect ']'"); goto advance; } - if (tok.kind == OLPTR) { + if (getkind(source) == OLPTR) { Type *tmp = maketype(); tmp->kind = TPTR; tmp->target = basetype, basetype = tmp; - gettok(false); + gettok(source, false); goto advance; } @@ -1513,13 +1643,13 @@ advance: } Node * -exprlist(bool isparam, Type *paramtype); +exprlist(Source *source, bool isparam, Type *paramtype); Node * -stmtlist(int indent, EnvKind kind); +stmtlist(Source *source, int indent, EnvKind kind); Node * -declaration(Type *ty) { +declaration(Source *source, Type *ty) { bool has_self_param = false; Decl *decl = NULL; Node *result = NULL; @@ -1536,63 +1666,63 @@ declaration(Type *ty) { * are processed */ /* - context = currenv->kind; + context = source->currenv->kind; */ - if (tok.kind == 'I') { - decl = makedecl(tok.u.key, DVAR); + if (getkind(source) == 'I') { + decl = makedecl(source, source->tok.u.key, DVAR); decl->type = ty; - result = makenode(NULL); + result = makenode(&source->tok, NULL); result->kind = ADECL; result->type = ty; result->u.declref = decl; - gettok(true); - } else if (tok.kind == 'T') { - Type *module = gettype(getbasetype(0)); - if (tok.kind == ODISP || tok.kind == ':') { - has_self_param = tok.kind == ':'; - gettok(false); + gettok(source, true); + } else if (getkind(source) == 'T') { + Type *module = gettype(source, getbasetype(source, 0)); + if (getkind(source) == ODISP || getkind(source) == ':') { + has_self_param = getkind(source) == ':'; + gettok(source, false); } else { - error("expected '.' or ':'"); + error(getloc(source), "expected '.' or ':'"); } /* TODO(m21c): obtain Decl* for * Type Module:my_decl * or Type Module.my_decl - declarations */ - if (tok.kind == 'I') { + if (getkind(source) == 'I') { /* module = makenode(module); module->kind = ODISP; module->rhs = makenode(NULL); */ - result = makenode(NULL); + result = makenode(&source->tok, NULL); result->kind = ADECL; /* result->rhs = module; */ - gettok(true); + gettok(source, true); } else { - error("expected identifier"); + error(getloc(source), "expected identifier"); } } else { - result = makenode(NULL); + result = makenode(&source->tok, NULL); result->kind = 'T'; result->type = ty; return result; } - if (tok.kind == OCALL) { + if (getkind(source) == OCALL) { Env *functionenv = NULL; Node *params = NULL; - gettok(false); - if (tok.kind != ')') { + gettok(source, false); + if (getkind(source) != ')') { Decl *param; - functionenv = pushenv(SPARAMLIST); - params = exprlist(true, NULL); + functionenv = pushenv(source, SPARAMLIST); + params = exprlist(source, true, NULL); for (param = functionenv->head; param; param = param->next) @@ -1601,26 +1731,26 @@ declaration(Type *ty) { param->kind = DPARAM; } } - expect(')', true, "expected ')'"); + expect(source, ')', true, "expected ')'"); - if (tok.kind != OASS) { + if (getkind(source) != OASS) { Node *stmts; - stmts = stmtlist(lastindent, SFUNCTION); + stmts = stmtlist(source, source->lastindent, SFUNCTION); result->lhs = stmts; - } else if (tok.kind == OASS) { + } else if (getkind(source) == OASS) { Node *node; - gettok(false); + gettok(source, false); functionenv->kind = SFUNCTION; - node = expr(PSTART); + node = expr(source, PSTART); result->lhs = node; } else { result->lhs = NULL; } - popenv(); + popenv(source); assert(decl); assert(decl->functionenv == NULL); @@ -1641,9 +1771,9 @@ declaration(Type *ty) { return result; } - if (tok.kind == OASS) { - gettok(false); - result->lhs = expr(PSTART); + if (getkind(source) == OASS) { + gettok(source, false); + result->lhs = expr(source, PSTART); assert(decl); decl->content = result->lhs; @@ -1658,8 +1788,8 @@ declaration(Type *ty) { } bool -isatom(void) { - switch ((int) tok.kind) { +isatom(Source *source) { + switch ((int) getkind(source)) { case 0: case '\n': case ';': case ',': case ':': @@ -1669,16 +1799,16 @@ isatom(void) { return false; } - if (getnumops(tok.kind) && getprec(tok.kind) != PUNARY) + if (getnumops(getkind(source)) && getprec(getkind(source)) != PUNARY) return false; return true; } Node * -stmtlist(int indent, EnvKind envkind) { +stmtlist(Source *source, int indent, EnvKind envkind) { Node *result = NULL, *lhs = NULL; - int needindent = nextindent(indent); + int needindent = nextindent(source, indent); Env *env = NULL; /* printf("needident: %d, currindent: %d, lastindent: %d\n", needindent, currindent, lastindent); */ @@ -1686,29 +1816,29 @@ stmtlist(int indent, EnvKind envkind) { for (;;) { Node *stmt; - if (tok.kind == '\n') { - gettok(false); - if (tok.kind == ';') - error("expected expression"); + if (getkind(source) == '\n') { + gettok(source, false); + if (getkind(source) == ';') + error(getloc(source), "expected expression"); } - if (lastkind == '\n' && lastindent < needindent) + if (source->lastkind == '\n' && source->lastindent < needindent) break; - if (tok.kind == ';') { - gettok(false); + if (getkind(source) == ';') { + gettok(source, false); /* NOTE(m21c): used for REPL */ - if (tok.kind == ';' || tok.kind == '\n') { + if (getkind(source) == ';' || getkind(source) == '\n') { /* TODO(m21c): output an error-message if not in REPL-mode */ } } - if (!isatom()) + if (!isatom(source)) break; - if (lhs && lastkind != '\n' && lastkind != ';') - error("expected line delimiter"); + if (lhs && source->lastkind != '\n' && source->lastkind != ';') + error(getloc(source), "expected line delimiter"); if (!env) { /* NOTE(m21c): if there is already a @@ -1716,16 +1846,16 @@ stmtlist(int indent, EnvKind envkind) { * function-environment, we just use * paramlist as our function-environment. * Else, push a new environment */ - if (envkind != SFUNCTION || !currenv || - currenv->kind != SPARAMLIST) + if (envkind != SFUNCTION || !source->currenv || + source->currenv->kind != SPARAMLIST) { - env = pushenv(envkind); + env = pushenv(source, envkind); } } - stmt = exprlist(false, NULL); + stmt = exprlist(source, false, NULL); - stmt = makenode(stmt); + stmt = makenode(&source->tok, stmt); stmt->kind = ASTMT; if (!lhs) { @@ -1738,14 +1868,17 @@ stmtlist(int indent, EnvKind envkind) { } /* NOTE(m21c): function: paramlist --> function, see NOTE above */ - if (envkind == SFUNCTION && currenv && currenv->kind == SPARAMLIST) { + if (envkind == SFUNCTION && + source->currenv && + source->currenv->kind == SPARAMLIST) + { assert(env == NULL); - currenv->kind = SFUNCTION; - env = currenv; + source->currenv->kind = SFUNCTION; + env = source->currenv; } else if (env) { - popenv(); + popenv(source); - result = makenode(result); + result = makenode(&source->tok, result); result->kind = ASCOPE; result->u.env = env; env->stmts = result; @@ -1754,123 +1887,136 @@ stmtlist(int indent, EnvKind envkind) { return result; } -Node *lastis; - Node * -atom(int flags) { - Node *lhs = NULL, *savedis = lastis; +atom(Source *source, int flags) { + Node *lhs = NULL, *savedis = source->lastis; Type *ty; int indent; /* int flags; */ /* unary 'is'-operator */ - if (tok.kind == KIS) { - if (!lastis) { - error("there is no left-hand-side for 'is'"); - lhs = makenode(NULL); + if (getkind(source) == KIS) { + if (!source->lastis) { + error( + getloc(source), + "there is no left-hand-side for 'is'" + ); + + lhs = makenode(&source->tok, NULL); } else { - lhs = makenode(lastis->lhs); + lhs = makenode(&source->tok, source->lastis->lhs); } - gettok(false); + gettok(source, false); lhs->kind = 'O'; - if (tok.kind == KNOT) - gettok(false), lhs->kind = ONEQ; + if (getkind(source) == KNOT) + gettok(source, false), lhs->kind = ONEQ; else lhs->kind = OEQU; - lhs->rhs = expr(PRELAT); + lhs->rhs = expr(source, PRELAT); return lhs; } /* unary prefix operators */ - if (getprec(tok.kind) == PUNARY) { - lhs = makenode(NULL); - gettok(false); - lhs->lhs = atom(0); + if (getprec(getkind(source)) == PUNARY) { + lhs = makenode(&source->tok, NULL); + gettok(source, false); + lhs->lhs = atom(source, 0); return lhs; } - if ((lhs = declaration(gettype(getbasetype(0))))) + lhs = declaration(source, gettype(source, getbasetype(source, 0))); + if (lhs) return lhs; if (flags & ~(QINFER | QCONST)) { - error("invalid use of qualifiers"); + error(getloc(source), "invalid use of qualifiers"); flags = flags & (QINFER | QCONST); } if (flags) { - lhs = atom(flags); + lhs = atom(source, flags); return lhs; } /* actual atom */ - switch (tok.kind) { + switch (getkind(source)) { case '(': #if 0 - gettok(false); - skipnewline(); - lhs = exprlist(false, NULL), lastis = savedis; + gettok(source, false); + skipnewline(source); + lhs = exprlist(source, false, NULL), source->lastis = savedis; if (lhs->kind == 'T') { /* NOTE(m21c): expecting that the type is also set in lhs->type */ lhs->kind = OCAST; - skipnewline(); - expect(')', true, "expected ')'"); + skipnewline(source); + expect(source, ')', true, "expected ')'"); - lhs->lhs = atom(0); + lhs->lhs = atom(source, 0); break; } - skipnewline(); - expect(')', true, "expected ')'"); + skipnewline(source); + expect(source, ')', true, "expected ')'"); #else - gettok(false); - if (tok.kind == '\n') { - lhs = stmtlist(lastindent, SSCOPE), lastis = savedis; + gettok(source, false); + if (getkind(source) == '\n') { + lhs = stmtlist(source, source->lastindent, SSCOPE); + source->lastis = savedis; } else { - lhs = exprlist(false, NULL), lastis = savedis; + lhs = exprlist(source, false, NULL); + source->lastis = savedis; + if (lhs->kind == 'T') { /* NOTE(m21c): expecting that the type is also set in lhs->type */ lhs->kind = OCAST; - skipnewline(); - expect(')', true, "expected ')'"); + skipnewline(source); + expect(source, ')', true, "expected ')'"); - lhs->lhs = atom(0); + lhs->lhs = atom(source, 0); break; } - skipnewline(); + skipnewline(source); } - expect(')', true, "expected ')'"); + expect(source, ')', true, "expected ')'"); #endif break; case 'I': - lhs = makenode(NULL); - lhs->u.declref = finddeclaration(tok.u.key); + lhs = makenode(&source->tok, NULL); + lhs->u.declref = finddeclaration( + source->currenv, + source->tok.u.key + ); if (lhs->u.declref) { lhs->kind = ADECLREF; lhs->type = lhs->u.declref->type; } else { - Env *funcenv = getfuncenv(); + Env *funcenv = getfuncenv(source); if (funcenv) { if (!funcenv->pending) { funcenv->pending = true; - if (!pendingenvhead) { - pendingenvtail = funcenv; - pendingenvhead = funcenv; + if (!source->pendingenvhead) { + source->pendingenvtail = funcenv; + source->pendingenvhead = funcenv; } else { - pendingenvtail->pendingnext = funcenv; - funcenv->pendingprev = pendingenvtail; - pendingenvtail = funcenv; + source->pendingenvtail->pendingnext = funcenv; + funcenv->pendingprev = source->pendingenvtail; + source->pendingenvtail = funcenv; } } } else { - error("'%s' undeclared", getstring(idents, tok.u.key)); + error( + getloc(source), + "'%s' undeclared", + getstring(idents, source->tok.u.key) + ); } - lhs->u.key = tok.u.key; + lhs->u.key = source->tok.u.key; } - gettok(true); + gettok(source, true); if (flags & QCONST) { /* TODO(m21c): const - conversion */ @@ -1880,162 +2026,176 @@ atom(int flags) { case 'N': case 'S': case 'C': - lhs = makenode(NULL); - gettok(true); + lhs = makenode(&source->tok, NULL); + gettok(source, true); if (flags & QCONST) { /* TODO(m21c): const - conversion */ } break; case KNOT: - lhs = makenode(NULL); - gettok(false); + lhs = makenode(&source->tok, NULL); + gettok(source, false); lhs->kind = OLNOT; - lhs->lhs = expr(PRELAT); + lhs->lhs = expr(source, PRELAT); break; case KBREAK: case KCONTINUE: - lhs = makenode(NULL); - lhs->kind = tok.kind == KBREAK ? ABREAK : ACONTINUE; - gettok(true); - if (tok.kind == ':') { - gettok(false); - skipnewline(); - if (tok.kind == 'I') { - lhs->lhs = makenode(NULL); - gettok(false); + lhs = makenode(&source->tok, NULL); + lhs->kind = getkind(source) == KBREAK ? ABREAK : ACONTINUE; + gettok(source, true); + if (getkind(source) == ':') { + gettok(source, false); + skipnewline(source); + if (getkind(source) == 'I') { + lhs->lhs = makenode(&source->tok, NULL); + gettok(source, false); } else { - error("expected identifier"); + error(getloc(source), "expected identifier"); } } break; case KRETURN: - lhs = makenode(NULL); - gettok(true); + lhs = makenode(&source->tok, NULL); + gettok(source, true); lhs->kind = ARETURN; - if (tok.kind == ':') { - gettok(false); - skipnewline(); - if (tok.kind == 'I') { - lhs->lhs = makenode(NULL); - gettok(false); + if (getkind(source) == ':') { + gettok(source, false); + skipnewline(source); + if (getkind(source) == 'I') { + lhs->lhs = makenode(&source->tok, NULL); + gettok(source, false); } else { - error("expected identifier"); + error(getloc(source), "expected identifier"); } } - if (isatom()) - lhs->rhs = exprlist(false, NULL); + if (isatom(source)) + lhs->rhs = exprlist(source, false, NULL); break; case KDO: - indent = lastindent; - lhs = makenode(NULL); - gettok(false); + indent = source->lastindent; + lhs = makenode(&source->tok, NULL); + gettok(source, false); lhs->kind = ADO; - lhs->lhs = stmtlist(indent, SSCOPE); + lhs->lhs = stmtlist(source, indent, SSCOPE); break; case KLOOP: - indent = lastindent; - lhs = makenode(NULL); - gettok(false); + indent = source->lastindent; + lhs = makenode(&source->tok, NULL); + gettok(source, false); lhs->kind = ALOOP; - lhs->lhs = stmtlist(indent, SSCOPE); + lhs->lhs = stmtlist(source, indent, SSCOPE); - if (tok.kind == KUNTIL && lastindent >= indent) { + if (getkind(source) == KUNTIL && source->lastindent >= indent) { lhs->kind = ALOOPUNTIL; - gettok(false); - lhs->u.payload = expr(POR); + gettok(source, false); + lhs->u.payload = expr(source, POR); } if (lhs->kind != ALOOP) goto joinelse; else break; case KWHILE: - indent = lastindent; - lhs = makenode(NULL); - gettok(false); + indent = source->lastindent; + lhs = makenode(&source->tok, NULL); + gettok(source, false); lhs->kind = AWHILE; - lhs->u.payload = expr(POR); - lhs->lhs = stmtlist(indent, SSCOPE); + lhs->u.payload = expr(source, POR); + lhs->lhs = stmtlist(source, indent, SSCOPE); goto joinelse; case KIF: - indent = lastindent; - lhs = makenode(NULL); - gettok(false); + indent = source->lastindent; + lhs = makenode(&source->tok, NULL); + gettok(source, false); lhs->kind = AIF; - lhs->u.payload = expr(POR); - skipnewline(); - if (tok.kind == 'I' && tok.u.key == auxthen) - gettok(false); - lhs->lhs = stmtlist(indent, SSCOPE); + lhs->u.payload = expr(source, POR); + skipnewline(source); + if (getkind(source) == 'I' && source->tok.u.key == auxthen) + gettok(source, false); + lhs->lhs = stmtlist(source, indent, SSCOPE); joinelse: - if (tok.kind == KELSE && lastindent >= indent) { - gettok(false); - lhs->rhs = stmtlist(indent, SSCOPE); + if (getkind(source) == KELSE && source->lastindent >= indent) { + gettok(source, false); + lhs->rhs = stmtlist(source, indent, SSCOPE); } break; default: joinerror: - error("expected expression"); - lhs = makenode(NULL); - gettok(true); + error(getloc(source), "expected expression"); + lhs = makenode(&source->tok, NULL); + gettok(source, true); } /* unary postfix operators */ - while (getprec(tok.kind) == PUNSUF) { - lhs = makenode(lhs); - if (tok.kind == ODISP) { - gettok(false); - skipnewline(); - if (tok.kind != 'I') - error("expected identifier"); - lhs->rhs = makenode(NULL); - } else if (tok.kind == OCALL) { - gettok(false); - if (tok.kind != ')') - lhs->rhs = exprlist(false, NULL), lastis = savedis; - expect(')', true, "expected ')'"); + while (getprec(getkind(source)) == PUNSUF) { + lhs = makenode(&source->tok, lhs); + + if (getkind(source) == ODISP) { + gettok(source, false); + skipnewline(source); + + if (getkind(source) != 'I') + error(getloc(source), "expected identifier"); + + lhs->rhs = makenode(&source->tok, NULL); + } else if (getkind(source) == OCALL) { + gettok(source, false); + + if (getkind(source) != ')') { + lhs->rhs = exprlist(source, false, NULL); + source->lastis = savedis; + } + + expect(source, ')', true, "expected ')'"); continue; - } else if (tok.kind == OARRAY) { - gettok(false); - lhs->rhs = exprlist(false, NULL), lastis = savedis; - expect(']', true, "expected ']'"); + } else if (getkind(source) == OARRAY) { + gettok(source, false); + + lhs->rhs = exprlist(source, false, NULL); + source->lastis = savedis; + + expect(source, ']', true, "expected ']'"); continue; } - gettok(true); + gettok(source, true); } /* 'not'-suffix for the binary 'is'-operator (i.e. 'is not') */ - while (tok.kind == KIS) { - lhs = makenode(lhs); - gettok(false); + while (getkind(source) == KIS) { + lhs = makenode(&source->tok, lhs); + gettok(source, false); lhs->kind = 'O'; - if (tok.kind == KNOT) - gettok(false), lhs->kind = ONEQ; + if (getkind(source) == KNOT) + gettok(source, false), lhs->kind = ONEQ; else lhs->kind = OEQU; - lastis = lhs; - lhs->rhs = expr(PRELAT); + source->lastis = lhs; + lhs->rhs = expr(source, PRELAT); } return lhs; } Node * -expr(int minprec) { - Node *lhs = atom(0), *last = NULL; +expr(Source *source, int minprec) { + Node *lhs = atom(source, 0), *last = NULL; /* only binary expr */ - while (getprec(tok.kind) >= minprec) { - lhs = makenode(lhs); - gettok(false); - skipnewline(); - lhs->rhs = expr(getprec(lhs->kind) + !israssoc(lhs->kind)); + while (getprec(getkind(source)) >= minprec) { + lhs = makenode(&source->tok, lhs); + gettok(source, false); + skipnewline(source); + + lhs->rhs = expr( + source, + getprec(lhs->kind) + !israssoc(lhs->kind) + ); switch (getprec(lhs->kind)) { case PRELAT: if (last) { - lhs = makenode(lhs); + lhs = makenode(&source->tok, lhs); lhs->rhs = lhs->lhs; lhs->kind = OLAND; @@ -2060,7 +2220,7 @@ Node * todeclaration(Node *curr, Node **ty) { if (*ty) { if (curr->kind == 'I') { - Node *decl = makenode(*ty); + Node *decl = makenode(curr, *ty); curr->kind = ADECL; decl->rhs = curr; curr = decl; @@ -2082,20 +2242,20 @@ todeclaration(Node *curr, Node **ty) { } Node * -exprlist(bool isparam, Type *paramtype) { +exprlist(Source *source, bool isparam, Type *paramtype) { Node *head, *tail; bool isdeclaration, typetuple; /* tail = todeclaration(tail, &paramtype); */ - if (paramtype && tok.kind == 'I') { - head = declaration(paramtype), tail = head; + if (paramtype && getkind(source) == 'I') { + head = declaration(source, paramtype), tail = head; } else { - head = expr(PSTART), tail = head; + head = expr(source, PSTART), tail = head; } if (isparam && tail->kind != ADECL) - error("expected declaration"); + error(getloc(source), "expected declaration"); if ((isdeclaration = tail->kind == ADECL)) { paramtype = tail->type; @@ -2103,22 +2263,22 @@ exprlist(bool isparam, Type *paramtype) { typetuple = tail->kind == 'T'; - while (tok.kind == ',') { + while (getkind(source) == ',') { Node *curr; - gettok(false); + gettok(source, false); - if (tok.kind == 'I' && isdeclaration) { + if (getkind(source) == 'I' && isdeclaration) { assert(paramtype); - curr = declaration(paramtype); + curr = declaration(source, paramtype); typetuple = false; } else { - curr = expr(PSTART); + curr = expr(source, PSTART); typetuple &= curr->kind == 'T'; /* curr = todeclaration(curr, &paramtype); */ } if ((paramtype || isparam) && curr->kind != ADECL) - error("expected declaration"); + error(getloc(source), "expected declaration"); if (curr->kind == ADECL) { paramtype = curr->type; @@ -2130,7 +2290,7 @@ exprlist(bool isparam, Type *paramtype) { tail = tail->next; } - lastis = NULL; + source->lastis = NULL; return head; } @@ -2271,7 +2431,7 @@ autoref(Type *ty, Node *node) #endif for (i = 0; i < numderefs; ++i) { - n = makenode(node); + n = makenode(node, node); n->type = node->type->target; n->kind = ADEREF; /* dereference */ node = n; @@ -2282,14 +2442,14 @@ autoref(Type *ty, Node *node) *t = prim[TPTR]; t->target = node->type; - n = makenode(node); + n = makenode(node, node); n->type = t; n->kind = AADDR; /* address-of */ node = n; /* TODO(m21c): Check for lvalue */ } else if (numderefs < -1) { - error("double referencing"); + error(&node->loc, "double referencing"); /* TODO(m21c): ERROR: double referencing */ return node; } @@ -2312,30 +2472,45 @@ wrap(Type *ty, Node *node) { if (node->kind == 'N') { /* TODO(m21c): layout correct type-conversions ? */ if (isfloattype(node->type)) { - if (isfloattype(ty)) - node->u.d = maskfloat(ty->size, node->u.d); - else if (isinttype(ty)) - node->u.u = maskint(ty->size, (int64_t) node->u.d); + if (isfloattype(ty)) { + node->u.d = maskfloat( + ty->size, + node->u.d + ); + } else if (isinttype(ty)) { + node->u.u = maskint( + ty->size, + (int64_t) node->u.d + ); + } } else if (isinttype(node->type)) { if (isfloattype(ty)) { - node->u.d = maskfloat(ty->size, (double) + node->u.d = maskfloat( + ty->size, (double) (int64_t) convint(node->type->size, !isunsignedtype(node->type), - node->u.u)); + node->u.u + ) + ); } else if (isinttype(ty)) { - node->u.u = maskint(ty->size, - convint(node->type->size, + node->u.u = maskint( + ty->size, + convint( + node->type->size, !isunsignedtype(node->type), - node->u.u)); + node->u.u + ) + ); } } + node->type = ty; return node; } node = autoref(ty, node); - node = makenode(node); + node = makenode(node, node); node->kind = ACONV; node->type = ty; relinknodes(node, node->lhs); @@ -2356,7 +2531,7 @@ conv(Node *node) { } Node * -typecheck(Node *expr) { +typecheck(Env *env, Node *expr) { Node *c; for (c = expr; c; c = c->next) { @@ -2382,11 +2557,11 @@ typecheck(Node *expr) { break; case OPLUS: case OMINUS: - lhs = typecheck(lhs); + lhs = typecheck(env, lhs); /* if (!isarithtype(lhs->type)) { - error("expression is not of arithmentic type"); + error(&lhs->loc, "expression is not of arithmentic type"); c->type = prim + TERRTYPE; break; } @@ -2397,10 +2572,14 @@ typecheck(Node *expr) { break; case OBNOT: - lhs = typecheck(lhs); + lhs = typecheck(env, lhs); if (!isinttype(lhs->type)) { - error("expression is not of integer type"); + error( + &lhs->loc, + "expression is not of integer type" + ); + c->type = prim + TERRTYPE; break; } @@ -2410,10 +2589,14 @@ typecheck(Node *expr) { break; case OLNOT: - lhs = typecheck(lhs); + lhs = typecheck(env, lhs); if (!isarithtype(lhs->type)) { - error("expression is not of arithmentic type"); + error( + &lhs->loc, + "expression is not of arithmentic type" + ); + c->type = prim + TERRTYPE; break; } @@ -2433,8 +2616,8 @@ typecheck(Node *expr) { case OMUL: case ODIV: case OMOD: case OADD: case OSUB: - lhs = typecheck(lhs); - rhs = typecheck(rhs); + lhs = typecheck(env, lhs); + rhs = typecheck(env, rhs); /* usual arithmetic conversion */ if (isarithtype(lhs->type) && isarithtype(rhs->type)) { @@ -2443,7 +2626,11 @@ typecheck(Node *expr) { else c->type = lhs->type; } else { - error("expression is not of arithmentic type"); + error( + &c->loc, + "expression is not of arithmentic type" + ); + c->type = prim + TERRTYPE; break; } @@ -2453,8 +2640,8 @@ typecheck(Node *expr) { break; case OBAND: case OBOR: case OXOR: - lhs = typecheck(lhs); - rhs = typecheck(rhs); + lhs = typecheck(env, lhs); + rhs = typecheck(env, rhs); if (isinttype(lhs->type) && isinttype(rhs->type)) { if (lhs->type->kind < rhs->type->kind) { @@ -2463,7 +2650,11 @@ typecheck(Node *expr) { c->type = lhs->type; } } else { - error("expression is not of integer type"); + error( + &c->loc, + "expression is not of integer type" + ); + c->type = prim + TERRTYPE; } @@ -2472,13 +2663,17 @@ typecheck(Node *expr) { break; case OLSH: case ORSH: case OARSH: - lhs = typecheck(lhs); - rhs = typecheck(rhs); + lhs = typecheck(env, lhs); + rhs = typecheck(env, rhs); if (isinttype(lhs->type) && isinttype(rhs->type)) { c->type = lhs->type; } else { - error("expression is not of integer type"); + error( + &c->loc, + "expression is not of integer type" + ); + c->type = prim + TERRTYPE; } @@ -2489,13 +2684,17 @@ typecheck(Node *expr) { case OEQU: case ONEQ: case OLET: case OLEQ: case OGRT: case OGEQ: - lhs = typecheck(lhs); - rhs = typecheck(rhs); + lhs = typecheck(env, lhs); + rhs = typecheck(env, rhs); if (isarithtype(lhs->type) && isarithtype(rhs->type)) { c->type = prim + TBOOL; } else { - error("expression is not of integer type"); + error( + &c->loc, + "expression is not of integer type" + ); + c->type = prim + TERRTYPE; } @@ -2504,13 +2703,17 @@ typecheck(Node *expr) { break; case OLAND: case OLOR: - lhs = typecheck(lhs); - rhs = typecheck(rhs); + lhs = typecheck(env, lhs); + rhs = typecheck(env, rhs); if (isarithtype(lhs->type) && isarithtype(rhs->type)) { c->type = prim + TBOOL; } else { - error("expression is not of integer type"); + error( + &c->loc, + "expression is not of integer type" + ); + c->type = prim + TERRTYPE; } @@ -2524,8 +2727,8 @@ typecheck(Node *expr) { case OADDA: case OSUBA: case OANDA: case OORA: case OXORA: - lhs = typecheck(lhs); - rhs = typecheck(rhs); + lhs = typecheck(env, lhs); + rhs = typecheck(env, rhs); switch ((int) c->kind) { case OASS: @@ -2533,20 +2736,32 @@ typecheck(Node *expr) { break; case OMULA: case ODIVA: case OMODA: case OADDA: case OSUBA: - if (isarithtype(lhs->type) && isarithtype(rhs->type)) { + if (isarithtype(lhs->type) && + isarithtype(rhs->type)) + { c->type = lhs->type; } else { - error("expression is not of arithmetic type"); + error( + &c->loc, + "expression is not of arithmetic type" + ); + c->type = prim + TERRTYPE; } break; case OLSHA: case ORSHA: case OARSHA: case OANDA: case OORA: case OXORA: - if (isinttype(lhs->type) && isinttype(rhs->type)) { + if (isinttype(lhs->type) && + isinttype(rhs->type)) + { c->type = lhs->type; } else { - error("expression is not of integer type"); + error( + &c->loc, + "expression is not of integer type" + ); + c->type = prim + TERRTYPE; } break; @@ -2558,23 +2773,21 @@ typecheck(Node *expr) { case ADECL: if (c->lhs) - c->lhs = wrap(c->type, typecheck(c->lhs)); + c->lhs = wrap(c->type, typecheck(env, c->lhs)); break; case ASCOPE: assert(c->lhs); assert(c->u.env); - currenv = c->u.env; - c->lhs = typecheck(c->lhs); + c->lhs = typecheck(c->u.env, c->lhs); - currenv = currenv->below; break; case AADDR: case ADEREF: assert(c->lhs); - c->lhs = typecheck(c->lhs); + c->lhs = typecheck(env, c->lhs); c->lhs = conv(c->lhs); break; @@ -2587,7 +2800,7 @@ typecheck(Node *expr) { } Node * -foldexpr(Node *expr) { +foldexpr(Env *env, Node *expr) { Node *c; #define evalbinary(op) do { \ @@ -2617,23 +2830,27 @@ foldexpr(Node *expr) { * will behave properly for non-operator nodes too */ switch (getnumops(c->kind)) { case 2: - rhs = foldexpr(rhs); + rhs = foldexpr(env, rhs); case 1: - lhs = foldexpr(lhs); + lhs = foldexpr(env, lhs); } switch ((int) c->kind) { case IDENT: do { - Decl *declref = finddeclaration(c->u.key); + Decl *declref = finddeclaration(env, c->u.key); if (declref) { c->kind = ADECLREF; c->u.declref = declref; c->type = declref->type; - } else if (currenv->kind != STOPLEVEL) { + } else if (env->kind != STOPLEVEL) { /* TODO(m21c): recreate Env-stack after parsing-pass */ - error("'%s' undeclared", getstring(idents, c->u.key)); + error( + &c->loc, + "'%s' undeclared", + getstring(idents, c->u.key) + ); } } while (0); break; @@ -2660,12 +2877,16 @@ foldexpr(Node *expr) { if (c->kind == OMUL) { evalbinary(*); } else { - if (rhs->u.u == 0 && isinttype(ty)) - error("division by zero"); - else if (c->kind == ODIV) + if (rhs->u.u == 0 && isinttype(ty)) { + error( + &c->loc, + "division by zero" + ); + } else if (c->kind == ODIV) { evalbinary(/); - else + } else { evalbinary(/); /* TODO(m21c): implement modulus for float-types */ + } } } else if (isvalue(lhs, 0)) { *c = *lhs; @@ -2675,7 +2896,7 @@ foldexpr(Node *expr) { /* delete(lhs); delete(rhs) */ } else if (isvalue(rhs, 0)) { if (rhs->u.u == 0 && isinttype(ty)) - error("division by zero"); + error(&c->loc, "division by zero"); *c = *rhs; /* delete(lhs); delete(rhs) */ } else if (isvalue(lhs, 1)) { @@ -2708,8 +2929,16 @@ foldexpr(Node *expr) { break; case OBAND: case OBOR: case OXOR: if (lhs->kind == 'N' && rhs->kind == 'N') { - assert(isinttype(lhs->type) || lhs->type->kind == TBOOL); - assert(isinttype(rhs->type) || rhs->type->kind == TBOOL); + assert( + isinttype(lhs->type) || + lhs->type->kind == TBOOL + ); + + assert( + isinttype(rhs->type) || + rhs->type->kind == TBOOL + ); + lhs->u.u = maskint(ty->size, lhs->u.u); rhs->u.u = maskint(ty->size, rhs->u.u); if (c->kind == OBAND) @@ -2724,7 +2953,7 @@ foldexpr(Node *expr) { break; case ACONV: /* TODO(m21c): implement this properly! */ - lhs = foldexpr(lhs); + lhs = foldexpr(env, lhs); if (lhs->type->kind == c->type->kind) *c = *lhs /*, delete(lhs) */; } @@ -3226,6 +3455,10 @@ printexpr(FILE *out, Node *expr, int indent) { int main(int argc, char **argv) { Env *p; + + Source *source = &testsource; + source->tabwidth = 8; + initkeywords(); initstrmap(&idents); initstrmap(&strings); @@ -3233,37 +3466,39 @@ main(int argc, char **argv) { auxthen = getstringkey(&idents, "then", 4); if (argc >= 2) { - filein = fopen(argv[1], "rb"); - filename = argv[1]; - assert(filein); + source->filein = fopen(argv[1], "rb"); + source->currloc.filename = argv[1]; + source->tok.loc.filename = argv[1]; + assert(source->filein); } else { - filein = stdin; - filename = "<stdin>"; + source->filein = stdin; + source->currloc.filename = "<stdin>"; + source->tok.loc.filename = "<stdin>"; highlight(stdout, HLPROMPT); printf("> "); highlight(stdout, HLNONE); - handlereplprompt = false; + source->handlereplprompt = false; } - gettok(false); - if (tok.kind == '\n') - gettok(false); + gettok(source, false); + if (getkind(source) == '\n') + gettok(source, false); - pushenv(STOPLEVEL); - while (tok.kind != 0) { + pushenv(source, STOPLEVEL); + while (getkind(source) != 0) { /* printf("token:%i:%i: %c '%.*s'\n", lastline, lastcol + 1, tok.u.id, currcol - lastcol, line + lastcol);*/ Node *ast; - ast = exprlist(false, NULL); + ast = exprlist(source, false, NULL); /* printast(ast, 0); printf("\n"); */ if (ast->kind != ADECL || !ast->u.payload || ast->u.payload->kind != ASCOPE) - ast = foldexpr(typecheck(ast)); + ast = foldexpr(source->currenv, typecheck(source->currenv, ast)); - if (filein == stdin) { + if (source->filein == stdin) { highlight(stdout, HLINFO); fputs("= ", stdout); highlight(stdout, HLNONE); @@ -3272,7 +3507,7 @@ main(int argc, char **argv) { printexpr(stdout, ast, 0); highlight(stdout, HLNONE); - if (filein == stdin) { + if (source->filein == stdin) { highlight(stdout, HLINFO); fputs(" : ", stdout); printtype(stdout, ast->type, 0); @@ -3281,43 +3516,43 @@ main(int argc, char **argv) { printf("\n"); - if (tok.kind == '\n') { - if (filein == stdin) { + if (getkind(source) == '\n') { + if (source->filein == stdin) { highlight(stdout, HLPROMPT); printf("> "); highlight(stdout, HLNONE); - handlereplprompt = false; + source->handlereplprompt = false; } - gettok(false); - } else if (tok.kind == ';') { - gettok(false); + gettok(source, false); + } else if (getkind(source) == ';') { + gettok(source, false); } - if (lastkind != ';' && lastkind != '\n') { - error("expected new line"); - while (tok.kind != ';' && tok.kind != '\n' && tok.kind != 0) - gettok(false); + if (source->lastkind != ';' && source->lastkind != '\n') { + error(getloc(source), "expected new line"); + while (getkind(source) != ';' && getkind(source) != '\n' && getkind(source) != 0) + gettok(source, false); - if (filein == stdin) { + if (source->filein == stdin) { highlight(stdout, HLPROMPT); printf("> "); highlight(stdout, HLNONE); - handlereplprompt = false; + source->handlereplprompt = false; } - if (tok.kind != 0) - gettok(false); + if (getkind(source) != 0) + gettok(source, false); } } - for (p = pendingenvhead; p; p = p->pendingnext) { + for (p = source->pendingenvhead; p; p = p->pendingnext) { if (p->stmts) - p->stmts = foldexpr(typecheck(p->stmts)); + p->stmts = foldexpr(source->currenv, typecheck(source->currenv, p->stmts)); } - popenv(); + popenv(source); - /* fclose(filein); */ + /* fclose(source->filein); */ /* disposestrmap(&strings); */ /* disposestrmap(&idents); */ }