📄 stmt.c
字号:
/* * C compiler * ========== * * Copyright 1989, 1990, 1991 Christoph van Wuellen. * Credits to Matthew Brandt. * All commercial rights reserved. * * This compiler may be redistributed as long there is no * commercial interest. The compiler must not be redistributed * without its full sources. This notice must stay intact. * * History: * * 1989 starting an 68000 C compiler, starting with material * originally by M. Brandt * 1990 68000 C compiler further bug fixes * started i386 port (December) * 1991 i386 port finished (January) * further corrections in the front end and in the 68000 * code generator. * The next port will be a SPARC port *//****************************************************************************** * * The statement module handles all of the possible c statements and builds a * parse tree of the statements. * * Each routine returns a pointer to a statement parse node which reflects the * statement just parsed. * *****************************************************************************/#include "chdr.h"#include "expr.h"#include "cglbdec.h"#include "proto.h"/********************************************************** Static Variables */#ifndef SYNTAX_CORRECTstatic BOOL return_found = FALSE; /* return statement encountered */static int break_lvl = 0; /* nesting depth of break statements */static int cont_lvl = 0; /* nesting depth of continue statements */static int case_lvl = 0; /* nesting depth of case statements */static BOOL need_label = FALSE;#endif /* SYNTAX_CORRECT *//*********************************************** Static Function Definitions */static STMT *mk_stmt P_ ((STMTTYPE));static STMT *whilestmt P_ ((void));static STMT *dostmt P_ ((void));static STMT *forstmt P_ ((void));static STMT *ifstmt P_ ((void));static STMT *casestmt P_ ((void));static STMT *switchstmt P_ ((void));static STMT *retstmt P_ ((void));static STMT *breakstmt P_ ((void));static STMT *contstmt P_ ((void));static STMT *exprstmt P_ ((void));static STMT *labelstmt P_ ((void));static STMT *gotostmt P_ ((void));static STMT *statement P_ ((void));static STMT *compound P_ ((void));#ifdef TRACEstatic STMT *tracestmt P_ ((void));#endif /* TRACE *//*****************************************************************************/
/*
* walkstmt() descends the statement tree recursively.
*/
#if defined(__STDC__) || defined(__cplusplus)
STMT * walkstmt (STMT *stmts, STMT *(*stmtfunc) (STMT *),
EXPR *(*exprfunc) (EXPR *))
#else
STMT * walkstmt (stmts, stmtfunc, exprfunc)
STMT *stmts;
STMT *(*stmtfunc) ();
EXPR *(*exprfunc) ();
#endif
{
STMT *stmt;
for (stmt = (*stmtfunc) (stmts); stmt != NIL_STMT; stmt = stmt->next) {
switch (stmt->stype) {
case st_return:
case st_expr:
stmt->exp = (*exprfunc) (stmt->exp);
break;
case st_while:
case st_do:
stmt->exp = (*exprfunc) (stmt->exp);
stmt->s1 = walkstmt (stmt->s1, stmtfunc, exprfunc);
break;
case st_for:
stmt->exp = (*exprfunc) (stmt->exp);
stmt->v1.e = (*exprfunc) (stmt->v1.e);
stmt->s1 = walkstmt (stmt->s1, stmtfunc, exprfunc);
stmt->v2.e = (*exprfunc) (stmt->v2.e);
break;
case st_if:
stmt->exp = (*exprfunc) (stmt->exp);
stmt->s1 = walkstmt (stmt->s1, stmtfunc, exprfunc);
stmt->v1.s = walkstmt (stmt->v1.s, stmtfunc, exprfunc);
break;
case st_switch:
stmt->exp = (*exprfunc) (stmt->exp);
stmt->v1.s = walkstmt (stmt->v1.s, stmtfunc, exprfunc);
break;
case st_case:
case st_default:
case st_label:
stmt->v1.s = walkstmt (stmt->v1.s, stmtfunc, exprfunc);
break;
case st_compound:
stmt->s1 = walkstmt (stmt->s1, stmtfunc, exprfunc);
break;
case st_goto:
case st_break:
case st_continue:
#ifdef ASM
case st_asm:
#endif /* ASM */
break;
default:
CANNOT_REACH_HERE ();
break;
}
stmt->next = (*stmtfunc) (stmt->next);
}
return stmts;
}
/*****************************************************************************/static STMT *mk_stmt P1 (STMTTYPE, st){ STMT *snp; snp = (STMT *) xalloc (sizeof (STMT)); snp->stype = st; snp->next = NIL_STMT; snp->exp = NIL_EXPR; snp->s1 = NIL_STMT;#ifdef DEBUGOPT snp->line = act_line; snp->linetxt = mk_string (act_linetxt);#endif /*DEBUGOPT */ return snp;}
#ifdef DOINLINE
static STMT *copystmt P1 (const STMT *, stmt)
{
STMT *snp;
if (stmt == NIL_STMT)
return NIL_STMT;
snp = mk_stmt (stmt->stype);
switch (stmt->stype) {
case st_return:
case st_expr:
snp->exp = stmt->exp;
break;
case st_while:
case st_do:
snp->exp = stmt->exp;
snp->s1 = stmt->s1;
break;
case st_for:
snp->exp = stmt->exp;
snp->v1.e = stmt->v1.e;
snp->s1 = stmt->s1;
snp->v2.e = stmt->v2.e;
break;
case st_if:
snp->exp = stmt->exp;
snp->s1 = stmt->s1;
snp->v1.s = stmt->v1.s;
break;
case st_switch:
snp->exp = stmt->exp;
snp->v1.s = stmt->v1.s;
break;
case st_case:
case st_default:
case st_label:
snp->v1.s = stmt->v1.s;
break;
case st_compound:
snp->s1 = stmt->s1;
break;
case st_goto:
case st_break:
case st_continue:
#ifdef ASM
case st_asm:
#endif /* ASM */
break;
default:
CANNOT_REACH_HERE ();
break;
}
snp->next = stmt->next;
return snp;
}
static STMT * copystmttree P1 (STMT *, stmt)
{
STMT *snp;
int save_global_flag = global_flag;
global_flag++;
snp = walkstmt (stmt, copystmt, copynode);
global_flag = save_global_flag;
return snp;
}
#endif /* DOINLINE */
#ifndef SYNTAX_CORRECT/* * returns TRUE if the stmt is a "NULL" statement */static BOOL is_empty_statement P1 (const STMT *, snp){ if (snp == NIL_STMT) return TRUE; switch (snp->stype) { case st_compound: return is_empty_statement (snp->s1); default: return FALSE; }}/* * check to see if the expression is a constant expression ... used * to see if conditional expressions are "invariant". */static void check_unconditional P2 (const EXPR *, ep, const char *, str){ if (ep != NIL_EXPR) { if (tst_const (ep)) { message (WARN_CONST, str); } else if ((ep->nodetype == en_test) && (ep->v.p[0]->nodetype == en_sym) && is_array_type (ep->v.p[0]->etp)) { message (WARN_ARRAY, str); } }}#endif /* SYNTAX_CORRECT *//* * whilestmt parses the c while statement. */static STMT *whilestmt P0 (void){ STMT *snp;#ifndef SYNTAX_CORRECT break_lvl++; cont_lvl++;#endif /* SYNTAX_CORRECT */ snp = mk_stmt (st_while); getsym (); needpunc (tk_openpa); snp->exp = condition_expression (); needpunc (tk_closepa); snp->s1 = statement ();#ifndef SYNTAX_CORRECT need_label = FALSE; break_lvl--; cont_lvl--;#endif /* SYNTAX_CORRECT */ return snp;}/* * dostmt parses the c do-while construct. */static STMT *dostmt P0 (void){ STMT *snp;#ifndef SYNTAX_CORRECT break_lvl++; cont_lvl++;#endif /* SYNTAX_CORRECT */ snp = mk_stmt (st_do); getsym (); snp->s1 = statement (); needpunc (kw_while); needpunc (tk_openpa); snp->exp = condition_expression (); needpunc (tk_closepa); needpunc (tk_semicolon);#ifndef SYNTAX_CORRECT need_label = FALSE; break_lvl--; cont_lvl--;#endif /* SYNTAX_CORRECT */ return snp;}static STMT *forstmt P0 (void){ STMT *snp;#ifndef SYNTAX_CORRECT break_lvl++; cont_lvl++;#endif /* SYNTAX_CORRECT */ snp = mk_stmt (st_for); getsym (); needpunc (tk_openpa); if (lang_option >= LANG_C99 && is_declaration_specifier (lastst)) { lc_auto = declaration_list (sc_auto, lc_auto); } else { snp->exp = expression ();#ifndef SYNTAX_CORRECT sequence_point (); check_discard (snp->exp);#endif /* SYNTAX_CORRECT */ needpunc (tk_semicolon); } if (lastst != tk_semicolon) { snp->v1.e = condition_expression (); } else { snp->v1.e = NIL_EXPR; } needpunc (tk_semicolon); snp->v2.e = expression ();#ifndef SYNTAX_CORRECT sequence_point (); check_discard (snp->v2.e);#endif /* SYNTAX_CORRECT */ needpunc (tk_closepa); snp->s1 = statement ();#ifndef SYNTAX_CORRECT need_label = FALSE; break_lvl--; cont_lvl--;#endif /* SYNTAX_CORRECT */ return snp;}/* * ifstmt parses the c if statement and an else clause if one is present. */static STMT *ifstmt P0 (void){ STMT *snp; snp = mk_stmt (st_if); getsym (); if (lastst == tk_openpa) {#ifndef SYNTAX_CORRECT BOOL needlab;#endif /* SYNTAX_CORRECT */ getsym (); snp->exp = condition_expression ();#ifndef SYNTAX_CORRECT check_unconditional (snp->exp, "if");#endif /* SYNTAX_CORRECT */ needpunc (tk_closepa); snp->s1 = statement ();#ifndef SYNTAX_CORRECT needlab = need_label; need_label = FALSE;#endif /* SYNTAX_CORRECT */ if (lastst == kw_else) { getsym (); snp->v1.s = statement (); } else { snp->v1.s = NIL_STMT;#ifndef SYNTAX_CORRECT /* check for a dangling else statement ... bad coding style? */ if ((snp->s1 != NIL_STMT) && (snp->s1->stype == st_if) && (snp->s1->v1.s != NIL_STMT)) { message (WARN_ELSE); }#endif /* SYNTAX_CORRECT */ }#ifndef SYNTAX_CORRECT need_label = need_label && needlab; if (is_empty_statement (snp->s1) && is_empty_statement (snp->v1.s)) { message (WARN_EMPTYIF); } } else { message (ERR_EXPREXPECT);#endif /* SYNTAX_CORRECT */ } return snp;}/* * consider the following piece of code: * * switch (i) { * case 1: * if (j) { * ..... * } else * case 2: * .... * } * * case statements may be deep inside, so we need a global variable * last_case to link them */static STMT *last_case; /* last case statement within this switch */static TYP *last_switch_type; /* type of switch controlling expression *//* * cases are returned as separate statements. for normal cases label is the * case value and v1.i is zero. for the default case v1.i is nonzero. */static STMT *casestmt P0 (void){ STMT *snp; BOOL ignore = FALSE; if (lastst == kw_case) { getsym (); snp = mk_stmt (st_case); snp->v2.i = intexpr (); /* * The constant expression in each case label is converted to the * promoted type of the controlling expression. */ if (last_switch_type) { if (!is_representable (snp->v2.i, last_switch_type)) { message (WARN_REPRESENT, (long) snp->v2.i, nameoftype (last_switch_type));
ignore = TRUE; } } } else { /* lastst is kw_default */ getsym (); snp = mk_stmt (st_default); } snp->s1 = NIL_STMT; if (!ignore) { if (last_case) { last_case->s1 = snp; } last_case = snp; } needpunc (tk_colon); snp->v1.s = statement ();#ifndef SYNTAX_CORRECT if (case_lvl == 0) { message (ERR_CASE); snp = snp->v1.s; }#endif /* SYNTAX_CORRECT */ return snp;}#ifndef SYNTAX_CORRECT/* * check_cases will check to see if any duplicate cases exist in the case list * pointed to by casehead. */static void check_cases P1 (const STMT *, casehead){ const STMT *top, *cur; for (top = casehead; top != NIL_STMT; top = top->s1) { for (cur = top->s1; cur != NIL_STMT; cur = cur->s1) { if (cur->stype == st_default) { if (top->stype == st_default) { message (ERR_DUPDEFAULT); return; } } else { if (top->stype != st_default && cur->v2.i == top->v2.i) { message (ERR_DUPCASE, cur->v2.i); return; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -