Skip to content

Commit 0e911d8

Browse files
committed
Implement switch expressions
1 parent c9ad518 commit 0e911d8

File tree

3 files changed

+142
-2
lines changed

3 files changed

+142
-2
lines changed

Diff for: source/compiler/sc.h

+1
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,7 @@ SC_FUNC void check_tagmismatch(int formaltag,int actualtag,int allowcoerce,int e
693693
SC_FUNC void check_tagmismatch_multiple(int formaltags[],int numtags,int actualtag,int errline);
694694
SC_FUNC char *funcdisplayname(char *dest,char *funcname);
695695
SC_FUNC int constexpr(cell *val,int *tag,symbol **symptr);
696+
SC_FUNC constvalue *insert_constval(constvalue *prev,constvalue *next,const char *name,cell val,int index);
696697
SC_FUNC constvalue *append_constval(constvalue_root *table,const char *name,cell val,int index);
697698
SC_FUNC constvalue *find_constval(constvalue_root *table,char *name,int index);
698699
SC_FUNC void delete_consttable(constvalue_root *table);

Diff for: source/compiler/sc1.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -5267,7 +5267,7 @@ static void destructsymbols(symbol *root,int level)
52675267
popreg(sPRI);
52685268
}
52695269

5270-
static constvalue *insert_constval(constvalue *prev,constvalue *next,
5270+
SC_FUNC constvalue *insert_constval(constvalue *prev,constvalue *next,
52715271
const char *name,cell val,int index)
52725272
{
52735273
constvalue *cur;
@@ -6210,7 +6210,7 @@ static int doswitch(void)
62106210
error(40,val); /* duplicate "case" label */
62116211
assert(csp==NULL || csp->next==cse);
62126212
insert_constval(csp,cse,itoh(lbl_case),val,0);
6213-
} /* if */
6213+
} /* while */
62146214
} /* if */
62156215
} while (matchtoken(','));
62166216
needtoken(':'); /* ':' ends the case */

Diff for: source/compiler/sc3.c

+139
Original file line numberDiff line numberDiff line change
@@ -1629,6 +1629,145 @@ static int hier2(value *lval)
16291629
} /* if */
16301630
return FALSE;
16311631
} /* case */
1632+
case tSWITCH: {
1633+
int swdefault,casecount,firstcase;
1634+
int swtag,csetag,exprtag;
1635+
int lbl_table,lbl_exit,lbl_case;
1636+
int ident,index;
1637+
int bck_allowtags;
1638+
cell cidx;
1639+
constvalue_root caselist = { NULL, NULL}; /* case list starts empty */
1640+
constvalue *cse,*csp,*newval;
1641+
char labelname[sNAMEMAX+1];
1642+
needtoken('(');
1643+
ident=expression(&val,&swtag,NULL,TRUE);
1644+
if (ident==iARRAY || ident==iREFARRAY)
1645+
error(33,"-unknown-"); /* array must be indexed */
1646+
/* generate the code for the switch statement, the label is the address
1647+
* of the case table (to be generated later).
1648+
*/
1649+
lbl_table=getlabel();
1650+
lbl_case=0; /* just to avoid a compiler warning */
1651+
ffswitch(lbl_table);
1652+
lbl_exit=getlabel(); /* get label number for jumping out of switch */
1653+
casecount=0;
1654+
swdefault=FALSE;
1655+
firstcase=TRUE;
1656+
do {
1657+
needtoken(tTERM);
1658+
ident=lex(&val,&st);
1659+
if (ident==')')
1660+
break;
1661+
lbl_case=getlabel();
1662+
setlabel(lbl_case);
1663+
bck_allowtags=sc_allowtags;
1664+
sc_allowtags=FALSE; /* do not allow tagnames here */
1665+
if (ident==tLABEL && st[0]=='_' && st[1]=='\0') {
1666+
if (swdefault!=FALSE)
1667+
error(16); /* multiple defaults in switch */
1668+
swdefault=TRUE;
1669+
} else {
1670+
if (ident!=tLABEL)
1671+
lexpush();
1672+
else
1673+
error(220); /* expression with tag override must appear between parentheses */
1674+
if (swdefault!=FALSE)
1675+
error(15); /* "default" case must be last in switch statement */
1676+
do {
1677+
casecount++;
1678+
stgget(&index,&cidx); /* mark position in code generator */
1679+
ident=expression(&val,&csetag,NULL,TRUE);
1680+
stgdel(index,cidx); /* scratch generated code */
1681+
if (ident!=iCONSTEXPR)
1682+
error(8); /* must be constant expression */
1683+
check_tagmismatch(swtag,csetag,TRUE,-1);
1684+
/* Search the insertion point (the table is kept in sorted order, so
1685+
* that advanced abstract machines can sift the case table with a
1686+
* binary search). Check for duplicate case values at the same time.
1687+
*/
1688+
for (csp=NULL, cse=caselist.first;
1689+
cse!=NULL && cse->value<val;
1690+
csp=cse, cse=cse->next)
1691+
/* nothing */;
1692+
if (cse!=NULL && cse->value==val)
1693+
error(40,val); /* duplicate "case" label */
1694+
/* Since the label is stored as a string in the "constvalue", the
1695+
* size of an identifier must be at least 8, as there are 8
1696+
* hexadecimal digits in a 32-bit number.
1697+
*/
1698+
#if sNAMEMAX < 8
1699+
#error Length of identifier (sNAMEMAX) too small.
1700+
#endif
1701+
assert(csp==NULL || csp->next==cse);
1702+
newval=insert_constval(csp,cse,itoh(lbl_case),val,0);
1703+
if (csp==NULL)
1704+
caselist.first=newval;
1705+
if (matchtoken(tDBLDOT)) {
1706+
cell end;
1707+
stgget(&index,&cidx); /* mark position in code generator */
1708+
ident=expression(&end,&csetag,NULL,TRUE);
1709+
stgdel(index,cidx); /* scratch generated code */
1710+
if (ident!=iCONSTEXPR)
1711+
error(8); /* must be constant expression */
1712+
if (end<=val)
1713+
error(50); /* invalid range */
1714+
while (++val<=end) {
1715+
casecount++;
1716+
/* find the new insertion point */
1717+
for (csp=NULL, cse=caselist.first;
1718+
cse!=NULL && cse->value<val;
1719+
csp=cse, cse=cse->next)
1720+
/* nothing */;
1721+
if (cse!=NULL && cse->value==val)
1722+
error(40,val); /* duplicate "case" label */
1723+
assert(csp==NULL || csp->next==cse);
1724+
insert_constval(csp,cse,itoh(lbl_case),val,0);
1725+
} /* while */
1726+
} /* if */
1727+
} while (matchtoken(','));
1728+
needtoken(':'); /* ':' ends the case */
1729+
} /* if */
1730+
sc_allowtags=bck_allowtags; /* reset */
1731+
ident=expression(NULL,&exprtag,NULL,FALSE);
1732+
if (ident==iARRAY || ident==iREFARRAY)
1733+
error(33,"-unknown-"); /* array must be indexed */
1734+
if (firstcase) {
1735+
tag=exprtag;
1736+
firstcase=FALSE;
1737+
} else {
1738+
check_tagmismatch(tag,exprtag,TRUE,-1);
1739+
} /* if */
1740+
jumplabel(lbl_exit);
1741+
} while (!matchtoken(')'));
1742+
#if !defined NDEBUG
1743+
/* verify that the case table is sorted (unfortunately, duplicates can
1744+
* occur; there really shouldn't be duplicate cases, but the compiler
1745+
* may not crash or drop into an assertion for a user error). */
1746+
for (cse=caselist.first; cse!=NULL && cse->next!=NULL; cse=cse->next)
1747+
assert(cse->value <= cse->next->value);
1748+
#endif
1749+
/* generate the table here, before lbl_exit (general jump target) */
1750+
setlabel(lbl_table);
1751+
assert(swdefault==FALSE || swdefault==TRUE);
1752+
if (swdefault==FALSE) {
1753+
/* store lbl_exit as the "none-matched" label in the switch table */
1754+
strcpy(labelname,itoh(lbl_exit));
1755+
} else {
1756+
/* lbl_case holds the label of the "default" clause */
1757+
strcpy(labelname,itoh(lbl_case));
1758+
} /* if */
1759+
ffcase(casecount,labelname,TRUE);
1760+
/* generate the rest of the table */
1761+
for (cse=caselist.first; cse!=NULL; cse=cse->next)
1762+
ffcase(cse->value,cse->name,FALSE);
1763+
1764+
setlabel(lbl_exit);
1765+
delete_consttable(&caselist); /* clear list of case labels */
1766+
clear_value(lval);
1767+
lval->ident=iEXPRESSION;
1768+
lval->tag=tag;
1769+
return FALSE;
1770+
} /* case */
16321771
case t__EMIT:
16331772
paranthese=matchtoken('(');
16341773
emit_flags |= efEXPR;

0 commit comments

Comments
 (0)