shithub: scc

ref: f5ecaab1bde3f51e6ccce10416530d5b29b4e84b
dir: /flow.c/

View raw version

#include <assert.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;
static 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);

	if (sym->label)
		error("label '%s' already defined", yytext);
	insert(sym, CTX_FUNC);
	sym->label = 1;
	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)
{
	register struct node *np;
	unsigned char nodecl = 0;
	struct compound c;

	c.tree = NULL;
	expect('{');
	new_ctx();
	while (!accept('}')) {
		if (np = decl(0)) {
			if (nodecl) {
				warn(options.mixdcls,
				     "mixed declarations and code");
			}
		} else {
			np = stmt();
			nodecl = 1;
		}
		addstmt(&c, np);
	}
	del_ctx();

	return c.tree;
}

static struct node *
stmt(void)
{
	register struct node *np;

	switch (yytoken) {
	case '{':      return 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(register struct symbol *sym)
{
	curfun = sym;
	return node(OFTN, compound(), NULL);
}

void
run(register struct node *np)
{
	prtree(np);
	putchar('\n');
	freesyms();
}