summaryrefslogtreecommitdiff
path: root/usr.bin/pcc/ccom
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/pcc/ccom')
-rw-r--r--usr.bin/pcc/ccom/cgram.y101
-rw-r--r--usr.bin/pcc/ccom/pass1.h5
-rw-r--r--usr.bin/pcc/ccom/trees.c17
3 files changed, 97 insertions, 26 deletions
diff --git a/usr.bin/pcc/ccom/cgram.y b/usr.bin/pcc/ccom/cgram.y
index 10961e47eae..7cec014fb61 100644
--- a/usr.bin/pcc/ccom/cgram.y
+++ b/usr.bin/pcc/ccom/cgram.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: cgram.y,v 1.5 2007/11/18 17:39:55 ragge Exp $ */
+/* $OpenBSD: cgram.y,v 1.6 2007/11/22 15:06:43 stefan Exp $ */
/*
* Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
@@ -169,7 +169,8 @@ static void swend(void);
static void addcase(NODE *p);
static void adddef(void);
static void savebc(void);
-static void swstart(int);
+static void swstart(int, TWORD);
+static void genswitch(int, TWORD, struct swents **, int);
static NODE * structref(NODE *p, int f, char *name);
static char *mkpstr(char *str);
static struct symtab *clbrace(NODE *);
@@ -863,23 +864,24 @@ forprefix: C_FOR '(' .e ';' .e ';' {
switchpart: C_SWITCH '(' e ')' {
NODE *p;
int num;
+ TWORD t;
savebc();
brklab = getlab();
- if ($3->n_type != INT) {
- /* must cast to integer */
- p = block(NAME, NIL, NIL, INT, 0, MKSUE(INT));
- p = buildtree(CAST, p, $3);
- $3 = p->n_right;
- nfree(p->n_left);
- nfree(p);
+ if (($3->n_type != BOOL && $3->n_type > ULONGLONG) ||
+ $3->n_type < CHAR) {
+ uerror("switch expression must have integer "
+ "type");
+ t = INT;
+ } else {
+ $3 = intprom($3);
+ t = $3->n_type;
}
-// ecomp( buildtree( FORCE, $3, NIL ) );
- p = tempnode(0, INT, 0, MKSUE(INT));
+ p = tempnode(0, t, 0, MKSUE(t));
num = p->n_lval;
ecomp(buildtree(ASSIGN, p, $3));
branch( $$ = getlab());
- swstart(num);
+ swstart(num, t);
reached = 0;
}
;
@@ -1145,6 +1147,7 @@ struct swdef {
struct swents *ents; /* Linked sorted list of case entries */
int nents; /* # of entries in list */
int num; /* Node value will end up in */
+ TWORD type; /* Type of switch expression */
} *swpole;
/*
@@ -1154,6 +1157,7 @@ static void
addcase(NODE *p)
{
struct swents **put, *w, *sw = tmpalloc(sizeof(struct swents));
+ CONSZ val;
p = optim(p); /* change enum to ints */
if (p->n_op != ICON || p->n_sp != NULL) {
@@ -1165,19 +1169,35 @@ addcase(NODE *p)
return;
}
+ val = p->n_lval;
+ p = makety(p, swpole->type, 0, 0, MKSUE(swpole->type));
+ if (p->n_op != ICON)
+ cerror("could not cast case value to type of switch "
+ "expression");
+ if (p->n_lval != val)
+ werror("case expression truncated");
+
sw->sval = p->n_lval;
+ tfree(p);
put = &swpole->ents;
- for (w = swpole->ents; w != NULL && w->sval < sw->sval; w = w->next)
- put = &w->next;
- if (w != NULL && w->sval == sw->sval)
+ if (ISUNSIGNED(swpole->type)) {
+ for (w = swpole->ents;
+ w != NULL && (U_CONSZ)w->sval < (U_CONSZ)sw->sval;
+ w = w->next)
+ put = &w->next;
+ } else {
+ for (w = swpole->ents; w != NULL && w->sval < sw->sval;
+ w = w->next)
+ put = &w->next;
+ }
+ if (w != NULL && w->sval == sw->sval) {
uerror("duplicate case in switch");
- else {
- plabel(sw->slab = getlab());
- *put = sw;
- sw->next = w;
- swpole->nents++;
+ return;
}
- tfree(p);
+ plabel(sw->slab = getlab());
+ *put = sw;
+ sw->next = w;
+ swpole->nents++;
}
/*
@@ -1195,7 +1215,7 @@ adddef(void)
}
static void
-swstart(int num)
+swstart(int num, TWORD type)
{
struct swdef *sw = tmpalloc(sizeof(struct swdef));
@@ -1203,6 +1223,7 @@ swstart(int num)
sw->ents = NULL;
sw->next = swpole;
sw->num = num;
+ sw->type = type;
swpole = sw;
}
@@ -1225,12 +1246,46 @@ swend(void)
swp[i] = swpole->ents;
swpole->ents = swpole->ents->next;
}
- genswitch(swpole->num, swp, swpole->nents);
+ genswitch(swpole->num, swpole->type, swp, swpole->nents);
swpole = swpole->next;
}
/*
+ * num: tempnode the value of the switch expression is in
+ * type: type of the switch expression
+ *
+ * p points to an array of structures, each consisting
+ * of a constant value and a label.
+ * The first is >=0 if there is a default label;
+ * its value is the label number
+ * The entries p[1] to p[n] are the nontrivial cases
+ * n is the number of case statements (length of list)
+ */
+static void
+genswitch(int num, TWORD type, struct swents **p, int n)
+{
+ NODE *r, *q;
+ int i;
+
+ if (mygenswitch(num, type, p, n))
+ return;
+
+ /* simple switch code */
+ for (i = 1; i <= n; ++i) {
+ /* already in 1 */
+ r = tempnode(num, type, 0, MKSUE(type));
+ q = block(ICON, NIL, NIL, type, 0, MKSUE(type));
+ q->n_sp = NULL;
+ q->n_lval = p[i]->sval;
+ r = buildtree(NE, r, clocal(q));
+ cbranch(buildtree(NOT, r, NIL), bcon(p[i]->slab));
+ }
+ if (p[0]->slab > 0)
+ branch(p[0]->slab);
+}
+
+/*
* Declare a variable or prototype.
*/
static struct symtab *
diff --git a/usr.bin/pcc/ccom/pass1.h b/usr.bin/pcc/ccom/pass1.h
index c736b681043..052673848d2 100644
--- a/usr.bin/pcc/ccom/pass1.h
+++ b/usr.bin/pcc/ccom/pass1.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pass1.h,v 1.4 2007/11/18 17:39:55 ragge Exp $ */
+/* $OpenBSD: pass1.h,v 1.5 2007/11/22 15:06:43 stefan Exp $ */
/*
* Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
*
@@ -177,7 +177,7 @@ struct swents { /* switch table */
CONSZ sval; /* case value */
int slab; /* associated label */
};
-void genswitch(int, struct swents **, int);
+int mygenswitch(int, TWORD, struct swents **, int);
extern int blevel;
extern int instruct, got_type;
@@ -254,6 +254,7 @@ extern NODE
*btsize(TWORD, union dimfun *, struct suedef *),
*tempnode(int, TWORD type, union dimfun *df, struct suedef *sue),
*doacall(NODE *f, NODE *a);
+NODE *intprom(NODE *);
OFFSZ tsize(TWORD, union dimfun *, struct suedef *),
psize(NODE *);
NODE * typenode(NODE *new);
diff --git a/usr.bin/pcc/ccom/trees.c b/usr.bin/pcc/ccom/trees.c
index 1fa2ecc9c74..7d93e4a97d2 100644
--- a/usr.bin/pcc/ccom/trees.c
+++ b/usr.bin/pcc/ccom/trees.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trees.c,v 1.9 2007/11/18 17:39:55 ragge Exp $ */
+/* $OpenBSD: trees.c,v 1.10 2007/11/22 15:06:43 stefan Exp $ */
/*
* Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
* All rights reserved.
@@ -2398,3 +2398,18 @@ plabel(int label)
reached = 1; /* Will this always be correct? */
send_passt(IP_DEFLAB, label);
}
+
+/*
+ * Perform integer promotion on node n.
+ */
+NODE *
+intprom(NODE *n)
+{
+ if ((n->n_type >= CHAR && n->n_type < INT) || n->n_type == BOOL) {
+ if ((n->n_type == UCHAR && MAX_UCHAR > MAX_INT) ||
+ (n->n_type == USHORT && MAX_USHORT > MAX_INT))
+ return makety(n, UNSIGNED, 0, 0, MKSUE(UNSIGNED));
+ return makety(n, INT, 0, 0, MKSUE(INT));
+ }
+ return n;
+}