Aria

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

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+
Maria.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();