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:
| M | aria.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, ¶mtype); */
- 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, ¶mtype); */
}
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); */
}