typedef struct ProgramS *Program;
typedef struct BodyS *Body;
typedef struct DecListS *DecList;
typedef struct DecS *Dec;
typedef struct VarDecListS *VarDecList;
typedef struct VarDecS *VarDec;
typedef struct TypeDecListS *TypeDecList;
typedef struct TypeDecS *TypeDec;
typedef struct ProcDecListS *ProcDecList;
typedef struct ProcDecS *ProcDec;
typedef struct TypeS *Type; 
typedef struct ComponentListS *ComponentList;
typedef struct ComponentS *Component;
typedef struct FormalParamListS *FormalParamList;
typedef struct FormalParamS *FormalParam;
typedef struct StatListS *StatList;
typedef struct StatS *Stat;
typedef struct ExpListS *ExpList;
typedef struct ExpS *Exp;
typedef struct RecordInitListS *RecordInitList;
typedef struct RecordInitS *RecordInit;
typedef struct ArrayInitListS *ArrayInitList;
typedef struct ArrayInitS *ArrayInit;
typedef struct LvalueListS *LvalueList;
typedef struct LvalueS *Lvalue;

typedef enum {GT=0,LT,EQ,GE,LE,NE,PLUS,MINUS,TIMES,SLASH,DIV,MOD,AND,OR} binop;

typedef enum {UPLUS,UMINUS,NOT} unop;

typedef char *id, *string;

struct ProgramS {
	Body b;
	}; 

struct BodyS {
	int line;
	DecList dl;
	Stat s;
	}; 

struct DecListS {
	Dec d;
	DecList next;
	}; 

struct DecS {
	enum{VarDecs=0,TypeDecs,ProcDecs} kind;
	union {
		struct {
			VarDecList vl;
			} vardecs;
		struct {
			TypeDecList tl;
			} typedecs;
		struct {
			ProcDecList pl;
			} procdecs;
		} u;
	};

struct VarDecListS {
	VarDec v;
	VarDecList next;
	}; 

struct VarDecS {
	int line;
	id i;
	Type t;
	Exp e;
	}; 

struct TypeDecListS {
	TypeDec t;
	TypeDecList next;
	}; 

struct TypeDecS {
	int line;
	id i;
	Type t;
	}; 

struct ProcDecListS {
	ProcDec p;
	ProcDecList next;
	}; 

struct ProcDecS {
	int line;
	id i;
	FormalParamList fl;
	Type t;
	Body b;	
	}; 

struct TypeS {
	int line;
	enum{NamedTyp=0,ArrayTyp,RecordTyp} kind;
	union {
		struct {
			id i;
			} namedtyp;
		struct {
			Type t;
			} arraytyp;
           	struct {
	                ComponentList cl;
		        } recordtyp;
		} u;
	};
 
struct ComponentListS {
        Component c;
        ComponentList next;
        };

struct ComponentS {
        int line;
        id i;
        Type t;
        };

struct FormalParamListS {
	FormalParam f;
	FormalParamList next;
	}; 

struct FormalParamS {
	int line;
	id i;
	Type t;
	}; 

struct StatListS {
	Stat s;
	StatList next;
	}; 

struct StatS {
	int line;
	enum{AssignSt=0,CallSt,ReadSt,WriteSt,IfSt,WhileSt,LoopSt,ForSt,ExitSt,RetSt,SeqSt} kind;
	union {
		struct {
			Lvalue l;
			Exp e;
			} assignst; 
		struct {
			id i;
			ExpList el;
			} callst; 
		struct {
			LvalueList ll;
			} readst; 
		struct {
			ExpList el;
			} writest; 
		struct {
			Exp e;
			Stat s1, s2;
			} ifst; 
		struct {
		        Exp e;
			Stat s;
		       } whilest;
		struct {
		        Stat s;
		       } loopst;
		struct {
			id i;
			Exp e1, e2, e3;
			Stat s;
			} forst; 
		struct {
			Exp e;
			} retst; 
		struct {
			StatList sl;
			} seqst; 
		} u;
	}; 

struct ExpListS {
	Exp e;
	ExpList next;
	}; 

struct ExpS {
	int line;
	enum{BinOpExp=0,UnOpExp,LvalExp,CallExp,RecordExp,ArrayExp,IntConst,RealConst,StringConst} kind;
	union {
		struct {
			binop b;
			Exp e1, e2;
			} binopexp; 
		struct {
			unop u;
			Exp e;
			} unopexp; 
		struct {
			Lvalue l;
			} lvalexp; 
		struct {
			id i;
			ExpList el;
			} callexp; 
     	        struct {
		        id i;
		        RecordInitList rl;
      		       } recordexp;
		struct {
			id i;
			ArrayInitList al;
			} arrayexp; 
		struct {
			int i;
			} intconstexp; 
		struct {
		        string r;
		        } realconstexp;
		struct {
			string c;
			} stringconstexp; 
		} u;
	}; 

struct RecordInitListS {
        RecordInit r;
        RecordInitList next;
        };

struct RecordInitS {
        id i;
        Exp e;
        };        

struct ArrayInitListS {
	ArrayInit a;
	ArrayInitList next;
	}; 

struct ArrayInitS {
	Exp e1, e2;
	}; 

struct LvalueListS {
	Lvalue l;
	LvalueList next;
	}; 

struct LvalueS {
	int line;
	enum{Var=0,ArrayDeref,RecordDeref} kind;
	union {
		struct {
			id i;
			} var;
		struct {
			Lvalue l;
			Exp e;
			} arrayderef; 
                struct {
		        Lvalue l;
                        id i;
	        	} recordderef;
		}u;
	};



/* constructor functions for asts */

Program mk_Program(Body b);
Body mk_Body(int line, DecList dl, Stat s); 
DecList mk_DecList(Dec d, DecList next); 
Dec mk_VarDecs(VarDecList vl); 
Dec mk_TypeDecs(TypeDecList tl); 
Dec mk_ProcDecs(ProcDecList pl); 
VarDecList mk_VarDecList(VarDec v, VarDecList next);
VarDec mk_VarDec(int line,id i, Type t, Exp e); 
TypeDecList mk_TypeDecList(TypeDec t, TypeDecList next);
TypeDec mk_TypeDec(int line, id i, Type t);
ProcDecList mk_ProcDecList(ProcDec p, ProcDecList next);
ProcDec mk_ProcDec(int line, id i, FormalParamList fl, Type t, Body b);
Type mk_NamedType(int line,id i); 
Type mk_ArrayType(int line,Type t);
Type mk_RecordType(int line,ComponentList cl);
ComponentList mk_ComponentList(Component c, ComponentList next);
Component mk_Component(int line, id i, Type t);
FormalParamList mk_FormalParamList(FormalParam f, FormalParamList next);
FormalParam mk_FormalParam(int line, id i, Type t); 
StatList mk_StatList(Stat s, StatList next);
Stat mk_AssignStat(int line, Lvalue l, Exp e); 
Stat mk_CallStat(int line, id i, ExpList el);
Stat mk_ReadStat(int line, LvalueList ll);
Stat mk_WriteStat(int line, ExpList el);
Stat mk_IfStat(int line, Exp e, Stat s1, Stat s2);
Stat mk_WhileStat(int line, Exp e, Stat s1);
Stat mk_LoopStat(int line, Stat s1);
Stat mk_ForStat(int line, id i, Exp e1, Exp e2, Exp e3, Stat s1);
Stat mk_ExitStat(int line);
Stat mk_RetStat(int line, Exp e);
Stat mk_SeqStat(StatList sl);
ExpList mk_ExpList(Exp e, ExpList next);
Exp mk_BinOpExp(int line, binop b, Exp e1, Exp e2); 
Exp mk_UnOpExp(int line, unop u, Exp e1);
Exp mk_LvalExp(int line, Lvalue l);
Exp mk_CallExp(int line, id i, ExpList el);
Exp mk_ArrayExp(int line, id i, ArrayInitList al);
Exp mk_RecordExp(int line, id i, RecordInitList rl);
Exp mk_IntConstExp(int line, int i);
Exp mk_RealConstExp(int line, string r);
Exp mk_StringConstExp(int line, string c);
RecordInitList mk_RecordInitList(RecordInit r, RecordInitList next);
RecordInit mk_RecordInit(id i, Exp e);
ArrayInitList mk_ArrayInitList(ArrayInit a, ArrayInitList next);
ArrayInit mk_ArrayInit(Exp e1, Exp e2); 
LvalueList mk_LvalueList(Lvalue l, LvalueList next);
Lvalue mk_VarLvalue(int line, id i);
Lvalue mk_ArrayDerefLvalue(int line, Lvalue l1, Exp e);
Lvalue mk_RecordDerefLvalue(int line, Lvalue l1, id i);

char *strsave(char *s);

/* print program tree  */
void print_Program(FILE *out,Program p);

