📄 stmt.c
字号:
/*
Copyright 1994-2003 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
This program is derived from the cc68k complier by
Matthew Brandt (mattb@walkingdog.net)
You may contact the author of this derivative at:
mailto::camille@bluegrass.net
or by snail mail at:
David Lindauer
850 Washburn Ave Apt 99
Louisville, KY 40222
*/
/*
* Statement parser
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "lists.h"
#include "expr.h"
#include "c.h"
#include "ccerr.h"
#include "diag.h"
extern int prm_oldfor;
extern TYP stdint;
extern int funcnesting;
extern int prm_c99;
extern int defaulttype;
extern int indefaultinit;
extern int stdpragmas;
extern int block_nesting;
extern char *cpp_funcname_tab[];
extern LIST *instantiated_inlines;
extern LIST *local_using_list, *local_tag_using_list;
extern SYM undef;
extern ENODE *block_rundown;
extern int lastch;
extern enum e_sym lastst, lastlastst;
extern char lastid[];
extern TABLE lsyms, oldlsym, ltags, oldltag;
extern int lineno;
extern SYM *currentfunc;
extern int skm_closepa[];
extern int incldepth;
extern short unalteredline[4096];
extern int prm_cplusplus, prm_debug;
extern int prm_ansi;
extern int vtabhead;
extern int currentfile;
extern FILELIST *lastinc;
extern int dbgblocknum;
extern short *lptr;
extern int prm_cmangle;
extern int arg_nesting;
extern SNODE *funcendstmt;
extern SYM *typequal;
extern char declid[];
extern SYM *catch_cleanup_func, *global_vararray_func;
extern TYP **headptr, *head;
extern int prm_xcept;
extern int skm_declend[];
extern int global_flag;
extern int stdaddrsize, stdintsize;
extern ENODE *expr_runup[];
extern ENODE *expr_rundown[];
extern int expr_updowncount;
extern int infuncargs;
extern int gotoCount;
int selectscalar(TYP *tp)
{
return tp->type == bt_pointer && !tp->val_flag || scalarnoncomplex(tp) ;
}
int incatchclause;
int asmline;
int skm_openpa[] =
{
openpa, begin, semicolon, 0
};
int skm_semi[] =
{
semicolon, end, 0
};
int skm_tocase[] =
{
kw_case, kw_default, end, 0
};
long nextlabel, firstlabel;
int goodcode;
TRYBLOCK *try_block_list;
#define CASE_MAX 512
struct caselist {
struct caselist *next;
int last;
LLONG_TYPE cases[CASE_MAX];
} *currentCases ;
static int gotellipse;
static char phibuf[4096];
static int lastlineno = 0;
static int switchbreak;
static int hasdefault;
static int inswitch;
static int switchwidth;
SNODE *cbautoinithead, *cbautoinittail, *cbautorundownhead,
*cbautorundowntail;
LASTDEST *lastDestPointer;
void stmtini(void)
{
lastlineno = 0;
nextlabel = firstlabel = 1;
goodcode = 0;
asmline = FALSE;
lastDestPointer = 0;
inswitch = 0;
}
/* get the size of the expression, and cast up to int as necessary */
static TYP *stmtsize(ENODE **node, TYP *tp)
{
#ifdef XXXXX
TYP *rv;
enum e_bt t1 ;
if (!tp || !*node)
return tp;
t1 = tp->type;
if (t1 <= bt_int)
t1 = bt_int;
else if (t1 <= bt_unsigned)
t1 = bt_unsigned;
rv = inttype(t1);
if (rv->type != tp->type)
promote_type(rv,node);
return rv ;
#else
return tp;
#endif
}
/* scan an expression and determine if there are any pias */
TYP *doassign(ENODE **exp, int canerror, int *skm)
{
TYP *tp;
goodcode |= GF_INIF;
if ((tp = expression(exp, TRUE)) == 0)
{
if (canerror)
generror(ERR_EXPREXPECT, 0, skm);
*exp = makenode(en_nacon, &undef, 0);
}
goodcode &= ~GF_INIF;
// cast to higher level
tp = stmtsize(exp,tp);
return tp;
}
//-------------------------------------------------------------------------
SNODE *whilestmt(void)
/*
* whilestmt parses the c while statement.
*/
{
SNODE *snp;
int ogc = goodcode;
TYP *tp ;
goodcode |= GF_INLOOP;
snp = xalloc(sizeof(SNODE));
snp->next = 0;
snp->stype = st_while;
snp->s1 = 0;
getsym();
needpunc(openpa, 0);
tp = doassign(&snp->exp, TRUE, 0);
if (tp)
{
if (tp->type == bt_cond)
tp = tp->btp ;
if (!selectscalar(tp))
generror(ERR_SELECTSCALAR, 0, 0);
}
needpunc(closepa, skm_closepa);
goodcode |= GF_CONTINUABLE | GF_BREAKABLE;
snp->s1 = cppblockedstatement(TRUE);
goodcode = ogc;
return snp;
}
//-------------------------------------------------------------------------
SNODE *dostmt(void)
/*
* dostmt parses the c do-while construct.
*/
{
SNODE *snp;
TYP *tp;
int ogc = goodcode, oswb = switchbreak;
goodcode |= GF_INLOOP;
snp = xalloc(sizeof(SNODE));
snp->next = 0;
snp->stype = st_do;
getsym();
goodcode |= GF_CONTINUABLE | GF_BREAKABLE;
snp->s1 = cppblockedstatement(TRUE);
goodcode = ogc;
if (lastst != kw_while)
gensymerror(ERR_IDENTEXPECT, lastid);
else
getsym();
needpunc(openpa, 0);
tp = doassign(&snp->exp, TRUE, 0);
if (tp)
{
if (tp->type == bt_cond)
tp = tp->btp ;
if (!selectscalar(tp))
generror(ERR_SELECTSCALAR, 0, 0);
}
needpunc(closepa, skm_closepa);
if (lastst != eof)
needpunc(semicolon, 0);
switchbreak = oswb;
return snp;
}
//-------------------------------------------------------------------------
SNODE *forstmt(void)
/*
* Generate a block for a for statement
*/
{
SNODE *snp, *forexp;
int ogc = goodcode, oswb = switchbreak;
int plussemi = 0;
int declared = 0;
int oldpragma;
TABLE ools, oolt;
goodcode |= GF_INLOOP;
snp = xalloc(sizeof(SNODE));
snp->next = 0;
getsym();
snp->label = snp->exp = snp->s2 = 0;
snp->stype = st_for;
if (needpunc(openpa, skm_closepa))
{
/* CPLUSPLUS allows you to declare a variable here */
if (castbegin(lastst) || lastst == kw_auto || lastst == kw_register)
{
if (prm_cplusplus || prm_c99)
{
ENODE *exp = 0, **next = &exp;
cbautoinithead = cbautoinittail = 0;
ools = oldlsym;
oldlsym = lsyms;
oolt = oldltag;
oldltag = ltags;
oldpragma = stdpragmas;
declared = 1;
blockdecl();
while (cbautoinithead)
{
if (*next)
{
*next = makenode(en_void, (*next), cbautoinithead
->exp);
next = &(*next)->v.p[1];
}
else
*next = cbautoinithead->exp;
cbautoinithead = cbautoinithead->next;
}
snp->label = exp;
plussemi = 1;
}
else
{
generror(ERR_NODECLARE, 0, 0);
snp->label = makenode(en_nacon, &undef, 0);
while (castbegin(lastst))
getsym();
goto forjoin;
}
}
else
forjoin:
{
if (expression(&snp->label, TRUE) == 0)
snp->label = 0;
plussemi = needpunc(semicolon, 0);
}
if (plussemi)
{
TYP *tp;
goodcode |= GF_INIF;
tp = expression(&snp->exp, TRUE);
tp = stmtsize(&snp->exp, tp);
if (tp)
{
if (tp->type == bt_cond)
tp = tp->btp ;
if (!selectscalar(tp))
generror(ERR_SELECTSCALAR, 0, 0);
}
forexp = snp->exp;
goodcode &= ~GF_INIF;
// doassign(&snp->exp,FALSE,0);
if (needpunc(semicolon, 0))
{
if (expression(&snp->s2, TRUE) == 0)
{
snp->s2 = 0;
}
}
}
needpunc(closepa, skm_closepa);
}
goodcode |= GF_CONTINUABLE | GF_BREAKABLE;
snp->s1 = cppblockedstatement(TRUE);
if (declared && !prm_oldfor)
{
SYM *q = lsyms.head;
gather_labels(&oldlsym, &lsyms);
while (q && q->next != oldlsym.head)
q = q->next;
if (q)
q->next = 0;
addblocklist(lsyms.head, oldlsym.head);
addrundown(snp);
check_funcused(&oldlsym, &lsyms);
if (oldlsym.head != lsyms.head)
arg_nesting++;
stdpragmas = oldpragma;
lsyms = oldlsym;
oldlsym.head = ools.head;
ltags = oldltag;
oldltag.head = oolt.head;
}
goodcode = ogc;
if (!switchbreak && !forexp)
goodcode |= GF_UNREACH;
switchbreak = oswb;
return snp;
}
//-------------------------------------------------------------------------
SNODE *ifstmt(void)
/*
* ifstmt parses the c if statement and an else clause if
* one is present.
*/
{
SNODE *snp;
int ogc = goodcode;
int temp = 0, temp1 = 0;
TYP *tp;
snp = xalloc(sizeof(SNODE));
snp->next = 0;
snp->stype = st_if;
getsym();
needpunc(openpa, 0);
tp = doassign(&snp->exp, TRUE, 0);
if (tp)
{
if (tp->type == bt_cond)
tp = tp->btp ;
if (!selectscalar(tp))
generror(ERR_SELECTSCALAR, 0, 0);
}
needpunc(closepa, skm_closepa);
snp->s1 = cppblockedstatement(FALSE);
temp1 = goodcode &(GF_RETURN | GF_BREAK | GF_CONTINUE | GF_GOTO | GF_THROW);
if (lastst == kw_else)
{
temp = goodcode &(GF_RETURN | GF_BREAK | GF_CONTINUE | GF_GOTO |
GF_THROW);
goodcode = ogc;
getsym();
snp->s2 = cppblockedstatement(FALSE);
temp = temp &goodcode;
}
else
snp->s2 = 0;
goodcode = ogc | (temp &temp1);
return snp;
}
//-------------------------------------------------------------------------
SNODE *casestmt(void)
/*
* cases are returned as seperate statements. for normal
* cases label is the case value and s2 is zero. for the
* default case s2 is nonzero.
*/
{
SNODE *snp;
SNODE *head = 0, *tail;
LLONG_TYPE ssize;
snp = xalloc(sizeof(SNODE));
snp->next = 0;
if (lastst == kw_case)
{
struct caselist *cc = currentCases;
getsym();
snp->s2 = 0;
snp->stype = st_case;
snp->switchid = (ssize = intexpr(0));
snp->label = (SNODE *)-1;
if (switchwidth == 1 && (ssize &0xffffff00) || switchwidth == 2 && (ssize &0xffff0000)
|| switchwidth == - 1 && (ssize < - 0x80 || ssize > 0x7f) || switchwidth == -
2 && (ssize < - 0x8000 || ssize > 0x7fff))
generror(ERR_LOSTCONVCASE, 0, 0);
while (cc) {
int i;
for (i=0; i < cc->last; i++)
if (ssize == cc->cases[i]) {
generror(ERR_DUPCASE,ssize,0);
cc = 0;
break ;
}
if (cc && !cc->next) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -