[hackers] [scc] Emit function types before emiting functions || Roberto E. Vargas Caballero

From: <git_AT_suckless.org>
Date: Fri, 7 Aug 2015 09:15:47 +0200 (CEST)

commit 84977e24ad1f367840d132c50b89d090a275ecbc
Author: Roberto E. Vargas Caballero <k0ga_AT_shike2.com>
AuthorDate: Fri Aug 7 09:13:00 2015 +0200
Commit: Roberto E. Vargas Caballero <k0ga_AT_shike2.com>
CommitDate: Fri Aug 7 09:13:00 2015 +0200

    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.

diff --git a/cc1/cc1.h b/cc1/cc1.h
index ce3a2cc..3fbda77 100644
--- a/cc1/cc1.h
+++ b/cc1/cc1.h
_AT_@ -51,6 +51,7 @@ struct symbol {
                 TFLOAT f;
                 char *s;
                 unsigned char token;
+ Symbol **pars;
         } u;
         struct symbol *next;
         struct symbol *hash;
_AT_@ -108,6 +109,7 @@ enum {
         FTN = 1,
         PTR,
         ARY,
+ PARS,
 };
 
 /* namespaces */
_AT_@ -129,10 +131,9 @@ enum {
         ISREGISTER = 8,
         ISDEFINED = 16,
         ISFIELD = 32,
- ISPARAM = 64,
- ISEXTERN = 128,
- ISUSED = 256,
- ISCONSTANT = 512
+ ISEXTERN = 64,
+ ISUSED = 128,
+ ISCONSTANT = 256
 };
 
 
diff --git a/cc1/code.c b/cc1/code.c
index 573f03a..9857edb 100644
--- a/cc1/code.c
+++ b/cc1/code.c
_AT_@ -147,6 +147,7 @@ emit(unsigned op, void *arg)
         (*opcode[op])(op, arg);
 }
 
+/* TODO: move these letters to cc.h */
 static void
 emitvar(Symbol *sym)
 {
_AT_@ -157,11 +158,9 @@ emitvar(Symbol *sym)
         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);
_AT_@ -204,26 +203,44 @@ static void
 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;
 
         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;
         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();
         }
_AT_@ -238,7 +255,8 @@ emitdcl(unsigned op, void *arg)
         emitvar(sym);
         putchar('\t');
         emitletter(sym->type);
- putchar('\n');
+ if (op != OFUN)
+ putchar('\n');
 }
 
 static void
_AT_@ -275,10 +293,16 @@ emitexp(unsigned op, void *arg)
 static void
 emitfun(unsigned op, void *arg)
 {
- Symbol *sym = arg;
+ Symbol *sym = arg, **sp;
+ int n;
+
+ emitdcl(op, arg);
+ puts("\t{");
 
- printf("%c%d\tF\t%s\t{\n",
- sym->flags & ISGLOBAL ? 'G' : 'Y', sym->id, sym->name);
+ n = sym->type->n.elem;
+ for (sp = sym->u.pars; n-- > 0; ++sp)
+ emit(ODECL, *sp);
+ puts("-");
 }
 
 static void
diff --git a/cc1/decl.c b/cc1/decl.c
index 5247887..154777b 100644
--- a/cc1/decl.c
+++ b/cc1/decl.c
_AT_@ -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;
_AT_@ -52,16 +49,76 @@ arydcl(struct dcldata *dp)
         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;
+
+ pushctx();
+ expect('(');
 
- parlist(&dummy);
+ if (accept(')'))
+ goto nopars;
 
- return queue(dp, FTN, dummy.n.elem, dummy.pars);
+ 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);
_AT_@ -75,6 +132,8 @@ directdcl(struct dcldata *dp, unsigned ns)
                 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);
_AT_@ -117,19 +176,27 @@ declarator(Type *tp, unsigned ns)
 {
         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);
_AT_@ -321,8 +388,10 @@ enumdcl(void)
         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;
_AT_@ -382,50 +451,21 @@ field(Symbol *sym, int sclass, Type *data)
 }
 
 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);
 }
 
_AT_@ -440,37 +480,21 @@ external(Symbol *sym, int sclass, Type *data)
 
         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 *
_AT_@ -480,11 +504,8 @@ dodcl(int rep, void (*fun)(Symbol *, int, Type *), uint8_t ns, Type *type)
         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;
_AT_@ -511,11 +532,8 @@ dodcl(int rep, void (*fun)(Symbol *, int, Type *), uint8_t ns, Type *type)
                         sym->token = TYPEIDEN;
                         break;
                 }
- if (tp->op == FTN && !prototype(sym))
- return NULL;
                 (*fun)(sym, sclass, type);
-
- } while (rep && accept(','));
+ } while (rep && !curfun && accept(','));
 
         return sym;
 }
_AT_@ -525,51 +543,12 @@ decl(void)
 {
         if (accept(';'))
                 return;
- if (!dodcl(1, curctx == OUTCTX ? 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)
+ if (!dodcl(1, (curctx == 0) ? external : internal, NS_IDEN, NULL))
                 return;
-
- n = tp->n.elem;
- for (sp = pars; n-- > 0; ++sp)
- emit(ODECL, *sp);
+ if (curfun)
+ curfun == NULL;
+ else
+ expect(';');
 }
 
 static void
diff --git a/cc1/stmt.c b/cc1/stmt.c
index f06a812..377f520 100644
--- a/cc1/stmt.c
+++ b/cc1/stmt.c
_AT_@ -334,6 +334,12 @@ compound(Symbol *lbreak, Symbol *lcont, Caselist *lswitch)
         }
 
         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('}');
 }
 
diff --git a/cc2/main.c b/cc2/main.c
index 3aec235..2511d40 100644
--- a/cc2/main.c
+++ b/cc2/main.c
_AT_@ -42,6 +42,8 @@ repeat:
 int
 main(void)
 {
+ fputs("cc2 is not updated with the output of cc1", stderr);
+ exit(1);
         while (moreinput()) {
                 parse();
                 optimize();
diff --git a/inc/cc.h b/inc/cc.h
index 241bddb..bf7896c 100644
--- a/inc/cc.h
+++ b/inc/cc.h
_AT_@ -37,7 +37,7 @@ typedef unsigned bool;
 #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'
Received on Fri Aug 07 2015 - 09:15:47 CEST

This archive was generated by hypermail 2.3.0 : Fri Aug 07 2015 - 09:24:15 CEST