ref: deed2f68c71afdeb172a8362c6c9d3f3b9f60c4b
dir: /cc1/stmt.c/
#include <stddef.h> #include <inttypes.h> #include <setjmp.h> #include <stdio.h> #include "../inc/cc.h" #include "../inc/sizes.h" #include "cc1.h" Symbol *curfun; static void stmt(Symbol *lbreak, Symbol *lcont, Caselist *lswitch); static void label(void) { Symbol *sym; switch (yytoken) { case IDEN: case TYPEIDEN: sym = lookup(NS_LABEL, yytext); if (sym->flags & ISDEFINED) error("label '%s' already defined", yytoken); if ((sym->flags & ISDECLARED) == 0) sym = install(NS_LABEL, sym); sym->flags |= ISDEFINED; emit(OLABEL, sym); next(); expect(':'); break; default: unexpected(); } } static void stmtexp(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { if (accept(';')) return; if (ahead() == ':') { label(); stmt(lbreak, lcont, lswitch); return; } emit(OEXPR, expr()); expect(';'); } static void While(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { Symbol *begin, *cond, *end; Node *np; begin = newlabel(); end = newlabel(); cond = newlabel(); expect(WHILE); np = condition(); emit(OJUMP, cond); emit(OBLOOP, NULL); emit(OLABEL, begin); stmt(end, begin, lswitch); emit(OLABEL, cond); emit(OBRANCH, begin); emit(OEXPR, np); emit(OELOOP, NULL); emit(OLABEL, end); } static void For(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { Symbol *begin, *cond, *end; Node *econd, *einc, *einit; begin = newlabel(); end = newlabel(); cond = newlabel(); expect(FOR); expect('('); einit = (yytoken != ';') ? expr() : NULL; expect(';'); econd = (yytoken != ';') ? exp2cond(expr(), 0) : NULL; expect(';'); einc = (yytoken != ')') ? expr() : NULL; expect(')'); emit(OEXPR, einit); emit(OJUMP, cond); emit(OBLOOP, NULL); emit(OLABEL, begin); stmt(end, begin, lswitch); emit(OEXPR, einc); emit(OLABEL, cond); emit(OBRANCH, begin); emit(OEXPR, econd); emit(OELOOP, NULL); emit(OLABEL, end); } static void Dowhile(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { Symbol *begin, *end; Node *np; begin = newlabel(); end = newlabel(); expect(DO); emit(OBLOOP, NULL); emit(OLABEL, begin); stmt(end, begin, lswitch); expect(WHILE); np = condition(); emit(OBRANCH, begin); emit(OEXPR, np); emit(OELOOP, NULL); emit(OLABEL, end); } static void Return(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { Node *np; Type *tp = curfun->type->type; expect(RETURN); np = (yytoken != ';') ? eval(expr()) : NULL; expect(';'); if (!np) { if (tp != voidtype) warn("function returning non void returns no value"); tp = voidtype; } else if (np->type != tp) { if (tp == voidtype) warn("function returning void returns a value"); else if ((np = convert(np, tp, 0)) == NULL) error("incorrect type in return"); } emit(ORET, tp); emit(OEXPR, np); } static void Break(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { expect(BREAK); if (!lbreak) error("break statement not within loop or switch"); emit(OJUMP, lbreak); expect(';'); } static void Continue(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { expect(CONTINUE); if (!lcont) error("continue statement not within loop"); emit(OJUMP, lcont); expect(';'); } static void Goto(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { Symbol *sym; namespace = NS_LABEL; next(); namespace = NS_IDEN; if (yytoken != IDEN) unexpected(); sym = yylval.sym; if ((sym->flags & ISDECLARED) == 0) sym = install(NS_LABEL, sym); sym->flags |= ISUSED; emit(OJUMP, sym); next(); expect(';'); } static void Switch(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { Caselist lcase = {.nr = 0, .head = NULL, .deflabel = NULL}; Node *cond; expect(SWITCH); expect ('('); cond = eval(expr()); /* TODO: why can I not call directly to convert here? */ switch (BTYPE(cond)) { case INT: case ENUM: cond = convert(cond, inttype, 0); break; default: error("incorrect type in switch statement"); } expect (')'); lcase.expr = cond; lcase.lbreak = newlabel(); lcase.ltable = newlabel(); emit(OSWITCH, &lcase); stmt(lbreak, lcont, &lcase); emit(OJUMP, lcase.lbreak); emit(OLABEL, lcase.ltable); emit(OSWITCHT, &lcase); emit(OLABEL, lcase.lbreak); } static void Case(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { Node *np; struct scase *pcase; expect(CASE); if (!lswitch) error("case label not within a switch statement"); if ((np = iconstexpr()) == NULL) error("case label does not reduce to an integer constant"); expect(':'); pcase = xmalloc(sizeof(*pcase)); pcase->expr = np; pcase->next = lswitch->head; emit(OLABEL, pcase->label = newlabel()); lswitch->head = pcase; if (++lswitch->nr == NR_SWITCH) error("too case labels for a switch statement"); stmt(lbreak, lcont, lswitch); } static void Default(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { Symbol *ldefault = newlabel(); expect(DEFAULT); expect(':'); emit(OLABEL, ldefault); lswitch->deflabel = ldefault; ++lswitch->nr; stmt(lbreak, lcont, lswitch); } static void If(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { Symbol *end, *lelse; Node *np; lelse = newlabel(); expect(IF); np = condition(); emit(OBRANCH, lelse); emit(OEXPR, negate(np)); stmt(lbreak, lcont, lswitch); if (accept(ELSE)) { end = newlabel(); emit(OJUMP, end); emit(OLABEL, lelse); stmt(lbreak, lcont, lswitch); emit(OLABEL, end); } else { emit(OLABEL, lelse); } } static void blockit(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { switch (yytoken) { case TYPEIDEN: if (ahead() == ':') goto parse_stmt; /* PASSTHROUGH */ case TYPE: case TQUALIFIER: case SCLASS: decl(); return; default: parse_stmt: stmt(lbreak, lcont, lswitch); } } void compound(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { static int nested; pushctx(); expect('{'); if (nested == NR_BLOCK) error("too nesting levels of compound statements"); ++nested; for (;;) { if (yytoken == '}') break; blockit(lbreak, lcont, lswitch); } --nested; popctx(); /* * curctx == GLOBALCTX+1 means we are at the end of a function * so we have to pop the context related to the parameters */ if (curctx == GLOBALCTX+1) popctx(); expect('}'); } static void stmt(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { void (*fun)(Symbol *, Symbol *, Caselist *); switch (yytoken) { case '{': fun = compound; break; case RETURN: fun = Return; break; case WHILE: fun = While; break; case FOR: fun = For; break; case DO: fun = Dowhile; break; case IF: fun = If; break; case BREAK: fun = Break; break; case CONTINUE: fun = Continue; break; case GOTO: fun = Goto; break; case SWITCH: fun = Switch; break; case CASE: fun = Case; break; case DEFAULT: fun = Default; break; default: fun = stmtexp; break; } (*fun)(lbreak, lcont, lswitch); }