commit b927e23f373b60c35a1282d31595be9a96d6133d
parent 5f57a40e5cd965c1ac9d9378c78189f6270b8604
Author: m21c <ho*******@gmail.com>
Date: Mon, 20 Apr 2026 21:11:32 +0200
worked on processing record fields + folding sizeof/alignof operators
Diffstat:
| M | compiler.c | | | 234 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- |
1 file changed, 228 insertions(+), 6 deletions(-)
diff --git a/compiler.c b/compiler.c
@@ -529,13 +529,23 @@ struct Type {
Decl *module; /* module and record info */
};
-typedef struct Field {
- Decl *fielddecl;
+typedef struct Field Field;
+
+typedef struct Record {
+ Field *head, *tail;
+
+ bool isunion;
+} Record;
+
+struct Field {
+ Decl *decl;
size_t offset, size; /* in bytes */
bool use;
-} Field;
+
+ Field *prev, *next;
+};
struct Decl {
DeclKind kind;
@@ -543,6 +553,7 @@ struct Decl {
Type *type;
Decl *module; /* module or bundle */
+ Record *record;
int key;
DeclFlags flags;
@@ -2426,6 +2437,53 @@ defertypedeclaration(Source *source, int key)
// }}}
+// @section record {{{
+
+Record recordbuf[4096];
+int recordtop;
+
+static Record *
+makerecord(Decl *recorddecl)
+{
+ Record *record;
+
+ assert(recordtop < lengthof(recordbuf));
+ record = recordbuf + recordtop++;
+ record->head = record->tail = NULL;
+
+ recorddecl->record = record;
+
+ assert(recorddecl->type);
+ record->isunion = recorddecl->type->kind == TUNION;
+
+ return record;
+}
+
+Field fieldbuf[4096 * 16];
+int fieldtop;
+
+static Field *
+makefield(Record *record, Decl *decl)
+{
+ Field *field;
+
+ assert(fieldtop < lengthof(fieldbuf));
+ field = fieldbuf + fieldtop++;
+ field->decl = decl;
+ field->offset = field->size = 0;
+ field->use = false;
+ field->prev = field->next = NULL;
+
+ assert(record);
+ listappend(record, field);
+
+ return field;
+}
+
+
+
+// }}}
+
// @section parser {{{
#define getkind(source) \
@@ -3108,11 +3166,75 @@ readident(Source *source, int flags)
return lhs;
}
+static void
+extractfields(Record *record, Node *recordscope)
+{
+ Node *stmt;
+
+ for (stmt = recordscope->lhs; stmt; stmt = stmt->rhs) {
+ Node *expr;
+
+ assert(stmt->kind == ASTMT);
+
+ expr = stmt->lhs;
+
+ /* @fixme expr might be validly NULL */
+ assert(expr);
+
+ if (expr->kind == ACOMMA) {
+ for (; expr; expr = expr->lhs) {
+ Node *nested;
+
+ if (expr->kind == ADECL)
+ makefield(record, expr->u.declref);
+
+ if (expr->kind != ACOMMA)
+ break;
+
+ nested = expr->rhs;
+
+ if (nested->kind != ADECL)
+ continue;
+
+ makefield(record, nested->u.declref);
+ }
+ continue;
+ }
+ if (expr->kind != ADECL)
+ continue;
+
+ makefield(record, expr->u.declref);
+ }
+}
+
+static void
+calculatefields(Record *record, Type *recordtype)
+{
+ Field *field;
+
+ for (field = record->head; field; field = field->next) {
+ size_t mod = 0, padding;
+ Type *type;
+
+ type = field->decl->type;
+
+ if (recordtype->align < type->align)
+ recordtype->align = type->align;
+
+ if (recordtype->align)
+ mod = recordtype->size % recordtype->align;
+
+ padding = mod ? recordtype->align - mod : 0;
+ recordtype->size += padding + type->size;
+ }
+}
+
static Node *
readrecord(Source *source, bool isunion)
{
Node *recordnode;
Decl *module;
+ Record *record;
int indent = source->lastindent;
EnvKind envkind = SSTRUCT;
@@ -3161,9 +3283,17 @@ readrecord(Source *source, bool isunion)
module->contentenv = recordnode->rhs->u.env;
}
+ record = makerecord(module);
+
/* TODO(m21c): validate record body, extract declarations,
* compute size and align, resolve aliases */
+ if (recordnode->rhs) {
+ assert(recordnode->rhs->kind == ASCOPE);
+ extractfields(record, recordnode->rhs);
+ }
+
+ calculatefields(record, recordnode->type);
return recordnode;
}
@@ -3234,6 +3364,17 @@ readrecordinitfieldlist(Source *source, Type *recordtype)
}
static Node *
+finishcontrolflow(Source *source, Node *lhs, int indent)
+{
+ if (skipnewlineontok(source, KELSE, indent)) {
+ gettok(source);
+ lhs->rhs = stmtlist(source, indent, SELSE, NULL, false);
+ }
+
+ return wrapenv(lhs, popenv(source));
+}
+
+static Node *
readatom(Source *source, int flags)
{
Node *lhs = NULL, *savedis = source->lastis;
@@ -3484,6 +3625,8 @@ readatom(Source *source, int flags)
goto joinelse;
/* skip postfix-operators */
+ // return finishcontrolflow(source, lhs, indent);
+
return wrapenv(lhs, popenv(source));
case KFOR:
@@ -3537,6 +3680,7 @@ readatom(Source *source, int flags)
/* @todo maybe use SFOR instead of SLOOP */
lhs->lhs = stmtlist(source, indent, SLOOP, NULL, false);
goto joinelse;
+ return finishcontrolflow(source, lhs, indent);
case KWHILE:
indent = source->lastindent;
@@ -3546,6 +3690,7 @@ readatom(Source *source, int flags)
lhs->u.payload = readexpr(source, POR);
lhs->lhs = stmtlist(source, indent, SWHILE, NULL, false);
goto joinelse;
+ return finishcontrolflow(source, lhs, indent);
case KIF:
indent = source->lastindent;
@@ -3564,6 +3709,7 @@ readatom(Source *source, int flags)
gettok(source);
lhs->rhs = stmtlist(source, indent, SELSE, NULL, false);
}
+ return finishcontrolflow(source, lhs, indent);
/* skip postfix-operators */
return wrapenv(lhs, popenv(source));
@@ -4865,6 +5011,32 @@ typecheck(Env *env, Node *expr)
}
static Node *
+foldexpr(Env *env, Node *expr);
+
+static Node *
+folddeclaration(Env *env, Node *expr)
+{
+ Decl *decl = expr->u.declref;
+
+ assert(decl);
+
+ if (decl->kind == DFUNCTION) {
+ if (decl->u.content)
+ /* @todo make sure the correct env is used */
+ decl->u.content = foldexpr(env, decl->u.content);
+
+ } else if (decl->kind == DPARAM || decl->kind == DVAR) {
+
+ /* @todo remove condition. it is only for testing structs.
+ * content may not be NULL otherwise (needs validation) */
+ if (decl->u.content)
+ decl->u.content = foldexpr(env, decl->u.content);
+ }
+
+ return expr;
+}
+
+static Node *
foldexpr(Env *env, Node *expr)
{
Node *lhs = expr->lhs, *rhs = expr->rhs;
@@ -5058,6 +5230,8 @@ foldexpr(Env *env, Node *expr)
}
deletenode(lhs);
+ /* @todo delete type */
+ expr->type = prim + TUSIZE;
expr->kind = NUMBER;
return expr;
@@ -5069,6 +5243,9 @@ foldexpr(Env *env, Node *expr)
return expr;
+ case ADECL:
+ return folddeclaration(env, expr);
+
case TYPE:
error(&expr->loc, "exptected expression, not type");
/* FALLTHROUGH */
@@ -5446,7 +5623,6 @@ fetchblocks(Block *block, Node *expr)
}
}
-
#if 0
static void
debugprintconduct(Conduct *conduct, int indent);
@@ -5637,6 +5813,7 @@ advance:
case KUNTIL:
case AFORSTEP:
case AFOREACH:
+ case ALOOPUNTIL:
if (expr->u.payload)
extractnfs(env, expr->u.payload);
if (expr->lhs)
@@ -5697,6 +5874,16 @@ advance:
extractnfs(env, expr->rhs);
break;
+ case KBREAK:
+ case KCONTINUE:
+ case KGOTO:
+ break;
+
+ case KSIZEOF:
+ case KALIGNOF:
+ /* @todo check for nested functions and report error */
+ break;
+
default:
error(&expr->loc, "internal error: unknown expression kind"
" (%s).", nodestrings[expr->kind]);
@@ -5777,6 +5964,12 @@ cginit(CodeGen *cg, Env *toplevel, FILE *out)
cgprintf(cg, "#include <stdlib.h>\n");
cgprintf(cg, "#include <string.h>\n");
+ cgprintf(cg, "typedef int16_t s16;\n");
+ cgprintf(cg, "typedef uint16_t u16;\n");
+ cgprintf(cg, "typedef unsigned int uint;\n");
+ cgprintf(cg, "typedef int64_t s64;\n");
+ cgprintf(cg, "typedef uint64_t u64;\n");
+
cgprintf(cg, "\n");
}
@@ -6265,7 +6458,6 @@ codegen(CodeGen *cg, Node *expr)
case ADECLREF:
cgdeclname(cg, expr->u.declref);
break;
- case ALOOPUNTIL:
case ALABEL:
case ASWITCH:
case ACASE:
@@ -6509,10 +6701,40 @@ codegen(CodeGen *cg, Node *expr)
cgprintf(cg, ")");
break;
case AFOREACH:
+ break;
+ case KLOOP:
+ cgprintf(cg, "for (;;) ");
+ if (expr->lhs)
+ cgprintclause(cg, expr->lhs);
+ /* @todo implement else-case properly? */
+ /* @note else-clause might be useless for an infinite loop */
+ /*
+ if (expr->rhs) {
+ cgprintf(cg, " else ");
+ cgprintclause(cg, expr->rhs);
+ }
+ */
+ cgprintf(cg, "\n");
+ break;
+ case ALOOPUNTIL:
+ cgprintf(cg, "do ");
+ if (expr->lhs)
+ cgprintclause(cg, expr->lhs);
+ cgprintf(cg, " while (!(");
+ if (expr->u.payload)
+ codegen(cg, expr->u.payload);
+ cgprintf(cg, "));\n");
+ /* @todo implement else-case properly */
+ /*
+ if (expr->rhs) {
+ cgprintf(cg, " else ");
+ cgprintclause(cg, expr->rhs);
+ }
+ */
+ break;
case KCASE:
case KOF:
case KDO:
- case KLOOP:
case KUNTIL:
/* @todo implement c version correctly */
break;