ref: 84977e24ad1f367840d132c50b89d090a275ecbc
parent: f089efb927e64fab733dc62d3e5627c832269cef
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Fri Aug 7 05:13:00 EDT 2015
Emit function types before emiting functions Function types are needed when a function is called, because the ABI for a function like f(...) can be different to the ABI for f(int), even in the case the receives only one parameter. This change emits parameters after emiting the function, so we can keep the storage specifier of the parameters and free P for pointers.
--- a/cc1/cc1.h
+++ b/cc1/cc1.h
@@ -51,6 +51,7 @@
TFLOAT f;
char *s;
unsigned char token;
+ Symbol **pars;
} u;
struct symbol *next;
struct symbol *hash;
@@ -108,6 +109,7 @@
FTN = 1,
PTR,
ARY,
+ PARS,
};
/* namespaces */
@@ -129,10 +131,9 @@
ISREGISTER = 8,
ISDEFINED = 16,
ISFIELD = 32,
- ISPARAM = 64,
- ISEXTERN = 128,
- ISUSED = 256,
- ISCONSTANT = 512
+ ISEXTERN = 64,
+ ISUSED = 128,
+ ISCONSTANT = 256
};
--- a/cc1/code.c
+++ b/cc1/code.c
@@ -147,6 +147,7 @@
(*opcode[op])(op, arg);
}
+/* TODO: move these letters to cc.h */
static void
emitvar(Symbol *sym)
{
@@ -157,11 +158,9 @@
else if (sym->flags & ISGLOBAL)
c = 'G';
else if (sym->flags & ISREGISTER)
- c = 'K';
+ c = 'R';
else if (sym->flags & ISFIELD)
c = 'M';
- else if (sym->flags & ISPARAM)
- c = 'P';
else
c = 'A';
printf("%c%d", c, sym->id);
@@ -204,13 +203,21 @@
emitletter(Type *tp)
{
putchar(tp->letter);
- if (tp->op == ARY)
+ switch (tp->op) {
+ case ARY:
+ case FTN:
+ case STRUCT:
+ case UNION:
printf("%d", tp->id);
+ }
}
static void
emittype(Type *tp)
{
+ int n;
+ Type **vp;
+
if (tp->printed)
return;
@@ -217,7 +224,8 @@
switch (tp->op) {
case ARY:
emittype(tp->type);
- printf("V%d\t", tp->id);
+ emitletter(tp);
+ putchar('\t');
emitletter(tp->type);
printf("\t#%d\n", tp->n.elem);
return;
@@ -224,6 +232,15 @@
case PTR:
emittype(tp->type);
return;
+ case FTN:
+ emitletter(tp);
+ n = tp->n.elem;
+ for (vp = tp->pars; n-- > 0; ++vp) {
+ putchar('\t');
+ emitletter(*vp);
+ }
+ putchar('\n');
+ return;
default:
abort();
}
@@ -238,7 +255,8 @@
emitvar(sym);
putchar('\t');
emitletter(sym->type);
- putchar('\n');
+ if (op != OFUN)
+ putchar('\n');
}
static void
@@ -275,10 +293,16 @@
static void
emitfun(unsigned op, void *arg)
{
- Symbol *sym = arg;
+ Symbol *sym = arg, **sp;
+ int n;
- printf("%c%d\tF\t%s\t{\n",
- sym->flags & ISGLOBAL ? 'G' : 'Y', sym->id, sym->name);
+ emitdcl(op, arg);
+ puts("\t{");
+
+ n = sym->type->n.elem;
+ for (sp = sym->u.pars; n-- > 0; ++sp)
+ emit(ODECL, *sp);
+ puts("-");
}
static void
--- a/cc1/decl.c
+++ b/cc1/decl.c
@@ -8,9 +8,6 @@
#include "../inc/cc.h"
#include "cc1.h"
-#define OUTCTX 0
-#define PARCTX 1
-
struct dcldata {
unsigned char op;
unsigned short nelem;
@@ -52,16 +49,76 @@
return queue(dp, ARY, n, NULL);
}
-static void parlist(Type *);
+static void
+parameter(Symbol *sym, int sclass, Type *data)
+{
+ Type *tp = sym->type, *funtp = data;
+ size_t n = funtp->n.elem;
+ if (tp == voidtype) {
+ if (n != 0)
+ error("incorrect void parameter");
+ funtp->n.elem = -1;
+ return;
+ }
+
+ if (n == -1)
+ error("'void' must be the only parameter");
+ tp = sym->type;
+ if (tp->op == FTN)
+ error("incorrect function type for a function parameter");
+ if (tp->op == ARY)
+ tp = mktype(tp->type, PTR, 0, NULL);
+ if (!sclass)
+ sym->flags |= ISAUTO;
+ if (sym->flags & (ISSTATIC|ISEXTERN))
+ error("bad storage class in function parameter");
+ if (n++ == NR_FUNPARAM)
+ error("too much parameters in function definition");
+ funtp->pars = xrealloc(funtp->pars, n);
+ funtp->pars[n-1] = tp;
+ funtp->n.elem = n;
+}
+
+static Symbol *dodcl(int rep,
+ void (*fun)(Symbol *, int, Type *),
+ uint8_t ns, Type *type);
+
+/* FIXME: what happens with the context in int (*f)(int)[];? */
static struct dcldata *
fundcl(struct dcldata *dp)
{
- Type dummy = {.n = {.elem = 0}, .pars = NULL};
+ Type type = {.n = {.elem = -1}, .pars = NULL};
+ Symbol *syms[NR_FUNPARAM], **sp;
+ size_t size;
- parlist(&dummy);
+ pushctx();
+ expect('(');
- return queue(dp, FTN, dummy.n.elem, dummy.pars);
+ if (accept(')'))
+ goto nopars;
+
+ type.n.elem = 0;
+ sp = syms;
+ do
+ *sp++ = dodcl(0, parameter, NS_IDEN, &type);
+ while (accept(','));
+
+ if (ahead() != '{')
+ goto nopars;
+
+ expect(')');
+
+ dp = queue(dp, FTN, type.n.elem, type.pars);
+ if (type.n.elem != -1) {
+ size = type.n.elem * sizeof(Symbol *);
+ dp = queue(dp, PARS, 0, memcpy(xmalloc(size), syms, size));
+ }
+ return dp;
+
+nopars:
+ expect(')');
+ return queue(dp, FTN, type.n.elem, type.pars);
}
static struct dcldata *declarator0(struct dcldata *dp, unsigned ns);
@@ -75,6 +132,8 @@
dp = declarator0(dp, ns);
expect(')');
} else {
+ /* TODO: check type of the function */
+ /* TODO: check function is not redefined */
if (yytoken == IDEN || yytoken == TYPEIDEN) {
if ((sym = install(ns)) == NULL)
error("redeclaration of '%s'", yytext);
@@ -117,19 +176,27 @@
{
struct dcldata data[NR_DECLARATORS+1];
struct dcldata *bp;
- Symbol *sym;
+ Symbol *sym, **pars = NULL;
data[0].ndcl = 0;
- for (bp = declarator0(data, ns); bp > data; ) {
- --bp;
- if (bp->op != IDEN) {
- tp = mktype(tp, bp->op, bp->nelem, bp->data);
- } else {
+ for (bp = declarator0(data, ns); bp-- > data; ) {
+ switch (bp->op) {
+ case IDEN:
sym = bp->data;
break;
+ case PARS:
+ pars = bp->data;
+ break;
+ default:
+ tp = mktype(tp, bp->op, bp->nelem, bp->data);
+ break;
}
}
+ sym->u.pars = pars;
+ if (tp->op == FTN && sym->flags & (ISREGISTER|ISAUTO))
+ error("invalid storage class for function '%s'", sym->name);
+
/* TODO: deal with external array declarations of [] */
if (!tp->defined && sym->name)
error("declared variable '%s' of incomplete type", sym->name);
@@ -321,8 +388,10 @@
for (val = 0; yytoken != ')'; ++val) {
if (yytoken != IDEN)
unexpected();
- if ((sym = install(NS_IDEN)) == NULL)
- error("'%s' redeclared as different kind of symbol", yytext);
+ if ((sym = install(NS_IDEN)) == NULL) {
+ error("'%s' redeclared as different kind of symbol",
+ yytext);
+ }
next();
sym->flags |= ISCONSTANT;
sym->type = inttype;
@@ -382,50 +451,21 @@
}
static void
-parameter(Symbol *sym, int sclass, Type *data)
-{
- Type *tp = sym->type, *funtp = data;
- size_t n = funtp->n.elem;
-
- if (tp == voidtype) {
- if (n != 0)
- error("incorrect void parameter");
- funtp->n.elem = -1;
- return;
- }
-
- if (n == -1)
- error("'void' must be the only parameter");
- tp = sym->type;
- if (tp->op == FTN)
- error("incorrect function type for a function parameter");
- if (tp->op == ARY)
- tp = mktype(tp->type, PTR, 0, NULL);
- if (!sclass)
- sym->flags |= ISAUTO;
- if (sym->flags & (ISSTATIC|ISEXTERN))
- error("bad storage class in function parameter");
- if (n++ == NR_FUNPARAM)
- error("too much parameters in function definition");
- sym->flags |= ISPARAM;
- funtp->pars = xrealloc(funtp->pars, n);
- funtp->pars[n-1] = tp;
- funtp->n.elem = n;
-}
-
-static void
internal(Symbol *sym, int sclass, Type *data)
{
-
if (!sym->name) {
warn("empty declaration");
return;
}
- if (!sclass)
- sym->flags |= ISAUTO;
- if (accept('='))
- initializer(sym);
- /* TODO: check if the variable is extern and has initializer */
+ if (sym->type->op == FTN) {
+ popctx();
+ } else {
+ if (!sclass)
+ sym->flags |= ISAUTO;
+ if (accept('='))
+ initializer(sym);
+ /* TODO: check if the variable is extern and has initializer */
+ }
emit(ODECL, sym);
}
@@ -440,37 +480,21 @@
if (sym->flags & (ISREGISTER|ISAUTO))
error("incorrect storage class for file-scope declaration");
- if (accept('='))
- initializer(sym);
- /* TODO: check if the variable is extern and has initializer */
- emit(ODECL, sym);
-}
-static int
-prototype(Symbol *sym)
-{
- int r = 1;
-
- /* TODO: check type of the function */
- /* TODO: check function is not redefined */
-
- if (sym->flags & (ISREGISTER|ISAUTO))
- error("invalid storage class for function '%s'", sym->name);
-
- if (curctx == PARCTX && yytoken == '{') {
+ if (sym->type->op == FTN && yytoken == '{') {
if (sym->token == TYPEIDEN)
error("function definition declared 'typedef'");
-
- sym->flags |= ISDEFINED;
curfun = sym;
+ sym->flags |= ISDEFINED;
emit(OFUN, sym);
compound(NULL, NULL, NULL);
emit(OEFUN, NULL);
- popctx();
- r = 0;
+ return;
}
-
- return r;
+ if (accept('='))
+ initializer(sym);
+ /* TODO: check if the variable is extern and has initializer */
+ emit(ODECL, sym);
}
static Symbol *
@@ -480,11 +504,8 @@
Type *base, *tp;
int sclass;
- /* FIXME: curctx == PARCTX is incorrect. Structs also
- * create new contexts
- */
if ((base = specifier(&sclass)) == NULL) {
- if (curctx != OUTCTX)
+ if (curctx != 0)
unexpected();
warn("type defaults to 'int' in declaration");
base = inttype;
@@ -511,12 +532,9 @@
sym->token = TYPEIDEN;
break;
}
- if (tp->op == FTN && !prototype(sym))
- return NULL;
(*fun)(sym, sclass, type);
+ } while (rep && !curfun && accept(','));
- } while (rep && accept(','));
-
return sym;
}
@@ -525,51 +543,12 @@
{
if (accept(';'))
return;
- if (!dodcl(1, curctx == OUTCTX ? external : internal, NS_IDEN, NULL))
+ if (!dodcl(1, (curctx == 0) ? external : internal, NS_IDEN, NULL))
return;
- expect(';');
-}
-
-/*
- * parlist() is called every time there is a argument list.
- * It means that is called for prototypes and for functions.
- * In both cases a new context is needed for the arguments,
- * but in the case of prototypes we need pop the context
- * before parsing anything else or we can have name conflicts.
- * The heuristic used here to detect a function is check if
- * next token will be '{', but it implies that K&R alike
- * functions are not allowed.
- */
-static void
-parlist(Type *tp)
-{
- Symbol *pars[NR_FUNPARAM], **sp = pars;
- bool isfun;
- int n;
-
- pushctx();
- expect('(');
-
- if (accept(')')) {
- tp->n.elem = -1;
- return;
- }
-
- do
- *sp++ = dodcl(0, parameter, NS_IDEN, tp);
- while (accept(','));
-
- isfun = ahead() == '{';
- if (!isfun)
- popctx();
- expect(')');
-
- if (!isfun)
- return;
-
- n = tp->n.elem;
- for (sp = pars; n-- > 0; ++sp)
- emit(ODECL, *sp);
+ if (curfun)
+ curfun == NULL;
+ else
+ expect(';');
}
static void
--- a/cc1/stmt.c
+++ b/cc1/stmt.c
@@ -334,6 +334,12 @@
}
popctx();
+ /*
+ * curctx == 1 means we are at the end of a function
+ * so we have to pop the context related to the parameters
+ */
+ if (curctx == 1)
+ popctx();
expect('}');
}
--- a/cc2/main.c
+++ b/cc2/main.c
@@ -42,6 +42,8 @@
int
main(void)
{
+ fputs("cc2 is not updated with the output of cc1", stderr);
+ exit(1);
while (moreinput()) {
parse();
optimize();
--- a/inc/cc.h
+++ b/inc/cc.h
@@ -37,7 +37,7 @@
#define L_UINT64 'O'
#define L_VOID '0'
-#define L_POINTER 'R'
+#define L_POINTER 'P'
#define L_FUNCTION 'F'
#define L_ARRAY 'V'
#define L_UNION 'U'