commit 2fae9d998da0050e988c600e6581a076441382ef
parent 9adea1257259dd445efff48073917cc5a6b3f230
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Mon, 11 Jan 2016 10:10:40 +0100
Add support for k&r functions
I know that this was the most expected feature of scc. You guys
can begin to work with scc after this commit.
Diffstat:
6 files changed, 149 insertions(+), 90 deletions(-)
diff --git a/cc1/cc1.h b/cc1/cc1.h
@@ -45,6 +45,7 @@ struct type {
bool integer : 1; /* this type is INT or enum */
bool arith : 1; /* this type is INT, ENUM, FLOAT */
bool aggreg : 1; /* this type is struct or union */
+ bool k_r : 1; /* This is a k&r function */
size_t size; /* sizeof the type */
size_t align; /* align of the type */
Type *type; /* base type */
@@ -134,7 +135,8 @@ enum {
enum {
FTN = 1,
PTR,
- ARY
+ ARY,
+ KRFTN
};
/* namespaces */
diff --git a/cc1/code.c b/cc1/code.c
@@ -355,20 +355,15 @@ static void
emitfun(unsigned op, void *arg)
{
Symbol *sym = arg, **sp;
- TINT n;
emitdcl(op, arg);
puts("\n{");
- n = sym->type->n.elem;
- for (sp = sym->u.pars; n-- > 0; ++sp) {
- if ((sym = *sp) == NULL)
- continue;
- /* enable non used warnings in parameters */
- sym->flags &= ~ISUSED;
- emit(ODECL, sym);
- }
+ for (sp = sym->u.pars; sp && *sp; ++sp)
+ emit(ODECL, *sp);
puts("\\");
+ free(sym->u.pars);
+ sym->u.pars = NULL;
}
static void
diff --git a/cc1/decl.c b/cc1/decl.c
@@ -52,6 +52,7 @@ push(struct declarators *dp, int op, ...)
case ARY:
p->nelem = va_arg(va, TINT);
break;
+ case KRFTN:
case FTN:
p->nelem = va_arg(va, TINT);
p->tpars = va_arg(va, Type **);
@@ -87,7 +88,7 @@ pop(struct declarators *dp, struct decl *dcl)
popctx();
dcl->pars = NULL;
}
- if (p->op == FTN)
+ if (p->op == FTN || p->op == KRFTN)
dcl->pars = p->pars;
dcl->type = mktype(dcl->type, p->op, p->nelem, p->tpars);
return 1;
@@ -159,7 +160,7 @@ parameter(struct decl *dcl)
switch (tp->op) {
case VOID:
- if (n != 0) {
+ if (n != 0 || funtp->k_r) {
errorp("incorrect void parameter");
return NULL;
}
@@ -175,13 +176,22 @@ parameter(struct decl *dcl)
return NULL;
}
if (!empty(sym, tp)) {
- if ((sym = install(NS_IDEN, sym)) == NULL) {
+ Symbol *p = install(NS_IDEN, sym);
+ if (!p && !funtp->k_r) {
errorp("redefinition of parameter '%s'", name);
return NULL;
}
+ if (p && funtp->k_r) {
+ errorp("declaration for parameter ā%sā but no such parameter",
+ sym->name);
+ return NULL;
+ }
+ if (p)
+ sym = p;
}
sym->type = tp;
+ sym->flags &= ~(ISAUTO|ISREGISTER);
sym->flags |= flags;
return sym;
}
@@ -192,66 +202,114 @@ static Symbol *dodcl(int rep,
Type *type);
static void
-fundcl(struct declarators *dp)
+krfun(Type *tp, Type *types[], Symbol *syms[], int *ntypes, int *nsyms)
{
- Type type, *types[NR_FUNPARAM], *tp;
- Symbol *syms[NR_FUNPARAM], *sym;
- TINT size;
- Symbol *pars;
- int toomany = 0, toovoid = 0;
-
- pushctx();
- expect('(');
- type.n.elem = 0;
+ int n = 0;
+ Symbol *sym;
+ int toomany = 0;
- if (yytoken == ')') {
- ++type.n.elem;
- syms[0] = NULL;
- types[0] = ellipsistype;
- goto end_params;
+ if (yytoken != ')') {
+ do {
+ sym = yylval.sym;
+ expect(IDEN);
+ sym->type = inttype;
+ sym->flags |= ISAUTO;
+ if ((sym = install(NS_IDEN, sym)) == NULL) {
+ errorp("redefinition of parameter '%s'",
+ sym->name);
+ continue;
+ }
+ if (n < NR_FUNPARAM) {
+ ++n;
+ *syms++ = sym;
+ continue;
+ }
+ if (!toomany)
+ errorp("too much parameters in function definition");
+ toomany = 1;
+ } while (accept(','));
}
+
+ *nsyms = n;
+ *ntypes = 1;
+ types[0] = ellipsistype;
+}
+
+static void
+ansifun(Type *tp, Type *types[], Symbol *syms[], int *ntypes, int *nsyms)
+{
+ int n = 0;
+ Symbol *sym;
+ int toomany = 0, toovoid = 0;
+
do {
- if (type.n.elem == -1) {
+ if (n == -1) {
if (!toovoid)
errorp("'void' must be the only parameter");
toovoid = 1;
}
- if (!accept(ELLIPSIS)) {
- sym = dodcl(0, parameter, NS_IDEN, &type);
- if (!sym)
- continue;
- tp = sym->type;
- } else {
- if (type.n.elem == 0)
+ if (accept(ELLIPSIS)) {
+ if (n == 0)
errorp("a named argument is requiered before '...'");
- tp = ellipsistype;
- sym = NULL;
+ ++n;
+ *syms = NULL;
+ *types++ = ellipsistype;
+ break;
}
- if (type.n.elem == NR_FUNPARAM) {
- if (toomany)
- continue;
- errorp("too much parameters in function definition");
- toomany = 1;
- } else if (type.n.elem >= 0) {
- syms[type.n.elem] = sym;
- types[type.n.elem] = tp;
- ++type.n.elem;
+ if ((sym = dodcl(0, parameter, NS_IDEN, tp)) == NULL)
+ continue;
+ if (tp->n.elem == -1) {
+ n = -1;
+ continue;
+ }
+ if (n < NR_FUNPARAM) {
+ *syms++ = sym;
+ *types++ = sym->type;
+ ++n;
+ continue;
}
- } while (tp != ellipsistype && accept(','));
+ if (!toomany)
+ errorp("too much parameters in function definition");
+ toomany = 1;
+ } while (accept(','));
+
+ *nsyms = n;
+ *ntypes = n;
+}
+
+static void
+fundcl(struct declarators *dp)
+{
+ Type *types[NR_FUNPARAM], type;
+ Symbol *syms[NR_FUNPARAM+1], **pars;
+ int k_r, ntypes, nsyms;
+ size_t size;
+ void (*fp)(Type **, Symbol **, int *, int *);
-end_params:
+ pushctx();
+ expect('(');
+ type.n.elem = 0;
+ type.k_r = 0;
+
+ k_r = (yytoken == ')' || yytoken == IDEN);
+ (*(k_r ? krfun : ansifun))(&type, types, syms, &ntypes, &nsyms);
expect(')');
- if (type.n.elem > 0) {
- size = type.n.elem * sizeof(Symbol *);
- pars = memcpy(xmalloc(size), syms, size);
- size = type.n.elem * sizeof(Type *);
- type.p.pars = memcpy(xmalloc(size), types, size);
+ type.n.elem = ntypes;
+ if (ntypes <= 0) {
+ type.p.pars = NULL;
} else {
+ size = ntypes * sizeof(Type *);
+ type.p.pars = memcpy(xmalloc(size), types, size);
+ }
+ if (nsyms <= 0) {
pars = NULL;
- type.p.pars = NULL;
+ } else {
+ size = (nsyms + 1) * sizeof(Symbol *);
+ pars = memcpy(xmalloc(size), syms, size);
+ pars[nsyms] = NULL;
}
- push(dp, FTN, type.n.elem, type.p.pars, pars);
+ push(dp, (k_r) ? KRFTN : FTN, type.n.elem, type.p.pars, pars);
}
static void declarator(struct declarators *dp, unsigned ns);
@@ -757,51 +815,47 @@ dodcl(int rep, Symbol *(*fun)(struct decl *), unsigned ns, Type *parent)
return sym;
}
-static void
-prototype(Symbol *sym)
-{
- int n;
- Symbol **p;
-
- emit(ODECL, sym);
- /*
- * avoid non used warnings in prototypes
- */
- n = sym->type->n.elem;
- for (p = sym->u.pars; n-- > 0; ++p) {
- if (*p == NULL)
- continue;
- (*p)->flags |= ISUSED;
- }
- free(sym->u.pars);
- sym->u.pars = NULL;
- popctx();
-}
-
void
decl(void)
{
- Symbol *sym;
+ Symbol **p, *par, *sym, *ocurfun;
if (accept(';'))
return;
sym = dodcl(1, identifier, NS_IDEN, NULL);
- /*
- * Functions only can appear at global context,
- * but due to parameter context, we have to check
- * against GLOBALCTX+1
- */
if (sym->type->op != FTN) {
expect(';');
return;
}
+ ocurfun = curfun;
+ curfun = sym;
+ /*
+ * Functions only can appear at global context,
+ * but due to parameter context, we have to check
+ * against GLOBALCTX+1
+ */
if (curctx != GLOBALCTX+1 || yytoken == ';') {
- prototype(sym);
+ emit(ODECL, sym);
+ /*
+ * avoid non used warnings in prototypes
+ */
+ for (p = sym->u.pars; p && *p; ++p)
+ (*p)->flags |= ISUSED;
+ popctx();
expect(';');
+ free(sym->u.pars);
+ sym->u.pars = NULL;
+ curfun = ocurfun;
return;
}
+ if (sym->type->k_r) {
+ while (yytoken != '{') {
+ par = dodcl(1, parameter, NS_IDEN, sym->type);
+ expect(';');
+ }
+ }
if (sym->flags & ISTYPEDEF)
errorp("function definition declared 'typedef'");
@@ -811,14 +865,13 @@ decl(void)
sym->flags &= ~ISEXTERN;
sym->flags |= ISGLOBAL;
}
+
sym->flags |= ISDEFINED;
sym->flags &= ~ISEMITTED;
- curfun = sym;
emit(OFUN, sym);
- free(sym->u.pars);
compound(NULL, NULL, NULL);
emit(OEFUN, NULL);
- curfun = NULL;
+ curfun = ocurfun;
}
static void
diff --git a/cc1/expr.c b/cc1/expr.c
@@ -339,9 +339,9 @@ arithmetic(char op, Node *lp, Node *rp)
if (ltp->arith && rtp->arith) {
arithconv(&lp, &rp);
} else if ((ltp->op == PTR || rtp->op == PTR) &&
- op == OADD || op == OSUB) {
+ (op == OADD || op == OSUB)) {
return parithmetic(op, rp, lp);
- } else {
+ } else if (op != OINC && op != ODEC) {
errorp("incorrect arithmetic operands");
}
return simplify(op, lp->type, lp, rp);
diff --git a/cc1/symbol.c b/cc1/symbol.c
@@ -111,6 +111,10 @@ popctx(void)
killsym(sym);
}
labels = NULL;
+ if (curfun) {
+ free(curfun->u.pars);
+ curfun->u.pars = NULL;
+ }
}
for (sym = head; sym && sym->ctx > curctx; sym = next) {
diff --git a/cc1/types.c b/cc1/types.c
@@ -436,11 +436,15 @@ mktype(Type *tp, int op, TINT nelem, Type *pars[])
Type **tbl, type;
unsigned t;
Type *bp;
- int c;
+ int c, k_r = 0;
if (op == PTR && tp == voidtype)
return pvoidtype;
+ if (op == KRFTN) {
+ k_r = 1;
+ op = FTN;
+ }
switch (op) {
case PTR: c = L_POINTER; break;
case ARY: c = L_ARRAY; break;
@@ -458,6 +462,7 @@ mktype(Type *tp, int op, TINT nelem, Type *pars[])
type.integer = 0;
type.printed = 0;
type.aggreg = 0;
+ type.k_r = k_r;
type.letter = c;
type.p.pars = pars;
type.n.elem = nelem;