[hackers] [scc] Rewrite decl.c || Roberto E. Vargas Caballero

From: <git_AT_suckless.org>
Date: Wed, 5 Aug 2015 08:55:51 +0200 (CEST)

commit 3c619b9a7518c458fe6343faab8f566368557080
Author: Roberto E. Vargas Caballero <k0ga_AT_shike2.com>
AuthorDate: Wed Aug 5 08:52:33 2015 +0200
Commit: Roberto E. Vargas Caballero <k0ga_AT_shike2.com>
CommitDate: Wed Aug 5 08:55:39 2015 +0200

    Rewrite decl.c
    
    decl.c had several function that were very similar between them,
    basically the different kind of declarations in a C program:
    
            - externals
            - internals
            - parameters
            - struct/union fields
    
    This version puts all the logic in only one function, dodcl(),
    which receives different parameters to adapt to the different
    situations. The idea was taken from kencc and lcc.

diff --git a/cc1/TODO b/cc1/TODO
index 8bd6c22..96638cb 100644
--- a/cc1/TODO
+++ b/cc1/TODO
_AT_@ -1,8 +1,6 @@
 * Verify correctness in initializators
 * emit initializators
 * emit structures definition
-* Rewrite decl.c and use only one decl function with a function pointer
- parameter
 * Allow external declarations of incomplete array types
 * Implement bitfields
 * Define data structure shared between cc1 and cc2 with the type
diff --git a/cc1/cc1.h b/cc1/cc1.h
index 7399403..3d9630d 100644
--- a/cc1/cc1.h
+++ b/cc1/cc1.h
_AT_@ -306,7 +306,7 @@ extern void compound(Symbol *lbreak, Symbol *lcont, Caselist *lswitch);
 
 /* decl.c */
 extern Type *typename(void);
-extern void extdecl(void), decl(void);
+extern void decl(void);
 
 /* lex.c */
 extern char ahead(void);
_AT_@ -350,6 +350,8 @@ extern int cppoff, disexpand;
 extern unsigned cppctx;
 extern Input *input;
 extern int lexmode;
+extern unsigned curctx;
+extern Symbol *curfun;
 
 extern Type *voidtype, *pvoidtype, *booltype,
             *uchartype, *chartype,
diff --git a/cc1/decl.c b/cc1/decl.c
index 04d40b1..d6aeaab 100644
--- a/cc1/decl.c
+++ b/cc1/decl.c
_AT_@ -8,11 +8,8 @@
 #include "../inc/cc.h"
 #include "cc1.h"
 
-#define ID_EXPECTED 1
-#define ID_ACCEPTED 2
-#define ID_FORBIDDEN 3
-
-/* TODO: check identifiers in enum declaration */
+#define OUTCTX 0
+#define PARCTX 1
 
 struct dcldata {
         unsigned char op;
_AT_@ -55,54 +52,16 @@ arydcl(struct dcldata *dp)
         return queue(dp, ARY, n, NULL);
 }
 
-static Symbol *parameter(void);
+static void parlist(Type *);
 
 static struct dcldata *
 fundcl(struct dcldata *dp)
 {
- size_t siz;
- unsigned n, i, noname;
- Type *pars[NR_FUNPARAM], **tp = pars;
- Symbol *syms[NR_FUNPARAM], **sp = syms, *sym;
+ Type dummy = {.n = {.elem = 0}, .pars = NULL};
 
         pushctx();
- expect('(');
-
- n = noname = 0;
- if (yytoken != ')') do {
- if ((sym = parameter()) == NULL) {
- if (n == 0)
- break;
- error("incorrect void parameter");
- }
- if (n++ == NR_FUNPARAM)
- error("too much parameters in function definition");
- *sp++ = sym;
- *tp++ = sym->type;
- noname |= sym->name[0] == '\0';
- } while (accept(','));
-
- expect(')');
- if (n != 0) {
- siz = sizeof(*tp) * n;
- tp = memcpy(xmalloc(siz), pars, siz);
- } else {
- tp = NULL;
- }
-
- if (yytoken != '{') {
- /* it is only a prototype */
- popctx();
- } else {
- /* it is a function definition */
- if (noname)
- error("parameter name omitted");
- sp = syms;
- for (i = 0; i < n; ++i)
- emit(ODECL, *sp++);
- }
-
- return queue(dp, FTN, n, tp);
+ parlist(&dummy);
+ return queue(dp, FTN, dummy.n.elem, dummy.pars);
 }
 
 static struct dcldata *declarator0(struct dcldata *dp, unsigned ns);
_AT_@ -154,7 +113,7 @@ declarator0(struct dcldata *dp, unsigned ns)
 }
 
 static Symbol *
-declarator(Type *tp, int flags, unsigned ns)
+declarator(Type *tp, unsigned ns)
 {
         struct dcldata data[NR_DECLARATORS+1];
         struct dcldata *bp;
_AT_@ -167,16 +126,12 @@ declarator(Type *tp, int flags, unsigned ns)
                         tp = mktype(tp, bp->op, bp->nelem, bp->data);
                 } else {
                         sym = bp->data;
- if (flags == ID_EXPECTED && *sym->name == '\0')
- error("missed identifier in declaration");
- if (flags == ID_FORBIDDEN && *sym->name != '\0')
- error("unexpected identifier in type name");
                         break;
                 }
         }
 
         /* TODO: deal with external array declarations of [] */
- if (!tp->defined && *sym->name)
+ if (!tp->defined && sym->name)
                 error("declared variable '%s' of incomplete type", sym->name);
         sym->type = tp;
         return sym;
_AT_@ -326,63 +281,26 @@ newtag(void)
 
 /* TODO: bitfields */
 
+static void fieldlist(Type *tp);
+
 static Type *
 structdcl(void)
 {
- Type *tagtype, *buff[NR_MAXSTRUCTS], **bp = &buff[0];
- Symbol *tagsym, *sym;
- unsigned n;
- size_t siz;
+ Symbol *sym;
+ Type *tp;
 
- tagsym = newtag();
- tagtype = tagsym->type;
+ sym = newtag();
+ tp = sym->type;
         if (!accept('{'))
- return tagtype;
-
- if (tagtype->defined)
- error("redefinition of struct/union '%s'", yytext);
- tagtype->defined = 1;
-
- while (!accept('}')) {
- Type *base, *tp;
-
- switch (yytoken) {
- case SCLASS:
- error("storage class '%s' in struct/union field",
- yytext);
- case IDEN: case TYPE: case TYPEIDEN: case TQUALIFIER:
- base = specifier(NULL);
- break;
- case ';':
- next();
- continue;
- default:
- unexpected();
- }
-
- if (accept(';'))
- error("identifier expected");
+ return tp;
 
- do {
- sym = declarator(base, ID_EXPECTED, tagtype->ns);
- sym->flags |= ISFIELD;
- tp = sym->type;
- if (tp->op == FTN)
- error("invalid type in struct/union");
- if (bp == &buff[NR_MAXSTRUCTS])
- error("too much fields in struct/union");
- *bp++ = sym->type;
- emit(ODECL, sym);
- } while (accept(','));
- expect(';');
- }
+ if (tp->defined)
+ error("redefinition of struct/union '%s'", sym->name);
+ tp->defined = 1;
 
- if ((n = bp - buff) != 0) {
- siz = sizeof(Type *) * n;
- tagtype->n.elem = n;
- tagtype->pars = memcpy(xmalloc(siz), buff, siz);
- }
- return tagtype;
+ while (!accept('}'))
+ fieldlist(tp);
+ return tp;
 }
 
 static Type *
_AT_@ -427,165 +345,217 @@ enumdcl(void)
         return tp;
 }
 
-static Symbol *
-parameter(void)
+Type *
+typename(void)
 {
- Symbol *sym;
         unsigned sclass;
         Type *tp;
+ Symbol *sym;
+
+ tp = specifier(&sclass);
+ if (sclass)
+ error("class storage in type name");
+ sym = declarator(tp, NS_IDEN);
+
+ if (!sym->name)
+ error("unexpected identifier in type name");
+
+ return sym->type;
+}
+
+static void
+field(Symbol *sym, unsigned sclass, Type *data)
+{
+ Type *tp = sym->type, *funtp = data;
+ size_t n = funtp->n.elem;
+
+ if (sclass)
+ error("storage class in struct/union field");
+ if (!sym->name)
+ error("missed identifier in field declaration");
+ if (tp->op == FTN)
+ error("invalid type in struct/union");
+ sym->flags |= ISFIELD;
+ if (n++ == NR_FUNPARAM)
+ error("too much fields in struct/union");
+ funtp->pars = xrealloc(funtp->pars, n);
+ funtp->pars[n-1] = tp;
+ funtp->n.elem = n;
+}
+
+static void
+parameter(Symbol *sym, unsigned 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 ((tp = specifier(&sclass)) == voidtype)
- return NULL;
- sym = declarator(tp, ID_ACCEPTED, NS_IDEN);
- sym->flags |= ISPARAM;
+ 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);
- switch (sclass) {
- case REGISTER:
- sym->flags |= ISREGISTER;
- break;
- case 0:
+ if (!sclass)
                 sym->flags |= ISAUTO;
- break;
- default:
+ if (sym->flags & (ISSTATIC|ISEXTERN))
                 error("bad storage class in function parameter");
- }
- return sym;
+ 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;
 }
 
-void
-decl(void)
+static void
+internal(Symbol *sym, unsigned sclass, Type *data)
 {
- Type *tp;
- Symbol *sym;
- unsigned sclass, isfun;
- extern jmp_buf recover;
 
- setsafe(END_DECL);
- if (setjmp(recover))
+ if (!sym->name) {
+ warn("empty declaration");
                 return;
- tp = specifier(&sclass);
- if (accept(';'))
+ }
+ if (!sclass)
+ sym->flags |= ISAUTO;
+ if (accept('='))
+ initializer(sym);
+ /* TODO: check if the variable is extern and has initializer */
+ emit(ODECL, sym);
+}
+
+static void
+external(Symbol *sym, unsigned sclass, Type *data)
+{
+ if (!sym->name) {
+ warn("empty declaration");
                 return;
+ }
+ sym->flags |= ISSTATIC|ISGLOBAL;
+
+ 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->token == TYPEIDEN)
+ error("function definition declared 'typedef'");
+
+ /* TODO: emit parameters emit(ODECL, *sp++); */
+ sym->flags |= ISDEFINED;
+ curfun = sym;
+ emit(OFUN, sym);
+ compound(NULL, NULL, NULL);
+ emit(OEFUN, NULL);
+ r = 0;
+ }
+
+ /*
+ * fundcl() creates a new context for the parameters
+ * and in this point we have to destroy the context
+ */
+ popctx();
+ return r;
+}
+
+static bool
+dodcl(int rep, void (*fun)(Symbol *, unsigned, Type *), uint8_t ns, Type *type)
+{
+ Type *base, *tp = NULL;
+ unsigned sclass = 0;
+ Symbol *sym = NULL;
+
+ /* FIXME: curctx == PARCTX is incorrect. Structs also
+ * create new contexts
+ */
+ /* FIXME: in arguments base can be NULL */
+ base = specifier(&sclass);
+ if (!base && curctx == OUTCTX) {
+ warn("type defaults to 'int' in declaration");
+ tp = inttype;
+ }
 
         do {
- setsafe(END_LDECL);
- setjmp(recover);
- sym = declarator(tp, ID_EXPECTED, NS_IDEN);
- isfun = sym->type->op == FTN;
+ sym = declarator(base, ns);
+ tp = sym->type;
 
                 switch (sclass) {
- case TYPEDEF:
- sym->token = TYPEIDEN;
- continue;
+ case REGISTER:
+ sym->flags |= ISREGISTER;
+ break;
+ case AUTO:
+ sym->flags |= ISAUTO;
+ break;
                 case STATIC:
                         sym->flags |= ISSTATIC;
                         break;
                 case EXTERN:
                         sym->flags |= ISEXTERN;
                         break;
- case REGISTER:
- sym->flags = ISREGISTER;
- if (isfun)
- goto bad_function;
- break;
- case AUTO:
- if (isfun)
- goto bad_function;
- /* passtrough */
- default:
- sym->flags |= ISAUTO;
+ case TYPEDEF:
+ sym->token = TYPEIDEN;
                         break;
                 }
- if (accept('='))
- initializer(sym);
- emit(ODECL, sym);
- } while (accept(','));
-
- expect(';');
- return;
-
-bad_function:
- error("invalid storage class for function '%s'", sym->name);
-}
 
-Type *
-typename(void)
-{
- unsigned sclass;
- Type *tp;
- Symbol *sym;
+ if (tp->op == FTN && !prototype(sym))
+ return 0;
+ (*fun)(sym, sclass, type);
+ } while (rep && accept(','));
 
- tp = specifier(&sclass);
- if (sclass)
- error("class storage in type name");
- sym = declarator(tp, ID_FORBIDDEN, NS_IDEN);
- return sym->type;
+ return 1;
 }
 
 void
-extdecl(void)
+decl(void)
 {
- Type *base, *tp;
- unsigned sclass;
- Symbol *sym;
- extern Symbol *curfun;
- extern jmp_buf recover;
-
- setsafe(END_DECL);
- if (setjmp(recover))
+ if (accept(';'))
                 return;
+ if (!dodcl(1, curctx == OUTCTX ? external : internal, NS_IDEN, NULL))
+ return;
+ expect(';');
+}
 
- switch (yytoken) {
- case IDEN: case TYPE: case TYPEIDEN: case SCLASS: case TQUALIFIER:
- base = specifier(&sclass);
- if (accept(';'))
- return;
- do {
- /* FIX: we cannot put a setjmp here because
- base was already assigned, and we were having
- problems with EOF */
- sym = declarator(base, ID_EXPECTED, NS_IDEN);
- tp = sym->type;
- sym->flags |= ISSTATIC;
- sym->flags |= ISGLOBAL;
-
- switch (sclass) {
- case REGISTER: case AUTO:
- error("incorrect storage class for file-scope declaration");
- case STATIC:
- sym->flags |= ISSTATIC;
- break;
- case EXTERN:
- sym->flags |= ISEXTERN;
- break;
- case TYPEDEF:
- sym->token = TYPEIDEN;
- continue;
- }
+static void
+parlist(Type *tp)
+{
+ expect('(');
 
- if (tp->op != FTN) {
- if (accept('='))
- initializer(sym);
- emit(ODECL, sym);
- } else if (yytoken == '{') {
- curfun = sym;
- emit(OFUN, sym);
- compound(NULL, NULL, NULL);
- emit(OEFUN, NULL);
- popctx();
- return;
- }
- } while (accept(','));
- /* PASSTHROUGH */
- case ';':
- expect(';');
+ if (accept(')')) {
+ /* TODO: implement k&r functions */
                 return;
- default:
- unexpected();
         }
+ do
+ dodcl(0, parameter, NS_IDEN, tp);
+ while (accept(','));
+
+ expect(')');
 }
 
+static void
+fieldlist(Type *tp)
+{
+ if (yytoken != ';')
+ dodcl(1, field, tp->ns, tp);
+ expect(';');
+}
diff --git a/cc1/main.c b/cc1/main.c
index 2ea327b..3f3218a 100644
--- a/cc1/main.c
+++ b/cc1/main.c
_AT_@ -67,7 +67,7 @@ main(int argc, char *argv[])
         ikeywords();
         ilex(*argv);
 
- for (next(); yytoken != EOFTOK; extdecl())
+ for (next(); yytoken != EOFTOK; decl())
                 /* nothing */;
 
         return 0;
diff --git a/cc1/symbol.c b/cc1/symbol.c
index 0b672fb..7e25a14 100644
--- a/cc1/symbol.c
+++ b/cc1/symbol.c
_AT_@ -10,7 +10,7 @@
 
 #define NR_SYM_HASH 64
 
-static unsigned curctx;
+unsigned curctx;
 static short localcnt;
 static short globalcnt;
 
Received on Wed Aug 05 2015 - 08:55:51 CEST

This archive was generated by hypermail 2.3.0 : Wed Aug 05 2015 - 09:00:15 CEST