ref: b030a1fcb12be82e5c78e76c3a9a3eb76879334c
dir: /flow.c/
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include "cc.h"
#include "symbol.h"
#include "tokens.h"
#include "syntax.h"
#include "sizes.h"
static struct node *stmt(void);
static unsigned char blocks[NR_BLOCK];
static unsigned char *blockp = blocks;
struct symbol *curfun;
static void
push(register unsigned char b)
{
if (blockp == &blocks[NR_BLOCK])
error("Too much nesting levels");
*blockp++ = b;
}
static void
pop(void)
{
assert(blockp >= blocks);
--blockp;
}
static struct node *
Goto(void)
{
register struct node *np;
register struct symbol *sym;
expect(GOTO);
expect(IDEN);
sym = lookup(yytext, NS_LABEL);
np = node(OGOTO, nodesym(sym), NULL);
expect(';');
return np;
}
static struct node *
While(void)
{
register struct node *cond, *np;
expect(WHILE);
expect('(');
cond = expr();
expect(')');
push(OWHILE);
np = node(OWHILE, cond, stmt());
pop();
return np;
}
static struct node *
Do(void)
{
register struct node *cond, *body, *np;
expect(DO);
body = stmt();
expect(WHILE);
expect('(');
cond = expr();
expect(')');
expect(';');
push(ODO);
np = node(ODO, body, cond);
pop();
return np;
}
static struct node *
For(void)
{
register struct node *exp1, *exp2, *exp3;
struct node *np;
expect(FOR);
expect('(');
exp1 = expr();
expect(';');
exp2 = expr();
expect(';');
exp3 = expr();
expect(')');
push(OFOR);
np = node(OFOR, exp1,
node(O2EXP, exp2,
node(O2EXP, exp3, stmt())));
pop();
return np;
}
static struct node *
If(void)
{
register struct node *cond, *body;
expect(IF);
expect('(');
cond = expr();
expect(')');
body = stmt();
return node(OIF, cond,
node(O2EXP, body, (accept(ELSE)) ? stmt() : NULL));
}
static struct node *
Switch(void)
{
register struct node *cond, *np;
expect(SWITCH);
expect('(');
cond = expr();
expect(')');
push(OSWITCH);
np = node(OSWITCH, cond, stmt());
pop();
return np;
}
static struct node *
label(void)
{
register struct symbol *sym = lookup(yytext, NS_LABEL);
/* TODO: detect repeated labels */
/* TODO: install in symbol table */
next(), next(); /* skip IDEN and ':' */
return node(OLABEL, nodesym(sym), stmt());
}
static struct node *
Break(void)
{
expect(BREAK);
expect(';');
if (blockp == blocks)
error("break statement not within loop or switch");
return node(OBREAK, NULL, NULL);
}
static struct node *
Continue(void)
{
register unsigned char *bp;
expect(CONTINUE);
expect(';');
for (bp = blocks; bp < blockp && *bp == OSWITCH; ++bp)
; /* nothing */
if (bp == blockp)
error("continue statement not within loop");
return node(OCONT, NULL, NULL);
}
static struct node *
Return(void)
{
register struct node *np;
expect(RETURN);
np = expr();
expect(';');
return node(ORETURN, np, NULL);
}
static struct node *
Case(void)
{
register unsigned char *bp;
register struct node *np, *exp;
expect(CASE);
exp = expr();
/* TODO: check if exp is constant */
/* TODO: Check if the type is correct */
for (bp = blocks; bp < blockp && *bp != OSWITCH; ++bp)
; /* nothing */
if (bp == blockp)
error("case statement not within switch");
np = node(OCASE, exp, NULL);
expect(':');
return np;
}
static struct node *
Default(void)
{
register unsigned char *bp;
expect(DEFAULT);
for (bp = blocks; bp < blockp && *bp != OSWITCH; ++bp)
; /* nothing */
if (bp == blockp)
error("default statement not within switch");
expect(':');
return node(ODEFAULT, NULL, NULL);
}
static struct node *
compound(void)
{
expect('{');
repeat: switch (yytoken) {
case TYPE: case SCLASS: case TQUALIFIER:
decl();
goto repeat;
case '}':
next();
return NULL;
default:
stmt();
goto repeat;
}
}
static struct node *
stmt(void)
{
register struct node *np;
switch (yytoken) {
case '{': return context(compound);
case SWITCH: return Switch();
case IF: return If();
case FOR: return For();
case DO: return Do();
case WHILE: return While();
case CONTINUE: return Continue();
case BREAK: return Break();
case RETURN: return Return();
case GOTO: return Goto();
case CASE: return Case();
case DEFAULT: return Default();
case IDEN: if (ahead() == ':') return label();
}
np = expr();
expect(';');
return np;
}
struct node *
function(void)
{
return node(OFTN, compound(), NULL);
}