shithub: scc

Download patch

ref: e6ef99231498cfcd683a5132b7de6f266e50444d
parent: 3f775a9d7d5405a555e5746f3314884ace516a4c
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Mon Jan 18 17:29:11 EST 2016

Add mkcompound()

This function takes an initializer structure and it creates
an array of expressions which will be used in the symbol
created for the compound literal.

--- a/cc1/cc1.h
+++ b/cc1/cc1.h
@@ -17,7 +17,6 @@
 typedef struct caselist Caselist;
 typedef struct node Node;
 typedef struct input Input;
-typedef struct init Init;
 
 struct limits {
 	union {
@@ -62,14 +61,6 @@
 	} n;
 };
 
-struct designator;
-
-struct init {
-	Type *type;
-	TUINT pos;
-	struct designator *head;
-};
-
 struct symbol {
 	char *name;
 	Type *type;
@@ -84,7 +75,7 @@
 		TFLOAT f;
 		char *s;
 		unsigned char token;
-		Init *init;
+		Node **init;
 		Symbol **pars;
 	} u;
 	struct symbol *next;
@@ -175,7 +166,8 @@
 	ISEMITTED  =    1024,
 	ISDEFINED  =    2048,
 	ISSTRING   =    4096,
-	ISTYPEDEF  =    8192
+	ISTYPEDEF  =    8192,
+	ISINITLST  =   16384
 };
 
 /* lexer mode, compiler or preprocessor directive */
--- a/cc1/code.c
+++ b/cc1/code.c
@@ -291,13 +291,9 @@
 static void
 emitinit(unsigned op, void *arg)
 {
-	Node *np = arg;
-
 	puts("(");
-	emitexp(OEXPR, np->right);
+	emitexp(OEXPR, arg);
 	puts(")");
-	np->right = NULL;
-	freetree(np);
 }
 
 static void
--- a/cc1/init.c
+++ b/cc1/init.c
@@ -1,6 +1,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include "../inc/cc.h"
 #include "../inc/sizes.h"
@@ -7,6 +8,8 @@
 #include "cc1.h"
 
 
+typedef struct init Init;
+
 struct designator {
 	TINT pos;
 	Node *expr;
@@ -13,7 +16,15 @@
 	struct designator *next;
 };
 
+struct init {
+	Type *type;
+	size_t pos;
+	size_t max;
+	struct designator *tail;
+	struct designator *head;
+};
 
+
 static TINT
 arydesig(Init *ip)
 {
@@ -63,10 +74,6 @@
 	struct designator *dp;
 	TINT (*fun)(Init *);
 
-	dp = xmalloc(sizeof(*dp));
-	dp->next = ip->head;
-	ip->head = dp;
-
 	switch (yytoken) {
 	case '[': fun = arydesig;   break;
 	case '.': fun = fielddesig; break;
@@ -85,44 +92,99 @@
 {
 	Node *np;
 
-	np = (accept('{')) ? initlist(tp) : assign();
-	if ((np = convert(decay(np), tp, 0)) == NULL)
+	np = (accept('{')) ? initlist(tp) : decay(assign());
+	if ((np = convert(np, tp, 0)) == NULL) {
 		errorp("incorrect initializer");
+		np = constnode(zero);
+	}
 	return np;
 }
 
 static Node *
-initlist(Type *tp)
+mkcompound(Init *ip)
 {
-	Init *ip;
+	Node **v, **p;
+	size_t n;
+	struct designator *dp, *next;
 	Symbol *sym;
+
+	n = ip->max;
+	if (n >= n * sizeof(*v)) {
+		errorp("compound literal too big");
+		return constnode(zero);
+	}
+	n *= sizeof(*v);
+	v = memset(xmalloc(n), 0, n);
+
+	for (dp = ip->head; dp; dp = next) {
+		p = &v[dp->pos];
+		freetree(*p);
+		*p = dp->expr;
+		next = dp->next;
+		free(dp);
+	}
+
+	sym = newsym(NS_IDEN);
+	sym->u.init = v;
+	sym->type = ip->type;
+	sym->flags |= ISINITLST;
+
+	return constnode(sym);
+}
+
+static void
+newdesig(Init *ip, Node *np)
+{
 	struct designator *dp;
-	int toomany = 0;
-	Type *newtp;
 
-	ip = xmalloc(sizeof(*ip));
-	ip->head = NULL;
-	ip->pos = 0;
-	ip->type = tp;
+	if (ip->pos > ip->max)
+		ip->max = ip->pos;
 
-	if (accept('}'))
-		goto end_of_initializer;
+	dp = xmalloc(sizeof(*dp));
+	dp->pos = ip->pos;
+	dp->expr = np;
+	dp->next = NULL;
 
-	for (ip->pos = 1; ; ++ip->pos) {
-		designation(ip);
+	if (ip->head == NULL) {
+		ip->head = ip->tail = dp;
+	} else {
+		ip->tail->next = dp;
+		ip->tail = dp;
+	}
+}
+
+static Node *
+initlist(Type *tp)
+{
+	Init in;
+	int toomany = 0, outbound;
+	Type *newtp;
+	Node *np;
+
+	in.tail = in.head = NULL;
+	in.type = tp;
+	in.pos = 0;
+	in.max = 0;
+
+	do {
+		if (yytoken == '}')
+			break;
+		outbound = 0;
+		designation(&in);
 		switch (tp->op) {
 		case ARY:
-			newtp = sym->type;
-			if (!tp->defined || ip->pos <= tp->n.elem)
+			newtp = tp->type;
+			if (!tp->defined || in.pos < tp->n.elem)
 				break;
 			if (!toomany)
 				warn("excess elements in array initializer");
+			outbound = 1;
 			toomany = 1;
 			break;
+		/* TODO: case UNION: */
 		case STRUCT:
-			if (ip->pos <= tp->n.elem) {
-				sym = tp->p.fields[ip->pos-1];
-				newtp = sym->type;
+			if (in.pos < tp->n.elem) {
+				newtp = tp->p.fields[in.pos]->type;
 				break;
 			}
 			newtp = inttype;
@@ -129,35 +191,45 @@
 			if (!toomany)
 				warn("excess elements in struct initializer");
 			toomany = 1;
+			outbound = 1;
 			break;
 		default:
 			newtp = tp;
 			warn("braces around scalar initializer");
-			if (ip->pos == 1)
+			if (in.pos == 0)
 				break;
 			if (!toomany)
 				warn("excess elements in scalar initializer");
 			toomany = 1;
+			outbound = 1;
 			break;
 		}
-		dp = ip->head;
-		dp->pos = ip->pos;
-		dp->expr = initialize(newtp);
 
-		if (!accept(','))
-			break;
-	}
+		np = initialize(newtp);
+		if (outbound)
+			freetree(np);
+		else
+			newdesig(&in, np);
+
+		if (++in.pos == 0)
+			errorp("compound literal too big");
+
+	} while (accept(','));
+
 	expect('}');
 
-end_of_initializer:
 	if (tp->op == ARY && !tp->defined) {
-		tp->n.elem = ip->pos;
+		tp->n.elem = in.pos;
 		tp->defined = 1;
 	}
-	sym = newsym(NS_IDEN);
-	sym->u.init = ip;
-	sym->type = tp;
-	return constnode(sym);
+	if (tp->op == ARY || tp->op == STRUCT)
+		in.max = tp->n.elem;
+	else if (in.max == 0) {
+		errorp("empty scalar initializer");
+		return constnode(zero);
+	}
+
+	return mkcompound(&in);
 }
 
 void
@@ -168,7 +240,6 @@
 
 	if (tp->op == FTN)
 		errorp("function '%s' is initialized like a variable", sym->name);
-
 	np = initialize(tp);
 
 	if (flags & ISDEFINED) {