/* autogenerated by john pongsajapan */
#include "stdio.h"
#include "ast.h"
#include "traverse.h"

#include "verify.h"

extern int GLOBAL_lineno;

void 
traverse_ID_Type(ID_Type * p, char *myID, int level)
{
	ID_Type *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
}

void 
traverse_Program(Program * p, char *myID, int level)
{
	Program *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	newFrame();
	traverse_DecList(p->decList, "decList", level + 1);
	traverse_SubList(p->subList, "subList", level + 1);
	traverse_StmBlock(p->stmBlock, "stmBlock", level + 1);
	endFrame();
	if (strcmp(this->idt.id, this->end_idt.id)) {
		sym_mismatch(this->idt._lineno, this->end_idt._lineno);
	}
}

void 
traverse_IDList(IDList * p, char *myID, int level)
{
	IDList *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_list_IDList(p, myID, level);
}

void 
traverse_list_IDList(IDList * p, char *myID, int level)
{
	while (p) {
		p = p->next;
	}
}

void 
traverse_Bound(Bound * p, char *myID, int level)
{
	Bound *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	if (this->idt.id)
		this->Value = getIntValue(this->idt.id) - this->partial;
}

void 
traverse_BoundInfo(BoundInfo * p, char *myID, int level)
{
	BoundInfo *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_Bound(p->lower_bound, "lower_bound", level + 1);
	traverse_Bound(p->upper_bound, "upper_bound", level + 1);
}

void 
traverse_BoundList(BoundList * p, char *myID, int level)
{
	BoundList *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_list_BoundList(p, myID, level);
}

void 
traverse_list_BoundList(BoundList * p, char *myID, int level)
{
	while (p) {
		traverse_BoundInfo(p->bound, "bound", level + 0);
		p = p->next;
	}
}

void 
traverse_DeclType(DeclType * p, char *myID, int level)
{
	DeclType *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_BoundList(p->_arraybounds, "_arraybounds", level + 1);
	traverse_ArrayDataType(p->arrayDataType, "arrayDataType", level + 1);
	if (this->arrayDataType) {
		this->_type = this->arrayDataType->Type + 4;
		this->_arraybounds = this->arrayDataType->boundList;
	} else
		this->_type = this->basicDataType;
}

void 
traverse_ArrayDataType(ArrayDataType * p, char *myID, int level)
{
	ArrayDataType *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_BoundList(p->boundList, "boundList", level + 1);
}

void 
traverse_VarDec(VarDec * p, char *myID, int level)
{
	VarDec *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_IDList(p->idList, "idList", level + 1);
	traverse_DeclType(p->declType, "declType", level + 1);
	declareIDlist(this->idList,
		      this->declType->_type,
		      this->declType->_arraybounds);
}

void 
traverse_ConstDec(ConstDec * p, char *myID, int level)
{
	ConstDec *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_IDList(p->idList, "idList", level + 1);
	traverse_LitExp(p->litExp, "litExp", level + 1);
	if (this->idt.id) {
		checkID(&this->idt, TYPE_CONST);
		this->litExp = getLitExp(this->idt.id);
	}
	declareIDlist_const(this->idList, this->litExp);
}

void 
traverse_Dec(Dec * p, char *myID, int level)
{
	Dec *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_VarDec(p->varDec, "varDec", level + 1);
	traverse_ConstDec(p->constDec, "constDec", level + 1);
}

void 
traverse_DecList(DecList * p, char *myID, int level)
{
	DecList *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_list_DecList(p, myID, level);
}

void 
traverse_list_DecList(DecList * p, char *myID, int level)
{
	while (p) {
		traverse_Dec(p->dec, "dec", level + 0);
		p = p->next;
	}
}

void 
traverse_ArgSetList(ArgSetList * p, char *myID, int level)
{
	ArgSetList *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_list_ArgSetList(p, myID, level);
}

void 
traverse_list_ArgSetList(ArgSetList * p, char *myID, int level)
{
	while (p) {
		traverse_VarDec(p->argset, "argset", level + 0);
		p = p->next;
	}
}

void 
traverse_Sub(Sub * p, char *myID, int level)
{
	Sub *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	newFrame();
	traverse_SubHeading(p->heading, "heading", level + 1);
	traverse_StmBlock(p->body, "body", level + 1);
	endFrame();
	if (strcmp(this->heading->idt.id, this->end_idt.id)) {
		sym_mismatch(this->heading->idt._lineno, this->end_idt._lineno);
	}
}

void 
traverse_SubParams(SubParams * p, char *myID, int level)
{
	SubParams *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_ArgSetList(p->val_params, "val_params", level + 1);
	traverse_ArgSetList(p->ref_params, "ref_params", level + 1);
}

void
traverse_SubHeading(SubHeading * p, char *myID, int level)
{
        SubHeading *this = p;
        if (!p)
                return;
        GLOBAL_lineno = p->_lineno;
        traverse_DeclType(p->return_type, "return_type", level + 1);
        declareSub(&this->idt, this->subParams, this->return_type->_type,
this->return_type->_arraybounds);
        traverse_SubParams(p->subParams, "subParams", level + 1);
}

void 
traverse_SubList(SubList * p, char *myID, int level)
{
	SubList *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_list_SubList(p, myID, level);
}

void 
traverse_list_SubList(SubList * p, char *myID, int level)
{
	while (p) {
		traverse_Sub(p->subroutine, "subroutine", level + 0);
		p = p->next;
	}
}

void 
traverse_AssignStm(AssignStm * p, char *myID, int level)
{
	AssignStm *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_BoundList(p->_arraybounds, "_arraybounds", level + 1);
	traverse_VarExp(p->var, "var", level + 1);
	traverse_Exp(p->expr, "expr", level + 1);
	handle_cast(this->var->_type, this->expr);
}

void 
traverse_ReadStm(ReadStm * p, char *myID, int level)
{
	ReadStm *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_VarExp(p->var, "var", level + 1);
	checkID(&this->var->idt, TYPE_MUTABLE);
}

void 
traverse_WriteStm(WriteStm * p, char *myID, int level)
{
	WriteStm *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_ExpList(p->list, "list", level + 1);
}

void 
traverse_WritelnStm(WritelnStm * p, char *myID, int level)
{
	WritelnStm *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_ExpList(p->list, "list", level + 1);
}

void 
traverse_If_Then_Stm(If_Then_Stm * p, char *myID, int level)
{
	If_Then_Stm *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_Exp(p->condition, "condition", level + 1);
	if (this->condition->_arraybounds)
		doError("If on array");
	handle_cast(TYPE_bool, this->condition);
	traverse_StmList(p->then_clause, "then_clause", level + 1);
}

void 
traverse_If_Then_Else_Stm(If_Then_Else_Stm * p, char *myID, int level)
{
	If_Then_Else_Stm *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_Exp(p->condition, "condition", level + 1);
	if (this->condition->_arraybounds)
		doError("If on array");
	handle_cast(TYPE_bool, this->condition);
	traverse_StmList(p->then_clause, "then_clause", level + 1);
	traverse_StmList(p->else_clause, "else_clause", level + 1);
}

void 
traverse_WhileStm(WhileStm * p, char *myID, int level)
{
	WhileStm *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_Exp(p->condition, "condition", level + 1);
	if (this->condition->_arraybounds)
		doError("While on array");
	traverse_StmList(p->body, "body", level + 1);
}

void 
traverse_ReturnStm(ReturnStm * p, char *myID, int level)
{
	ReturnStm *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_Exp(p->expr, "expr", level + 1);
	handle_return(this->expr);
}

void 
traverse_Stm(Stm * p, char *myID, int level)
{
	Stm *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_AssignStm(p->assignStm, "assignStm", level + 1);
	traverse_ReadStm(p->read, "read", level + 1);
	traverse_WriteStm(p->write, "write", level + 1);
	traverse_WritelnStm(p->writeln, "writeln", level + 1);
	traverse_If_Then_Stm(p->if_then, "if_then", level + 1);
	traverse_If_Then_Else_Stm(p->if_then_else, "if_then_else", level + 1);
	traverse_WhileStm(p->whileStm, "whileStm", level + 1);
	traverse_ReturnStm(p->returnStm, "returnStm", level + 1);
	traverse_StmBlock(p->stmBlock, "stmBlock", level + 1);
}

void 
traverse_StmList(StmList * p, char *myID, int level)
{
	StmList *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_list_StmList(p, myID, level);
}

void 
traverse_list_StmList(StmList * p, char *myID, int level)
{
	while (p) {
		traverse_Stm(p->stm, "stm", level + 0);
		p = p->next;
	}
}

void 
traverse_StmBlock(StmBlock * p, char *myID, int level)
{
	StmBlock *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	dupFrame();
	traverse_SubList(p->subList, "subList", level + 1);
	traverse_DecList(p->decList, "decList", level + 1);
	traverse_StmList(p->stmList, "stmList", level + 1);
	endFrame();
}

void 
traverse_LitExp(LitExp * p, char *myID, int level)
{
	LitExp *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_BoundList(p->_arraybounds, "_arraybounds", level + 1);
	this->_type = this->Type;
}

void 
traverse_SubCallExp(SubCallExp * p, char *myID, int level)
{
	SubCallExp *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_BoundList(p->_arraybounds, "_arraybounds", level + 1);
	traverse_ExpList(p->expList, "expList", level + 1);
	this->_type = getSubType(this->idt.id);
	this->_type = getSubType(this->idt.id);
	{
		SubParams *sp = getSubParams(this->idt.id);
		ArgSetList *l = sp->val_params;
		ExpList *el = this->expList;
		IDList *idl;
		while (l && el) {
			idl = l->argset->idList;
			while (idl && el) {
				handle_cast(l->argset->declType->_type, el->exp);
				idl = idl->next;
				el = el->next;
			}
			l = l->next;
		}
		if (idl) {
			doError("Too few arguments!");
		}
		l = sp->ref_params;
		while (l && el) {
			idl = l->argset->idList;
			while (idl && el) {
				if (!el->exp->varExp) {
					doError("Need variable to be passed by reference!");
				}
				handle_cast(l->argset->declType->_type, el->exp);
				idl = idl->next;
				el = el->next;
			}
			l = l->next;
		}
		if (idl) {
			doError("Too few arguments!");
		}
		if (el) {
			doError("Too many arguments!");
		}
	}
}

void 
traverse_VarExp(VarExp * p, char *myID, int level)
{
	VarExp *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_BoundList(p->_arraybounds, "_arraybounds", level + 1);
	traverse_ExpList(p->offsets, "offsets", level + 1);
	this->_arraybounds = getBounds(this->idt.id);
	checkID(&this->idt, TYPE_ANY);
	if (this->offsets) {
		ExpList *p = this->offsets;
		BoundList *b = this->_arraybounds;
		while (p && b) {
			if (p->exp->_type != TYPE_int)
				doError("Array index not int");
			p = p->next;
			b = b->next;
		}
		if (p || b) {
			doError("Incorrect dimensions!:");
		}
	}
	this->_type = getType(this->idt.id);
	if (this->offsets && (this->_type >= 4))
		this->_type -= 4;
}

void 
traverse_LogicExp(LogicExp * p, char *myID, int level)
{
	LogicExp *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_BoundList(p->_arraybounds, "_arraybounds", level + 1);
	traverse_Exp(p->x, "x", level + 1);
	traverse_Exp(p->y, "y", level + 1);
	handle_logicexp(this->op, this->x, this->y, this);
}

void 
traverse_ArithExp(ArithExp * p, char *myID, int level)
{
	ArithExp *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_BoundList(p->_arraybounds, "_arraybounds", level + 1);
	traverse_Exp(p->x, "x", level + 1);
	traverse_Exp(p->y, "y", level + 1);
	handle_arithexp(this->op, this->x, this->y, this);
}

void 
traverse_RelExp(RelExp * p, char *myID, int level)
{
	RelExp *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_BoundList(p->_arraybounds, "_arraybounds", level + 1);
	traverse_Exp(p->x, "x", level + 1);
	traverse_Exp(p->y, "y", level + 1);
	handle_relexp(this->op, this->x, this->y, this);
}

void 
traverse_Exp(Exp * p, char *myID, int level)
{
	Exp *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_BoundList(p->_arraybounds, "_arraybounds", level + 1);
	traverse_VarExp(p->varExp, "varExp", level + 1);
	traverse_LitExp(p->litExp, "litExp", level + 1);
	traverse_SubCallExp(p->callExp, "callExp", level + 1);
	traverse_LogicExp(p->logicExp, "logicExp", level + 1);
	traverse_ArithExp(p->arithExp, "arithExp", level + 1);
	traverse_RelExp(p->relExp, "relExp", level + 1);
	traverse_Exp(p->nestedExp, "nestedExp", level + 1);
#define propExp(x) if (this->x) { this->_type = this->x->_type; this->_arraybounds = this->x->_arraybounds; }
	propExp(varExp);
	propExp(litExp);
	propExp(callExp);
	propExp(logicExp);
	propExp(arithExp);
	propExp(relExp);
	propExp(nestedExp);
}

void 
traverse_ExpList(ExpList * p, char *myID, int level)
{
	ExpList *this = p;
	if (!p)
		return;
	GLOBAL_lineno = p->_lineno;
	traverse_list_ExpList(p, myID, level);
}

void 
traverse_list_ExpList(ExpList * p, char *myID, int level)
{
	while (p) {
		traverse_Exp(p->exp, "exp", level + 0);
		p = p->next;
	}
}
