commit b1543447c96b23e112eee21abfaa132d942ad272
parent abe9dca122aaec0f6bb88a80b5733f46c06da088
Author: m21c <ho*******@gmail.com>
Date: Thu, 8 Jul 2021 23:25:44 +0200
worked on primitive types + typechecking
Diffstat:
| M | .gitignore | | | 1 | + |
| M | aria.c | | | 866 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------- |
2 files changed, 683 insertions(+), 184 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,6 +1,7 @@
.oldcode/*
.vscode/*
bin/*
+spec/*
test/*
debug*.cmd
diff --git a/aria.c b/aria.c
@@ -71,42 +71,44 @@ struct Env Env;
/* - type struct - */
-enum {
- TVOID = 1, TBOOL,
+typedef enum {
+ TERRTYPE = 1, TDUMMY,
+
+ TVOID, TBOOL, TINFER, TUINFER,
- TU8, TS8, TU16, TS16, TU32, TS32, TU64, TS64,
+ TS8, TU8, TS16, TU16, TS32, TU32, TS64, TU64,
TF32, TF64,
TPTR, TARRAY,
TMAX
-};
+} TypeKind;
-#define TUCHAR TU8
#define TCHAR TS8
-#define TUSHORT TU16
+#define TUCHAR TU8
#define TSHORT TS16
-#define TUINT TU32
+#define TUSHORT TU16
#define TINT TS32
-#define TULONG TU64
+#define TUINT TU32
#define TLONG TS64
-#define TULLONG TU64
+#define TULONG TU64
#define TLLONG TS64
+#define TULLONG TU64
#define TFLOAT TF32
#define TDOUBLE TF64
#define TLDOUBLE TF64
-#define TUSIZE TU64
#define TSSIZE TS64
+#define TUSIZE TU64
/* TODO(m21c): maybe add long double type ? */
typedef
struct Type Type;
struct Type {
- int kind;
+ TypeKind kind;
size_t size, align;
@@ -125,20 +127,30 @@ struct Type {
};
Type prim[] = {
- [TVOID] = {TVOID, 0, 0, {0}, NULL},
- [TBOOL] = {TBOOL, 1, 1, {0}, NULL},
-
- [TU8] = {TU8, 1, 1, {0}, NULL},
- [TS8] = {TS8, 1, 1, {0}, NULL},
- [TU16] = {TU16, 2, 2, {0}, NULL},
- [TS16] = {TS16, 2, 2, {0}, NULL},
- [TU32] = {TU32, 4, 4, {0}, NULL},
- [TS32] = {TS32, 4, 4, {0}, NULL},
- [TU64] = {TU64, 8, 8, {0}, NULL},
- [TS64] = {TS64, 8, 8, {0}, NULL},
-
- [TF32] = {TF32, 4, 4, {0}, NULL},
- [TF64] = {TF64, 8, 8, {0}, NULL},
+ [TERRTYPE] = {TERRTYPE, 0, 0, {0}, NULL},
+ [TDUMMY] = {TDUMMY, 0, 0, {0}, NULL},
+
+ [TVOID] = {TVOID, 0, 0, {0}, NULL},
+
+ [TBOOL] = {TBOOL, 1, 1, {0}, NULL},
+
+ [TINFER] = {TINFER, 4, 4, {0}, NULL},
+ [TUINFER] = {TUINFER, 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},
+
+ [TF32] = {TF32, 4, 4, {0}, NULL},
+ [TF64] = {TF64, 8, 8, {0}, NULL},
+
+ [TPTR] = {TPTR, 8, 8, {0}, NULL},
+ [TARRAY] = {TARRAY, 0, 0, {0}, NULL},
};
Type typebuf[4096];
@@ -227,8 +239,9 @@ enum {
typedef enum Kind {
ANNOT = '@',
- SEMIDELIM = ';', COMMADELIM = ',', COLONDELIM = ':', LCURLDELIM = '{',
- RCURLDELIM = ']', RSQRDELIM = ']', RPARDELIM = ')',
+ SEMIDELIM = ';', COMMADELIM = ',', COLONDELIM = ':',
+ LCURLDELIM = '{', /*LSQRDELIM = '[',*/ LPARDELIM = '(',
+ RCURLDELIM = '}', RSQRDELIM = ']', RPARDELIM = ')',
CHAR = 'C',
IDENT = 'I',
NUMBER = 'N',
@@ -253,7 +266,7 @@ typedef enum Kind {
/* Operators */
OSUFINC, OSUFDEC, OARRAY, OCALL, ODISP,
- ODEREF, OINC, ODEC, OBNOT, OLNOT, OFLIP, OADDR, OPLUS, OMINUS, OCAST,
+ OLPTR, OINC, ODEC, OBNOT, OLNOT, OFLIP, /*ORPTR,*/ OPLUS, OMINUS, OCAST,
OMUL, ODIV, OMOD, OLSH, OARSH, ORSH, OBAND,
OADD, OSUB, OBOR, OXOR,
ORANGE,
@@ -268,6 +281,7 @@ typedef enum Kind {
ASTMT, ADO, ADECL, ADECLREF, ALOOP, ALOOPUNTIL, AWHILE, AFOR, ACONTINUE,
ABREAK, ASCOPE, ARETURN, AGOTO, ALABEL, AIF, ASWITCH, ACASE,
ACONV,
+ ADEREF, AADDR,
MAXKINDS
} Kind;
@@ -358,10 +372,10 @@ const char *nodestrings[] = {
[OSUFINC] = "++", [OSUFDEC] = "--",
[OARRAY] = "[]", [OCALL] = "()",
[ODISP] = ".",
- [ODEREF] = "*", [OINC] = "++",
+ [OLPTR] = "*", [OINC] = "++",
[ODEC] = "--", [OBNOT] = "~",
[OLNOT] = "!", [OFLIP] = "~=",
- [OADDR] = "&", [OPLUS] = "+",
+ /*[ORPTR] = "&",*/ [OPLUS] = "+",
[OMINUS] = "-", [OCAST] = "(type)",
[OMUL] = "*", [ODIV] = "/",
[OMOD] = "%", [OLSH] = "<<",
@@ -419,13 +433,13 @@ const uint8_t opinfo[] = {
[OCALL] = opentry(1, false, PUNSUF),
[ODISP] = opentry(1, false, PUNSUF),
- [ODEREF] = opentry(1, true, PUNARY),
+ [OLPTR] = opentry(1, true, PUNARY),
[OINC] = opentry(1, true, PUNARY),
[ODEC] = opentry(1, true, PUNARY),
[OBNOT] = opentry(1, true, PUNARY),
[OLNOT] = opentry(1, true, PUNARY),
[OFLIP] = opentry(1, true, PUNARY),
- [OADDR] = opentry(1, true, PUNARY),
+ /*[ORPTR] = opentry(1, true, PUNARY),*/
[OPLUS] = opentry(1, true, PUNARY),
[OMINUS] = opentry(1, true, PUNARY),
[OCAST] = opentry(1, true, PUNARY),
@@ -636,7 +650,7 @@ getstringkey(StringMap *map, const char *str, int n) {
map->valscap = cap;
}
- newstr = calloc(n + 1, sizeof (char*));
+ newstr = calloc(n + 1, sizeof(char*));
assert(newstr);
memcpy(newstr, str, n);
@@ -744,7 +758,7 @@ skipwhite:
}
}
- tok.type = prim;
+ tok.type = prim + TERRTYPE;
tok.u.u = 0;
tok.lhs = NULL;
tok.rhs = NULL;
@@ -856,7 +870,7 @@ skipwhite:
}
}
} else {
- int typeid = TINT - TUINT;
+ int typeid = TUINT - TINT;
if (mystrncasecmp(stringbuf, "0b", 2) == 0) {
tok.u.u = strtoull(stringbuf + 2, &end, 2);
@@ -866,39 +880,39 @@ skipwhite:
switch (*end) {
case 0:
- typeid = TINT;
+ typeid = TINFER;
break;
- case 'u': case 'U':
- typeid = 0;
case 's': case 'S':
case 'i': case 'I':
+ typeid = 0;
+ case 'u': case 'U':
++end;
if (*end == 0) {
- typeid += TUINT;
+ typeid += TINFER;
break;
} else if (*end == '8') {
- typeid += TU8;
+ typeid += TS8;
if (end[1])
goto errorint;
break;
} else if (!strcmp(end, "16")) {
- typeid += TU16;
+ typeid += TS16;
break;
} else if (!strcmp(end, "32")) {
- typeid += TU32;
+ typeid += TS32;
break;
} else if (!strcmp(end, "64")) {
- typeid += TU64;
+ typeid += TS64;
break;
} else if (!mystrcasecmp(end, "sz")) {
- typeid += TUSIZE;
+ typeid += TSSIZE;
break;
}
default:
if (!mystrcasecmp(end, "ll")) {
- typeid += TULLONG;
+ typeid += TLLONG;
} else if (*end == 'l' || *end == 'L') {
- typeid += TULONG;
+ typeid += TLONG;
if (end[1])
goto errorint;
} else {
@@ -998,7 +1012,7 @@ skipwhite:
tok.kind = ODISP;
goto joinop;
case '*':
- tok.kind = select('=', OMULA, (haslhs ? OMUL : ODEREF));
+ tok.kind = select('=', OMULA, (haslhs ? OMUL : OLPTR));
goto joinop;
case '/':
tok.kind = select('=', ODIVA, ODIV);
@@ -1022,7 +1036,7 @@ skipwhite:
goto joinop;
case '&':
tok.kind = select('=', OANDA, select('&', OLAND,
- (haslhs ? OBAND : OADDR)));
+ /*(haslhs ? OBAND : ORPTR)*/ OBAND));
goto joinop;
case '+':
tok.kind = select('=', OADDA, select('+',
@@ -1132,7 +1146,7 @@ finddeclinenv(int key, Env *env) {
Decl *decl;
- if (env->keycache[cacheindex] & cachebit == 0)
+ if ((env->keycache[cacheindex] & cachebit) == 0)
return NULL;
for (decl = env->head; decl; decl = decl->next) {
@@ -1189,7 +1203,19 @@ finddeclaration(int key) {
for (env = currenv; env; env = env->below) {
Decl *decl;
- if (currenv->keycache[cacheindex] & cachebit == 0)
+ /* NOTE(m21c): look-up exclusion list first.
+ * If found: only lookup in found env */
+ /* FIXME(m21c): make a separate list, and not use excludehead,
+ * excludenext ! */
+ /*
+ for (decl = env->excludehead; decl; decl = decl->excludenext) {
+ if (decl->key == key)
+ return finddeclinenv(key, env);
+ }
+ */
+
+
+ if ((env->keycache[cacheindex] & cachebit) == 0)
continue;
for (decl = env->head; decl; decl = decl->next) {
@@ -1546,7 +1572,7 @@ advance:
goto advance;
}
- if (tok.kind == ODEREF) {
+ if (tok.kind == OLPTR) {
Type *tmp = maketype();
tmp->kind = TPTR;
tmp->target = ty, ty = tmp;
@@ -1626,7 +1652,7 @@ declaration(Node *typenode) {
bool
isatom(void) {
- switch (tok.kind) {
+ switch ((int) tok.kind) {
case 0:
case '\n': case ';':
case ',': case ':':
@@ -2085,10 +2111,11 @@ exprlist(bool isparam, Node *paramtype) {
bool
isinttype(Type *ty) {
switch (ty->kind) {
- case TU8: case TS8:
- case TU16: case TS16:
- case TU32: case TS32:
- case TU64: case TS64:
+ case TINFER: case TUINFER:
+ case TS8: case TU8:
+ case TS16: case TU16:
+ case TS32: case TU32:
+ case TS64: case TU64:
return true;
default:
return false;
@@ -2108,11 +2135,13 @@ isfloattype(Type *ty) {
bool
isarithtype(Type *ty) {
switch (ty->kind) {
- case TU8: case TS8:
- case TU16: case TS16:
- case TU32: case TS32:
- case TU64: case TS64:
- case TF32: case TF64:
+ case TBOOL:
+ case TINFER: case TUINFER:
+ case TS8: case TU8:
+ case TS16: case TU16:
+ case TS32: case TU32:
+ case TS64: case TU64:
+ case TF32: case TF64:
return true;
default:
return false;
@@ -2122,8 +2151,9 @@ isarithtype(Type *ty) {
bool
isunsignedtype(Type *ty) {
switch (ty->kind) {
- case TU8: case TU16:
- case TU32: case TU64:
+ case TBOOL: case TUINFER:
+ case TU8: case TU16:
+ case TU32: case TU64:
return true;
default:
return false;
@@ -2154,14 +2184,99 @@ convint(int srcsize, bool srcsigned, uint64_t value) {
return value;
}
+void
+relinknodes(Node *dst, Node *src) {
+ if (src->next) {
+ dst->next = src->next;
+ dst->next->prev = dst;
+ src->next = NULL;
+ }
+
+ if (src->prev) {
+ dst->prev = src->prev;
+ dst->prev->next = dst;
+ src->prev = NULL;
+ }
+}
+
Node *
-conv(Node *node) {
+conv(Node *node);
+
+Node *
+autoref(Type *ty, Node *node)
+{
+ int numderefs = 0, i;
+ Node *n;
+ Type *t;
+
+ for (n = node; n && n->kind == OLPTR; n = n->lhs) {
+ --numderefs;
+
+ /*
+ node->lhs = NULL;
+ deletenode(node);
+ */
+
+ assert(n->lhs);
+ node = n->lhs;
+ }
+
+ assert(node != NULL);
+
+ printf("numderefs[1]: %i\n", numderefs);
+
+ for (t = node->type; t && t->kind == TPTR; t = t->target)
+ ++numderefs;
+
+ printf("numderefs[2]: %i\n", numderefs);
+
+ for (t = ty; t && t->kind == TPTR; t = t->target)
+ --numderefs;
+
+ printf("numderefs[3]: %i\n", numderefs);
+
+#if 0
+ if (numderefs)
+ node = conv(node);
+#endif
+
+ for (i = 0; i < numderefs; ++i) {
+ n = makenode(node);
+ n->type = node->type->target;
+ n->kind = ADEREF; /* dereference */
+ node = n;
+ }
+
+ if (numderefs == -1) {
+ t = maketype();
+ *t = prim[TPTR];
+ t->target = node->type;
+
+ n = makenode(node);
+ n->type = t;
+ n->kind = AADDR; /* address-of */
+ node = n;
+
+ /* TODO(m21c): Check for lvalue */
+ } else if (numderefs < -1) {
+ error("double referencing");
+ /* TODO(m21c): ERROR: double referencing */
+ return node;
+ }
+
+ if (ty && numderefs) {
+ /* TODO(m21c): Check for type-compatability and for ptr-types */
+ }
+
return node;
}
Node *
wrap(Type *ty, Node *node) {
- if (node->type && ty->kind == node->type->kind)
+ assert(ty);
+ assert(node->type);
+
+ if (ty->kind == node->type->kind)
return node;
if (node->kind == 'N') {
@@ -2188,12 +2303,30 @@ wrap(Type *ty, Node *node) {
return node;
}
+ node = autoref(ty, node);
+
node = makenode(node);
node->kind = ACONV;
node->type = ty;
+ relinknodes(node, node->lhs);
return node;
}
+Node *
+conv(Node *node) {
+ Type *ty = node->type;
+
+ assert(ty);
+
+ if (ty->kind == TINFER)
+ return wrap(prim + TINT, node);
+ if (ty->kind == TUINFER)
+ return wrap(prim + TUINT, node);
+ return autoref(NULL, node);
+}
+
+#if 0
+
typedef
Node *(*RuleFunc)(Node *expr);
@@ -2234,11 +2367,15 @@ binaryarithrule(Node *binary) {
else
tt = lhs->type;
} else {
- tt = prim + TVOID;
+ error("expression is not of arithmentic type");
+ binary->type = prim + TVOID;
+ return binary;
}
lhs = wrap(tt, lhs);
rhs = wrap(tt, rhs);
+ binary->lhs = lhs;
+ binary->rhs = rhs;
binary->type = tt;
#define evalbinary(op) do { \
@@ -2310,20 +2447,118 @@ binaryarithrule(Node *binary) {
/* delete(lhs); delete(rhs) */
}
}
+ #undef evalbinary
+ #undef isvalue
- binary->lhs = lhs;
- binary->rhs = rhs;
return binary;
}
Node *
unaryarithrule(Node *unary) {
+ Node *lhs = unary->lhs;
+ Type *tt;
+
+ if (!lhs) return unary;
+
+ lhs = foldexpr(lhs);
+
+ /* usual arithmetic conversion */
+ if (!isarithtype(lhs->type)) {
+ error("expression is not of arithmentic type");
+ unary->type = prim + TVOID;
+ return unary;
+ }
+
+ lhs = conv(lhs);
+ unary->lhs = lhs;
+ unary->type = tt = lhs->type;
+
+ switch (unary->kind) {
+ case OPLUS:
+ *unary = *lhs;
+ /* delete(lhs) */
+ break;
+ case OMINUS:
+ if (lhs->kind == 'N') {
+ if (isfloattype(tt)) {
+ unary->kind = 'N';
+ unary->u.d = maskfloat(tt->size, -lhs->u.d);
+ /* delete(lhs) */
+ } else if (isinttype(tt)) {
+ unary->kind = 'N';
+ unary->u.u = maskint(tt->size, -lhs->u.u);
+ /* delete(lhs) */
+ }
+ } else if (lhs->kind == OMINUS && lhs->lhs) {
+ *unary = *lhs->lhs;
+ /* delete(lhs) */
+ }
+ break;
+ default:;
+ }
+
+ return unary;
+}
+
+Node *
+unarybitwiserule(Node *unary) {
+ Node *lhs = unary->lhs;
+ Type *tt;
+
+ if (!lhs) return unary;
+
+ lhs = foldexpr(lhs);
+
+ /* usual arithmetic conversion */
+ if (!isarithtype(lhs->type)) {
+ error("expression is not of arithmentic type");
+ unary->type = prim + TVOID;
+ return unary;
+ }
+
+ lhs = conv(lhs);
+ unary->lhs = lhs;
+ unary->type = tt = lhs->type;
+
+ switch (unary->kind) {
+ case OPLUS:
+ *unary = *lhs;
+ /* delete(lhs) */
+ break;
+ case OMINUS:
+ if (lhs->kind == 'N') {
+ if (isfloattype(tt)) {
+ unary->kind = 'N';
+ unary->u.d = maskfloat(tt->size, -lhs->u.d);
+ /* delete(lhs) */
+ } else if (isinttype(tt)) {
+ unary->kind = 'N';
+ unary->u.u = maskint(tt->size, -lhs->u.u);
+ /* delete(lhs) */
+ }
+ } else if (lhs->kind == OMINUS && lhs->lhs) {
+ *unary = *lhs->lhs;
+ /* delete(lhs) */
+ }
+ break;
+ default:;
+ }
+
return unary;
}
RuleFunc ruletable[] = {
['I'] = &identrule,
+ /* TODO(m21c): on inc/dec operations: check for lvalue */
+ [OSUFINC] = &unaryarithrule,
+ [OSUFDEC] = &unaryarithrule,
+ [OINC] = &unaryarithrule,
+ [ODEC] = &unaryarithrule,
+
+ [OPLUS] = &unaryarithrule,
+ [OMINUS] = &unaryarithrule,
+
[OMUL] = &binaryarithrule,
[ODIV] = &binaryarithrule,
[OMOD] = &binaryarithrule,
@@ -2333,146 +2568,383 @@ RuleFunc ruletable[] = {
[MAXKINDS] = NULL
};
-#if 0
+#endif
-RuleFunc opfunctable[] = {
- [OSUFINC] = &emptyrule, [OSUFDEC] = &emptyrule,
- [OARRAY] = &emptyrule, [OCALL] = &emptyrule,
- [ODISP] = &emptyrule,
+Node *
+typecheck(Node *expr) {
+ Node *c;
- [ODEREF] = &emptyrule,
- [OINC] = &emptyrule, [ODEC] = &emptyrule,
- [OBNOT] = &emptyrule, [OLNOT] = &emptyrule,
- [OFLIP] = &emptyrule,
- [OADDR] = &emptyrule,
- [OPLUS] = &emptyrule, [OMINUS] = &emptyrule,
- [OCAST] = &emptyrule,
+ for (c = expr; c; c = c->next) {
+ Node *lhs = c->lhs, *rhs = c->rhs;
+
+ switch (getnumops(c->kind)) {
+ case 2:
+ assert(rhs);
+ if (rhs->type->kind == TERRTYPE)
+ c->type = prim + TERRTYPE;
+ case 1:
+ assert(lhs);
+ if (lhs->type->kind == TERRTYPE)
+ c->type = prim + TERRTYPE;
+ }
- [OMUL] = &emptyrule, [ODIV] = &emptyrule, [OMOD] = &emptyrule,
- [OLSH] = &emptyrule, [OARSH] = &emptyrule, [ORSH] = &emptyrule,
- [OBAND] = &emptyrule,
+ if (c->type && c->type->kind == TERRTYPE)
+ continue;
- [OADD] = &emptyrule, [OSUB] = &emptyrule,
- [OBOR] = &emptyrule, [OXOR] = &emptyrule,
+ switch (c->kind) {
+ case OLPTR:
+ c->type = c->lhs->type;
+ break;
- [ORANGE] = &emptyrule,
+ case OPLUS: case OMINUS:
+ lhs = typecheck(lhs);
- [OLEQ] = &emptyrule, [OLET] = &emptyrule,
- [OGEQ] = &emptyrule, [OGRT] = &emptyrule,
- [ONEQ] = &emptyrule, [OEQU] = &emptyrule,
- [OIDENT] = &emptyrule,
+ /*
+ if (!isarithtype(lhs->type)) {
+ error("expression is not of arithmentic type");
+ c->type = prim + TERRTYPE;
+ break;
+ }
+ */
- [OLAND] = &emptyrule,
+ c->type = lhs->type;
+ c->lhs = conv(lhs);
+ break;
- [OLOR] = &emptyrule,
+ case OBNOT:
+ lhs = typecheck(lhs);
- [OASS] = &emptyrule,
+ if (!isinttype(lhs->type)) {
+ error("expression is not of integer type");
+ c->type = prim + TERRTYPE;
+ break;
+ }
- [OMULA] = &emptyrule, [ODIVA] = &emptyrule, [OMODA] = &emptyrule,
- [OLSHA] = &emptyrule, [OARSHA] = &emptyrule, [ORSHA] = &emptyrule,
- [OANDA] = &emptyrule,
- [OADDA] = &emptyrule, [OSUBA] = &emptyrule,
- [OORA] = &emptyrule, [OXORA] = &emptyrule,
-};
+ c->type = lhs->type;
+ c->lhs = conv(lhs);
+ break;
-Node *
-oprules(Node *expr) {
- return opfunctable[expr->u.id](expr);
-}
+ case OLNOT:
+ lhs = typecheck(lhs);
-RuleFunc astfunctable[] = {
- [ASTMT] = &emptyrule,
- [ADO] = &emptyrule,
- [ADECL] = &emptyrule,
- [ADECLREF] = &emptyrule,
- [ALOOP] = &emptyrule,
- [ALOOPUNTIL] = &emptyrule,
- [AWHILE] = &emptyrule,
- [AFOR] = &emptyrule,
- [ACONTINUE] = &emptyrule,
- [ABREAK] = &emptyrule,
- [ASCOPE] = &emptyrule,
- [ARETURN] = &emptyrule,
- [AGOTO] = &emptyrule,
- [ALABEL] = &emptyrule,
- [AIF] = &emptyrule,
- [ASWITCH] = &emptyrule,
- [ACASE] = &emptyrule
-};
+ if (!isarithtype(lhs->type)) {
+ error("expression is not of arithmentic type");
+ c->type = prim + TERRTYPE;
+ break;
+ }
-Node *
-astrules(Node *expr) {
- return astfunctable[expr->u.id](expr);
-}
+ c->type = prim + TBOOL;
+ c->lhs = conv(lhs);
+ break;
-#endif
+ case OCAST:
+ /*
+ assert(rhs);
+ assert(lhs->kind == 'T');
+ */
-Node *
-foldexpr(Node *expr) {
- Node *c, *n;
+ /* c->type = c->lhs->type; */
+ break;
- for (c = expr; c; c = c->next) {
-#if 0
- if (c->kind == ADECL)
- continue;
+ case OMUL: case ODIV: case OMOD:
+ case OADD: case OSUB:
+ lhs = typecheck(lhs);
+ rhs = typecheck(rhs);
- if (c->kind == 'I') {
- Decl *declref = finddeclaration(c->u.key);
- if (declref) {
- c->kind = ADECLREF;
- c->u.declref = declref;
+ /* usual arithmetic conversion */
+ if (isarithtype(lhs->type) && isarithtype(rhs->type)) {
+ if (lhs->type->kind < rhs->type->kind)
+ c->type = rhs->type;
+ else
+ c->type = lhs->type;
} else {
- error("'%s' undeclared", getstring(idents, c->u.key));
+ error("expression is not of arithmentic type");
+ c->type = prim + TERRTYPE;
+ break;
}
- continue;
- }
- if (c->kind == AIF && c->u.payload) {
- c->u.payload = foldexpr(c->u.payload);
- }
+ c->lhs = wrap(c->type, lhs);
+ c->rhs = wrap(c->type, rhs);
+ break;
+
+ case OBAND: case OBOR: case OXOR:
+ lhs = typecheck(lhs);
+ rhs = typecheck(rhs);
+
+ if (isinttype(lhs->type) && isinttype(rhs->type)) {
+ if (lhs->type->kind < rhs->type->kind) {
+ c->type = rhs->type;
+ } else {
+ c->type = lhs->type;
+ }
+ } else {
+ error("expression is not of integer type");
+ c->type = prim + TERRTYPE;
+ }
- if (c->lhs)
- c->lhs = foldexpr(c->lhs);
- if (c->rhs)
- c->rhs = foldexpr(c->rhs);
-#elif 1
- if (ruletable[c->kind]) {
- n = ruletable[c->kind](c);
-
- if (n != c) {
- n->prev = c->prev;
- n->next = c->next;
- /* deletenode(c) */
- c = n;
+ c->lhs = wrap(c->type, lhs);
+ c->rhs = wrap(c->type, rhs);
+ break;
+
+ case OLSH: case ORSH: case OARSH:
+ lhs = typecheck(lhs);
+ rhs = typecheck(rhs);
+
+ if (isinttype(lhs->type) && isinttype(rhs->type)) {
+ c->type = lhs->type;
+ } else {
+ error("expression is not of integer type");
+ c->type = prim + TERRTYPE;
}
- }
-#else
- Node *lhs, *rhs;
- Type *lt, *lt, *tt;
- #define convertbinaryarith() \
- lhs = foldexpr(c->lhs); \
- rhs = foldexpr(c->rhs); \
- tt = usualarithconv(lhs->type, rhs->type); \
- lhs = wrap(tt, lhs); \
- rhs = wrap(tt, rhs); \
- c->type = tt
+ c->lhs = wrap(c->type, lhs); /* this should be unneeded */
+ c->rhs = wrap(c->type, rhs);
+ break;
+ case OEQU: case ONEQ:
+ case OLET: case OLEQ:
+ case OGRT: case OGEQ:
+ lhs = typecheck(lhs);
+ rhs = typecheck(rhs);
- switch (c->kind) {
- case OMUL: case ODIV: case OMOD:
- case OADD: case OSUB:
- convertbinaryarith();
+ if (isarithtype(lhs->type) && isarithtype(rhs->type)) {
+ c->type = prim + TBOOL;
+ } else {
+ error("expression is not of integer type");
+ c->type = prim + TERRTYPE;
+ }
+
+ c->lhs = conv(lhs);
+ c->rhs = conv(rhs);
+ break;
+
+ case OLAND: case OLOR:
+ lhs = typecheck(lhs);
+ rhs = typecheck(rhs);
+
+ if (isarithtype(lhs->type) && isarithtype(rhs->type)) {
+ c->type = prim + TBOOL;
+ } else {
+ error("expression is not of integer type");
+ c->type = prim + TERRTYPE;
+ }
+
+ c->lhs = conv(lhs);
+ c->rhs = conv(rhs);
+ break;
+
+ case OASS:
+ case OMULA: case ODIVA: case OMODA:
+ case OLSHA: case ORSHA: case OARSHA:
+ case OADDA: case OSUBA:
+ case OANDA:
+ case OORA: case OXORA:
+ lhs = typecheck(lhs);
+ rhs = typecheck(rhs);
+
+ switch ((int) c->kind) {
+ case OASS:
+ c->type = lhs->type;
+ break;
+ case OMULA: case ODIVA: case OMODA:
+ case OADDA: case OSUBA:
+ if (isarithtype(lhs->type) && isarithtype(rhs->type)) {
+ c->type = lhs->type;
+ } else {
+ error("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)) {
+ c->type = lhs->type;
+ } else {
+ error("expression is not of integer type");
+ c->type = prim + TERRTYPE;
+ }
+ break;
+ }
+
+ c->lhs = conv(lhs);
+ c->rhs = wrap(c->type, rhs);
break;
+
+ case ADECL:
+ assert(rhs);
+ assert(lhs);
+
+ c->type = lhs->type;
+
+ if (c->u.payload)
+ c->u.payload = wrap(c->type, typecheck(c->u.payload));
+ break;
+
+ case ASCOPE:
+ assert(c->lhs);
+ assert(c->u.env);
+ currenv = c->u.env;
+
+ c->lhs = typecheck(c->lhs);
+
+ currenv = currenv->below;
+ break;
+
+ case AADDR:
+ case ADEREF:
+ assert(c->lhs);
+ c->lhs = typecheck(c->lhs);
+ c->lhs = conv(c->lhs);
+ break;
+
default:
break;
}
-#endif
}
return expr;
}
+Node *
+foldexpr(Node *expr) {
+ Node *c;
+
+ #define evalbinary(op) do { \
+ c->kind = 'N'; \
+ if (isfloattype(ty)) \
+ c->u.d = maskfloat(ty->size, \
+ maskfloat(ty->size, lhs->u.d) op \
+ maskfloat(ty->size, rhs->u.d) \
+ ); \
+ else if (isinttype(ty)) \
+ c->u.u = maskint(ty->size, \
+ maskint(ty->size, lhs->u.u) op \
+ maskint(ty->size, rhs->u.u) \
+ ); \
+ /* delete(lhs); delete(rhs) */ \
+ } while (0)
+
+ #define isvalue(expr, value) (expr->kind == 'N' && \
+ ((expr->u.u == value && isinttype(ty)) || \
+ (expr->u.d == value && isarithtype(ty))))
+
+ for (c = expr; c; c = c->next) {
+ Node *lhs = c->lhs, *rhs = c->rhs;
+ Type *ty = c->type;
+
+ switch (getnumops(c->kind)) {
+ case 2:
+ rhs = foldexpr(rhs);
+ case 1:
+ lhs = foldexpr(lhs);
+ }
+
+ switch ((int) c->kind) {
+ case IDENT:
+ do {
+ Decl *declref = finddeclaration(c->u.key);
+
+ if (declref) {
+ c->kind = ADECLREF;
+ c->u.declref = declref;
+ c->type = declref->type;
+ } else if (currenv->kind != STOPLEVEL) {
+ /* TODO(m21c): recreate Env-stack after parsing-pass */
+ error("'%s' undeclared", getstring(idents, c->u.key));
+ }
+ } while (0);
+ break;
+ case OADD: case OSUB:
+ if (lhs->kind == 'N' && rhs->kind == 'N') {
+ if (c->kind == OADD) evalbinary(+);
+ else evalbinary(-);
+ } else if (isvalue(lhs, 0)) {
+ if (c->kind == OADD) {
+ *c = *rhs;
+ /* delete(lhs); delete(rhs) */
+ } else {
+ c->kind = OMINUS;
+ c->lhs = rhs;
+ /* delete(lhs) */
+ }
+ } else if (isvalue(rhs, 0)) {
+ *c = *lhs;
+ /* delete(lhs); delete(rhs) */
+ }
+ break;
+ case OMUL: case ODIV: case OMOD:
+ if (lhs->kind == 'N' && rhs->kind == 'N') {
+ if (c->kind == OMUL) {
+ evalbinary(*);
+ } else {
+ if (rhs->u.u == 0 && isinttype(ty))
+ error("division by zero");
+ else if (c->kind == ODIV)
+ evalbinary(/);
+ else
+ evalbinary(/); /* TODO(m21c): implement modulus for float-types */
+ }
+ } else if (isvalue(lhs, 0)) {
+ *c = *lhs;
+ /* delete(lhs); delete(rhs) */
+ } else if (c->kind == OMUL && isvalue(rhs, 0)) {
+ *c = *rhs;
+ /* delete(lhs); delete(rhs) */
+ } else if (isvalue(rhs, 0)) {
+ if (rhs->u.u == 0 && isinttype(ty))
+ error("division by zero");
+ *c = *rhs;
+ /* delete(lhs); delete(rhs) */
+ } else if (isvalue(lhs, 1)) {
+ *c = *rhs;
+ /* delete(lhs); delete(rhs) */
+ } else if (c->kind == OMUL && isvalue(rhs, 1)) {
+ *c = *lhs;
+ /* delete(lhs); delete(rhs) */
+ }
+ break;
+ case OPLUS:
+ *c = *lhs;
+ /* delete(lhs) */
+ break;
+ case OMINUS:
+ if (lhs->kind == 'N') {
+ if (isfloattype(ty)) {
+ c->kind = 'N';
+ c->u.d = maskfloat(ty->size, -lhs->u.d);
+ /* delete(lhs) */
+ } else if (isinttype(ty)) {
+ c->kind = 'N';
+ c->u.u = maskint(ty->size, -lhs->u.u);
+ /* delete(lhs) */
+ }
+ } else if (lhs->kind == OMINUS && lhs->lhs) {
+ *c = *lhs->lhs;
+ /* delete(lhs) */
+ }
+ 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);
+ lhs->u.u = maskint(ty->size, lhs->u.u);
+ rhs->u.u = maskint(ty->size, rhs->u.u);
+ if (c->kind == OBAND)
+ c->u.u = lhs->u.u & rhs->u.u;
+ else if (c->kind == OBOR)
+ c->u.u = lhs->u.u | rhs->u.u;
+ else
+ c->u.u = lhs->u.u ^ rhs->u.u;
+ c->kind = 'N';
+ c->u.u = maskint(ty->size, c->u.u);
+ }
+ break;
+ }
+ }
+ return expr;
+}
+
/* - print ast */
int
@@ -2494,13 +2966,16 @@ int printtype(FILE *out, Type *type, int indent) {
break;
#define typecase(type, str) \
case type: n += fprintf(out, str); break
- typecase(TPTR, "*");
- typecase(TVOID, "void"); typecase(TBOOL, "bool");
- typecase(TU8, "u8" ); typecase(TS8, "s8" );
- typecase(TU16, "u16" ); typecase(TS16, "s16" );
- typecase(TU32, "u32" ); typecase(TS32, "s32" );
- typecase(TU64, "u64" ); typecase(TS64, "s64" );
- typecase(TF32, "f32" ); typecase(TF64, "f64" );
+ typecase(TERRTYPE, "<error-type>");
+ typecase(TDUMMY, "<not-implemented>");
+ typecase(TPTR, "*");
+ typecase(TVOID, "void" ); typecase(TBOOL, "bool" );
+ typecase(TINFER, "i" ); typecase(TUINFER, "u" );
+ typecase(TS8, "s8" ); typecase(TU8, "u8" );
+ typecase(TS16, "s16" ); typecase(TU16, "u16" );
+ typecase(TS32, "s32" ); typecase(TU32, "u32" );
+ typecase(TS64, "s64" ); typecase(TU64, "u64" );
+ typecase(TF32, "f32" ); typecase(TF64, "f64" );
#undef typecase
default:;
}
@@ -2587,7 +3062,7 @@ printoperant(FILE *out, Node *expr, int opprec, bool braceequalprec, int indent)
if (expr->next || (
!isatomnode(expr->kind) && (
!getnumops(expr->kind) || prec < opprec ||
- (braceequalprec && prec == prec)
+ (braceequalprec && prec == opprec)
)
)
) {
@@ -2638,8 +3113,17 @@ printexpr(FILE *out, Node *expr, int indent) {
} else {
switch (c->kind) {
case OCAST:
+ putc('(', out), ++n;
+ n += printtype(out, c->type, indent);
+ putc(')', out), ++n;
+ break;
default:
n += fprintf(out, "%s", nodestrings[c->kind]);
+ if (getprec(c->lhs->kind) == PUNARY &&
+ c->kind != OLPTR)
+ {
+ putc(' ', out), ++n;
+ }
}
n += printoperant(out, c->lhs, PUNARY, false, indent);
}
@@ -2717,6 +3201,16 @@ printexpr(FILE *out, Node *expr, int indent) {
n += fprintf(out, ") ");
n += printoperant(out, c->lhs, PUNARY, false, indent);
break;
+ case AADDR:
+ n += fputs("&{", out);
+ n += printoperant(out, c->lhs, PUNARY, false, indent);
+ n += fputs("}", out);
+ break;
+ case ADEREF:
+ n += fputs("*{", out);
+ n += printoperant(out, c->lhs, PUNARY, false, indent);
+ n += fputs("}", out);
+ break;
default:
break;
}
@@ -2767,8 +3261,12 @@ main(int argc, char **argv) {
printf("\n");
*/
if (ast->kind != ADECL || !ast->u.payload || ast->u.payload->kind != ASCOPE)
- ast = foldexpr(ast);
+ ast = foldexpr(typecheck(ast));
printexpr(stdout, ast, 0);
+ if (filein == stdin) {
+ fputs(" : ", stdout);
+ printtype(stdout, ast->type, 0);
+ }
printf("\n");
@@ -2793,7 +3291,7 @@ main(int argc, char **argv) {
for (p = pendingenvhead; p; p = p->pendingnext) {
if (p->stmts)
- p->stmts = foldexpr(p->stmts);
+ p->stmts = foldexpr(typecheck(p->stmts));
}
popenv();