Benjamin Ranck

::::::::::::::
alltext.txt
::::::::::::::
::::::::::::::
debug.c
::::::::::::::
/*
 * debug.c - print messages from various file streams safely
 * $Id: debug.c,v 1.6 2002/10/31 02:45:06 mathomas Exp $
 */
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <errno.h>
#include "debug.h"

/*
 * print error and terminate program 
 */

void
die(const char *msg)
{
        perror(msg);
        exit(errno);
}

/* 
 * stdout printing wrapper 
 */

void 
dump(const char *fmt, ...)
{
        va_list args;

        if(!fmt)
                return;

        va_start(args, fmt);
        (void) vfprintf(stdout, fmt, args);
        va_end(args);

        (void) fflush(stdout);
}

/* 
 * stderr printing wrapper 
 */

void 
error(const char *fmt, ...)
{
        va_list args; 
        
        if(!fmt)
                return; 
                
        va_start(args, fmt);
        (void) fprintf(stderr, "error: ");
        (void) vfprintf(stderr, fmt, args);
        va_end(args);

        (void) fflush(stderr);
}

/*
 * stderr printing wrapper and clean exit 
 */

void 
fatal(const char *fmt, ...)
{
        va_list args;

        if(!fmt)
                exit(EXIT_FAILURE);

        va_start(args, fmt);
        (void) fprintf(stderr, "fatal: ");
        (void) vfprintf(stderr, fmt, args);
        va_end(args);

        (void) fflush(stderr);
        (void) fflush(stdout);

        exit(EXIT_FAILURE);
}

::::::::::::::
evalTree.c
::::::::::::::
/*
 * Author Ben Ranck
 * Evaluation Tree
 */

#include "evalTree.h"
#include <stdio.h>

SymbolTable * symTab;
/* These global vars used to control loops and so forth*/
	int breaknode = 0;
	int continuenode = 0;

int
evalTree(NODE * root, SymbolTable * sym) {
    	symTab = sym; 
        return eval(root);
}

/*
 * Runs recursively down the tree and evaluates depending on node type
 * evaluations which require a single line are within the function else they
 * are passed off to specific evaluation functions
 */

int
eval(NODE * node) {

	int switchInt = node->sNodeType;
    	int res = NULL;

    	switch(switchInt) {
    	case(NODE_ASSIGN) :
        	/* Assignment will have a left child type variable so we can go straigh to it's value */
        	res = symTab->entries[node->NodeLeft->sTableIndex].value = eval(node->NodeRight);
        	break;
    	case(NODE_BREAK) :
            breaknode = !breaknode;
            break;
    	case(NODE_PROGRAM) :
            res = evalProgram(node);
            break;
        case(NODE_CONTINUE) :
            continuenode = !continuenode;
            /* By using '!' operator can take care of nested	cases */
            break;
        case(NODE_EQ_OP) :
            res = ( eval(node->NodeLeft) == eval(node->NodeRight) );
            break;
        case(NODE_GT_OP) :
            res = ( eval(node->NodeLeft) > eval(node->NodeRight) );
            break;
        case(NODE_VARIABLE) :
            res = (symTab->entries[node->sTableIndex].value);
            break;
        case(NODE_DECLARATION) :
            /* If right tree is not NULL then declarition is also initialization */
            if(node->NodeRight != NULL)
                symTab->entries[node->NodeLeft->sTableIndex].value = eval(node->NodeRight);
            break;
        case(NODE_NUMBER) :
            res  = node->vari.sValue;
            break;
        case(NODE_LT_OP) :
            res = ( eval(node->NodeLeft) < eval(node->NodeRight) );
            break;
        case(NODE_WHILE) :
            res = evalWhile(node);
            break;
        case(NODE_SUB_OP) :
            res = ( eval(node->NodeLeft) - eval(node->NodeRight) );
            break;
        case(NODE_NEG_OP) :
            res = -(eval(node->NodeLeft));
            break;
        case(NODE_NOT_OP) :
            res = !(eval(node->NodeLeft));
            break;
        case(NODE_IF) :
            res = evalIf(node);
            break;
        case(NODE_OR_OP) :
            res = ( eval(node->NodeLeft) || eval(node->NodeRight) );
            break;
        case(NODE_AND_OP) :
            res = ( eval(node->NodeLeft) && eval(node->NodeRight) );
            break;
        case(NODE_MOD_OP) :
            res = ( eval(node->NodeLeft) % eval(node->NodeRight) );
            break;
        case(NODE_ADD_OP) :
            res = ( eval(node->NodeLeft) + eval(node->NodeRight) );
            break;
        case(NODE_MUL_OP) :
            res = ( eval(node->NodeLeft) * eval(node->NodeRight) );
            break;
	case(NODE_DIV_OP) :
            res = ( eval(node->NodeLeft) / eval(node->NodeRight) );
            break;
        case(NODE_RETURN) :
            res = eval(node->NodeLeft);
            break;
        case(NODE_IF_ELSE) :
            res = evalIfElse(node);
            break;
        case(NODE_ELSE) :
            puts("This node should never be evaluated here, always in the evalIfElse()");
            break;
        case(NODE_BLOCK) :
            res = evalBlock(node);
            break;
        default :
            printf("Unknown node type: %i\n", switchInt);
        

        }

        return res;
}

 /* evaluates a list  of declaration nodes on the left and a statement node on the right */
   
int
evalProgram(NODE * node) {
    int res = NULL;
    NODE* currNode;

    for(currNode = node->NodeLeft; currNode != NULL; currNode = currNode->NodeNext)
        eval(currNode);

    res = eval(node->NodeRight);
    return res;

}

 /* evaluates a list of declaration nodes on the left and statement nodes right */
   
int
evalBlock(NODE * node) {
    int res = NULL;
    NODE* currNode;

    for(currNode = node->NodeLeft; currNode != NULL; currNode = currNode->NodeNext)
        eval(currNode);
    for(currNode = node->NodeRight; currNode != NULL; currNode = currNode->NodeNext)
        res = eval(currNode);

    return res;
}

/* evaluates noderight while nodeleft is true */
 
int
evalWhile(NODE * node) {
    int res = NULL;

    while(eval(node->NodeLeft) ) {
        res = eval(node->NodeRight);
		if(breaknode){
			breaknode = !breaknode;
			break;
		}
		if(continuenode) {
			continuenode = !continuenode;
			continue;
		}
	}
    return res;
}

/* 
 * Single if statement, ie no else statement
 * nodeleft is condition noderight is statement to execute
 */

int
evalIf(NODE * node){
    int res = NULL;
    
    if( eval(node->NodeLeft) )
        res = eval(node->NodeRight);

    return res;
}

/*
 * takes an IF_ELSE node which has a nodeleft which is the condition and
 * and node right which is an ELSE node, if nodeleft is true it
 * evaluates the leftchild of it's noderight, otherwise it evaluates the
 * right child of it's noderight, ie ELSE node contains the if's statement
 * as well as it's statement
 */

int
evalIfElse(NODE * node) {
    	int res = NULL;

        if(eval(node->NodeLeft) )
            res = eval(node->NodeRight->NodeLeft);
        else
            res = eval(node->NodeRight->NodeRight);

        return res;
}


::::::::::::::
lex.l
::::::::::::::
/* 
 * Author: Mark Thomas 
 * Lexical Analyser written using Lex
 */

/* denotes a letter */
L                       [a-zA-Z_]

/* denotes a digit */
D                       [0-9]

/* denotes whitespace(s) */
W                       [ \t\v\n\f]

/* denotes end of line character */
N                       [\n]

%{
#include <stdio.h>
#include "node.h"
#include "parse.tab.h"
#include "xalloc.h"

/* global variables as used in Lex */

extern YYSTYPE yylval;
extern int yydebug;

/* function prototypes */

int yywrap(void);
void yyerror(char *);
void count(void);
int checkType(void);
int comment(void);

/* stores current line number */
static int sLineNumber = 1;
static int column = 0;
%}


/* List of Tokens that the Lex uses */

%%

"/*"                    { count();      comment(); }
"break"                 { count();      yylval.sValue = BREAK;          return(BREAK); }
"continue"              { count();      yylval.sValue = CONTINUE;       return(CONTINUE); }
"return"                { count();      yylval.sValue = RETURN;         return(RETURN); }
"while"                 { count();      yylval.sValue = WHILE;          return(WHILE); }
"else"                  { count();      yylval.sValue = ELSE;           return(ELSE); }
"if"                    { count();      yylval.sValue = IF;             return(IF); } 
"int"                   { count();      yylval.sValue = INT;            return(INT); }

{N}                     { count();      sLineNumber++; }
{L}({L}|{D})*           { count();      return checkType(); }
{D}({D})*               { count();      yylval.sValue = atoi(yytext);   return(INT_DENOTATION); }
{W}                     { count();      yylval.sValue = 0; }

"+"                     { count();      yylval.sValue = '+';            return('+'); }
"-"                     { count();      yylval.sValue = '-';            return('-'); }
"*"                     { count();      yylval.sValue = '*';            return('*'); }
"/"                     { count();      yylval.sValue = '/';            return('/'); }
"%"                     { count();      yylval.sValue = '%';            return('%'); }
"!"                     { count();      yylval.sValue = '!';            return('!'); }
"?"                     { count();      yylval.sValue = '?';            return('?'); }
":"                     { count();      yylval.sValue = ':';            return(':'); }
"="                     { count();      yylval.sValue = '=';            return('='); }
","                     { count();      yylval.sValue = ',';            return(','); }
">"                     { count();      yylval.sValue = '>';            return('>'); }
"<"                     { count();      yylval.sValue = '<';		return('<'); }
"("                     { count();      yylval.sValue = 0;              return('('); }
")"                     { count();      yylval.sValue = 0;              return(')'); }
"{"                     { count();      yylval.sValue = 0;              return('{'); }
"}"                     { count();      yylval.sValue = 0;              return('}'); }
"||"                    { count();      yylval.sValue = OR_OP;          return(OR_OP); }
"&&"                    { count();      yylval.sValue = AND_OP;         return(AND_OP); }
"=="                    { count();      yylval.sValue = EQ_OP;          return(EQ_OP); }
";"                     { count();      yylval.sValue = 0;              return(';'); }

.                       { yyerror("Bad character"); exit(1);}

%%

/* Code section */


/* use only one lex file for analysis */

int
yywrap(void)
{
        return(1);
}


/* copy identifier value and return it */

int 
checkType(void)
{
	yylval.pszValue = xstrdup(yytext);	/* copy the string */

   	return(IDENTIFIER);
}


/* ignore comments */

int
comment(void)
{
    int c;

    for (;;){	
	/* read each character until we find close comment */
        while ((c = input()) != '*' && c != EOF)
                if (c == '\n') sLineNumber++;

                if (c == '*'){
                    while ((c = input()) == '*') 
                        ;
                    if (c == '\n') sLineNumber++;
                    if (c == '/') break;
                }

                if(c == EOF)
                    printf("unterminated comment\n");
        }
}

/* calculate the current position on the line */

void count(void)
{
        int i;
 
        for(i = 0; yytext[i] != '\0'; i++)
                if(yytext[i] == '\n')
                        column = 0;
                else if(yytext[i] == '\t')           
                        column += 8 - (column % 8);
                else
                        column++;
         
        ECHO;
}

/* report an error to the standard error stream */

void
yyerror( char *s )
{
    	fflush(stdout);
    	fprintf(stderr, "\n%*s\n%*s at position %d on line %d\n",
            column, "^", column, s, column, sLineNumber);
}
::::::::::::::
main.c
::::::::::::::
#include <locale.h>
#include <stdio.h>
#include "node.h"
#include "nameAnalyser.h"
#include "stdlib.h"

NODE* expTree;

int
main(int argc, char **argv) {

        extern int yyparse();
        NODE * root;
        EnvNode * rootEnv;
        SymbolTable * symTab;
        int i, result, interpError = 0, numParams = 0;

        setlocale(LC_ALL, ""); /* clean the environment */

        rootEnv = (EnvNode*) malloc(sizeof(EnvNode));
        initEnvNode(rootEnv);
        symTab = (SymbolTable*) malloc(sizeof(SymbolTable));
        initSymTab(symTab);

        interpError = yyparse();	/* do the parsing */
        
        if(!interpError) {		/* if no error found then analyse the tree */
            	interpError = analyseTree(expTree, rootEnv, symTab);
            	deleteEnvNode(rootEnv);
            
        	if(!interpError) {
            		for(i = 0; i < symTab->numEntries; i++) {
                		if(symTab->entries[i].isParam == 1) {
                    			numParams++;

                    		if(numParams <= argc-1)
                        		symTab->entries[i].value = atoi(argv[numParams]);
                		}
            		}

            	if(numParams == argc-1) {
                	result = evalTree(expTree, symTab);
                	printf("The program evaluated to: %i\n", result);
            	}
            else
                printf("Error: Unable to run program. Expected %i parameters, found %i parameters\n", numParams, argc-1);
        	}
        }
        
    	deleteSymTab(symTab);
    	return(0);
}
::::::::::::::
Makefile
::::::::::::::
#
# Mark Thomas
#

GCC 	= gcc
LEX 	= /usr/ccs/bin/lex
YACC 	= bison
YFLAGS	= -dv
LFLAGS	= -t
CFLAGS 	= -O2 -ansi -pedantic -ggdb -g 
LINKER	= -ll
SRC	= debug.c debug.h  nameAnalyser.c nameAnalyser.h xalloc.c xalloc.h node.c node.h parse.y lex.l main.c evalTree.c evalTree.h
OBJ	= parse.o lex.o debug.o xalloc.o nameAnalyser.o node.o main.o evalTree.o
EXE	= interpreter

all:	$(OBJ)
	$(GCC) $(CFLAGS) -Wall -o $(EXE) $(OBJ) $(LINKER)

.c.o:
	$(GCC) $(CFLAGS) -c $<

lex.o:	parse.tab.h lex.c

lex.c:	lex.l
	$(LEX) $(LFLAGS) lex.l > lex.c

parse.o:parse.c

parse.c:parse.y
	$(YACC) $(YFLAGS) parse.y
	mv -f parse.tab.c parse.c
	
	
clean:	;rm -f $(EXE) parse.output parse.tab.h parse.c lex.c core *.o *~
::::::::::::::
nameAnalyser.c
::::::::::::::
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "xalloc.h"
#include "node.h"
#include "nameAnalyser.h"

void
initEnvNode(EnvNode * node) {
	node->firstChild = NULL;
    	node->lastChild = NULL;
    	node->firstIdent = NULL;
    	node->lastIdent = NULL;
    	node->parent = NULL;
    	node->nextSibling = NULL;
}

void
addEnvChild(EnvNode * parent) {
    	EnvNode * newNode = XMALLOC(EnvNode , 1);
    
    	assert(parent != NULL);

    	initEnvNode(newNode);
    	newNode->parent = parent;

    	if(parent->firstChild == NULL){
        	parent->firstChild = newNode;
        	parent->lastChild = newNode;
    	}
    	else {
        	parent->lastChild->nextSibling = newNode;
        	parent->lastChild = newNode;
    	}
}

void
addEnvIdent(EnvNode * node, char * name, SymbolTable * symTab) {
    	Identifier * newIdent;
    
    	assert(node != NULL && name != NULL && symTab != NULL);
    	newIdent = XMALLOC(Identifier, 1);
    	newIdent->name = XMALLOC(char, strlen(name)+1);
    	strcpy(newIdent->name, name);
   	newIdent->index = addSymTabEntry(symTab);

   	if(node->firstIdent == NULL) {
        	node->firstIdent = newIdent;
        	node->lastIdent = newIdent;
    	}
    	else {
        	node->lastIdent->next = newIdent;
        	node->lastIdent = newIdent;
    	}
}

int
getIdentIndex(EnvNode * node, char * name) {
    	Identifier * currIdent;

    	assert(name != NULL);
    
    	if(node == NULL)
        	return -1;

    	for(currIdent = node->firstIdent;
        	currIdent != NULL;
        	currIdent = currIdent->next)
	{
        	if(strncmp(currIdent->name, name, MAX_VAR_NAME_SIZE) == 0)
            		return currIdent->index;
    	}

    		return getIdentIndex(node->parent, name);
}

int
isInEnv(EnvNode * node, char * name) {
    	Identifier * currIdent;
    
    	assert(node != NULL && name != NULL);

    	for(currIdent = node->firstIdent; 
		currIdent != NULL; 
		currIdent = currIdent->next) 
	{
        	if(strncmp(currIdent->name, name, MAX_VAR_NAME_SIZE) == 0)
            		return 1;
    	}

    	return 0;

}

void
deleteEnvNode(EnvNode * node) {
    	Identifier * currIdent;
    	Identifier * prevIdent;
    	EnvNode * currChild;
    	EnvNode * prevChild;

    	assert(node != NULL);

    	for(currIdent = node->firstIdent; currIdent != NULL; ){
        	deleteIdent(currIdent);
        	prevIdent = currIdent;
        	currIdent = currIdent->next;

        	XFREE(prevIdent);
    	}

    	for(currChild = node->firstChild; currChild != NULL; ){
        	deleteEnvNode(currChild);
        	prevChild = currChild;
        	currChild = currChild->nextSibling;
        
        	XFREE(prevChild);
    	}
}

void
deleteIdent(Identifier * ident){
    	XFREE(ident->name);

}

void
initSymTab(SymbolTable * symTab){
    	assert(symTab != NULL);
    
    	symTab->entries = XMALLOC(STEntry, DEFAULT_ST_SIZE);
    	symTab->numEntries = 0;
    	symTab->size =  DEFAULT_ST_SIZE;
}


/* returns the index of the new entry */

int
addSymTabEntry(SymbolTable * symTab) {
    	STEntry * newEntries;
    	int i;
        
    	assert(symTab != NULL);

    	/* resize the table if necessary */
 
   	if(symTab->numEntries == symTab->size) {
        	newEntries = XCALLOC(STEntry, 2*(symTab->size));
		memcpy(newEntries, symTab->entries, sizeof(STEntry)*(symTab->size));
        	XFREE(symTab->entries);
        	symTab->entries = newEntries;
        	symTab->size = 2*(symTab->size);
    	}
    
    	symTab->numEntries++;

    	/* return the index of the new entry */
    	return(symTab->numEntries - 1);

}

void
deleteSymTab(SymbolTable * symTab) {
    	XFREE(symTab->entries);
}


int
analyseTree(NODE * root, EnvNode * rootEnv, SymbolTable * symTab) {
    	NODE * currNode;
    	char* identName;
    	int identIndex;
    	int errorFound = 0;
    
    	if(root == NULL)
        	return;

    	switch(root->sNodeType) {
    	case NODE_DECLARATION:
 
       /* left node will be an identifier */

        identName = root->NodeLeft->vari.szName;

        if(!isInEnv(rootEnv, identName))
            	addEnvIdent(rootEnv, identName, symTab);

        else {
            errorFound = 1;
            printf("Error: Identifier %s already declared. Line: %i.\n", identName, root->sLineNumber);
            break;	
	}

        errorFound = analyseTree(root->NodeLeft, rootEnv, symTab);

        if(root->NodeRight != NULL)
            	errorFound = analyseTree(root->NodeRight, rootEnv, symTab);
        break;

    	case NODE_VARIABLE:
        	identIndex = getIdentIndex(rootEnv, root->vari.szName);
        	if(identIndex != -1)
            		root->sTableIndex = identIndex;
        	else {
            		errorFound = 1;
            		printf("Error: Identifier %s undeclared. Line: %i\n",  root->vari.szName,
	    		root->sLineNumber);	
        	}
        break;

        /* nodes that contain nothing to check */

    	case NODE_BREAK:
    	case NODE_CONTINUE:
        	break;
    	case NODE_NUMBER:
        	break;
        
        /* unary nodes */

    	case NODE_RETURN:
    	case NODE_NEG_OP:
    	case NODE_NOT_OP:
        	errorFound = analyseTree(root->NodeLeft, rootEnv, symTab);
        	break;

    	case NODE_BLOCK:
        /* blocks require a new scope */
        	addEnvChild(rootEnv);
        	rootEnv = rootEnv->lastChild;

        	for(currNode = root->NodeLeft; 
			currNode != NULL && !errorFound; 
			currNode = currNode->NodeNext)

            		errorFound = analyseTree(currNode, rootEnv, symTab);

        	for(currNode = root->NodeRight; 
			currNode !=NULL && !errorFound; 
			currNode = currNode->NodeNext)

            			errorFound = analyseTree(currNode, rootEnv, symTab);
        	break;

    	case NODE_PROGRAM:
		for(currNode = root->NodeLeft; 
			currNode != NULL && !errorFound; 
			currNode = currNode->NodeNext) 
		{
	    		errorFound = analyseTree(currNode, rootEnv, symTab);
	    		symTab->entries[currNode->NodeLeft->sTableIndex].isParam = 1;
		}

        	errorFound = analyseTree(root->NodeRight, rootEnv, symTab);
        	break;
    
        /* binary nodes */
    	default:
        	errorFound = analyseTree(root->NodeLeft, rootEnv, symTab);
        	errorFound = analyseTree(root->NodeRight, rootEnv, symTab);
    	}
    
    	if (errorFound) {
    		deleteSymTab(symTab);
		exit(0);
	}

    	return errorFound;
}
::::::::::::::
nameAnalyser.h
::::::::::::::
#ifndef _NAME_ANALYSER_H
#define _NAME_ANALYSER_H

#define DEFAULT_ST_SIZE 10

/* An entry in the symbol table. In COMP3100 the entry can only
 represent an integer. */
typedef struct STEntry {
    int value;
    int isParam;
} STEntry;

typedef struct SymbolTable {
    STEntry * entries;
    int numEntries;
    int size;
} SymbolTable;

typedef struct Identifier {
  struct Identifier * next;
  char * name;
  int index;
} Identifier;

typedef struct EnvNode {
  struct EnvNode * firstChild;
  struct EnvNode * lastChild;
  Identifier * firstIdent;
  Identifier * lastIdent;
  struct EnvNode * parent;
  struct EnvNode * nextSibling;
} EnvNode;

/*typedef struct _node NODE;*/

void initEnvNode(EnvNode * node);
void addEnvChild(EnvNode * parent);
void addEnvIdent(EnvNode * node, char * name, SymbolTable * symTab);
void deleteEnvNode(EnvNode * node);
int getIdentIndex(EnvNode * node, char * name);

void deleteIdent(Identifier * ident);

void initSymTab(SymbolTable * symTab);
int addSymTabEntry(SymbolTable * symTab); /*returns the index of the new entry*/
void deleteSymTab(SymbolTable * symTab);

int analyseTree(NODE * root, EnvNode * rootEnv, SymbolTable * symTab);

#endif
::::::::::::::
node.c
::::::::::::::
/*
 *      Node by Mark Thomas and Owen Macindoe
 *      A data structure for holding expression tree information
 *     for an interpreter working on a subset of C.
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <varargs.h>
#include "xalloc.h"
#include "node.h"

/* Create a new node */

static NODE *NewNode(int sNodeType)
{
    	register NODE *r = 0;

    	r = XMALLOC(NODE, 1);
    	memset(r, '\0', sizeof(NODE));
    	r->sNodeType = sNodeType;

    	return r;
}

/* add a node to the tree */

NODE *AddNode(NODE *left, int sNodeType, NODE *right)
{
   	register NODE *r;

   	r = NewNode(sNodeType);
   	r->NodeLeft  = left;
   	r->NodeRight = right;

   	return r;
}

/* append a node to the tree */

NODE *AppendNode(NODE *nodeList, NODE *nodeNew)
{
   	register NODE *oldlist;
   	oldlist = nodeList;

   	while (nodeList->NodeNext != NULL)
      		nodeList = nodeList->NodeNext;

   	nodeList->NodeNext = nodeNew;

   	return oldlist;
}

/* add a node with value equal to sValue */

NODE *AddNumber(int sValue)
{
  	register NODE *pNode;

   	pNode = NewNode(NODE_NUMBER);
   	pNode->vari.sValue = sValue;
   	pNode->sVariableType = TYPE_INTEGER;

   	return pNode;
}

/* add a node with value equal to pszName */

NODE *AddVariable(char *pszName)
{
   	register NODE *r;/* = FindVariable(pszName);*/
   	r = NewNode(NODE_VARIABLE);

   	strncpy(r->vari.szName, pszName, MAX_VAR_NAME_SIZE);
   	/* all variables default to integer type*/
   	r->sVariableType = TYPE_INTEGER;

   	return r;
}

/* delete a nodee from the three */

void DeleteNode(NODE * node) {
	if(node->NodeLeft != NULL)
		DeleteNode(node->NodeLeft);

	if(node->NodeRight != NULL)
		DeleteNode(node->NodeRight);

	if(node->NodeNext != NULL)
		DeleteNode(node->NodeNext);
	
	XFREE(node);
}

::::::::::::::
node.h
::::::::::::::
#ifndef _NODE_H
#define _NODE_H

#define TYPE_INTEGER		0
#define NODE_PROGRAM         	1
#define NODE_STATEMENT       	2 
#define NODE_FUNCTION        	3
#define NODE_EXPRESSION      	4
#define NODE_PREINCREMENT    	5
#define NODE_PREDECREMENT    	6
#define NODE_POSTINCREMENT   	7
#define NODE_POSTDECREMENT   	8
#define NODE_NUMBER          	9
#define NODE_STRING         	10
#define NODE_VARIABLE       	11
#define NODE_ELSE           	12
#define NODE_FOR            	13
#define NODE_IF             	14
#define NODE_RETURN         	15
#define NODE_WHILE          	16
#define NODE_INT            	17
#define NODE_VOID           	18
#define NODE_EXP_OP         	19
#define NODE_MUL_OP         	20
#define NODE_MOD_OP         	21
#define NODE_DIV_OP         	22
#define NODE_ADD_OP         	23
#define NODE_SUB_OP         	24
#define NODE_INC_OP         	25
#define NODE_DEC_OP         	26
#define NODE_NOT_OP         	27
#define NODE_AND_OP         	28
#define NODE_OR_OP          	29
#define NODE_LT_OP          	30
#define NODE_GT_OP          	31
#define NODE_LE_OP          	32 
#define NODE_GE_OP          	33
#define NODE_EQ_OP          	34
#define NODE_NE_OP          	35
#define NODE_ASSIGN         	36
#define NODE_BREAK          	37
#define NODE_DECLARATION    	38
#define NODE_QUESTION       	39
#define NODE_COLON          	40
#define NODE_CONTINUE       	41
#define NODE_MINUS_OP       	42
#define NODE_BLOCK          	43
#define NODE_NEG_OP         	44
#define NODE_IF_ELSE        	45

#define MAX_VAR_NAME_SIZE  	60

typedef struct _node
{
   	/* type of node */
   	int  sNodeType;

   	/* line number of node relative to code (for error reporting or debug) */
   	int  sLineNumber;

   	/* links to related nodes (depending on node type may not be used) */
   	struct _node *NodeLeft;
   	struct _node *NodeRight;
   
   	/* !NEW! link to the next node (used for nodes containing lists of expressions) */
   	struct _node *NodeNext;

   	/* type of variable (string, integers, chars etc)*/
   	int  sVariableType;

   	/* the index number of the variable in the symbol table*/
   	int sTableIndex;

   	/* the value of the token (as returned by LEXX tokenizer)*/
   	int  sTokenValue;
   
   	/* strings, integers and numbers*/
   	struct _vari {
       		int  sValue;
       		char szName[MAX_VAR_NAME_SIZE];
   	} vari;
            
} NODE;

/* Function to add nodes to the parse node list */
NODE *AddNumber(int sNumber);
NODE *AddVariable(char *pszName);
NODE *AddNode(NODE *left, int op, NODE *right);
NODE *AppendNode(NODE *nodeList, NODE *nodeNew);
void DeleteNode(NODE * node);

#endif
::::::::::::::
parse.y
::::::::::::::
/* YACC/BISON parser */

%{
#include <stdio.h>
#include "node.h"
%}


/* list of needed tokens */

%token IDENTIFIER INT_DENOTATION
%token EQ_OP
%token AND_OP OR_OP
%token INT
%token IF ELSE WHILE CONTINUE BREAK RETURN

/* 
 * Surpress ambiguous shift/reduce conflict in compound statement.
 * This is predictably resolved by bison correctly anyway.       
 */

%expect 1

/* data types used in grammar */

%union
{
   int  sValue;
   char *pszValue;
   NODE *pNode;
}

/* rules which create nodes on the tree */

%type <pNode>   comp3100program
%type <pNode>   expression
%type <pNode>   condition
%type <pNode>   disjunction
%type <pNode>   conjunction
%type <pNode>   comparison
%type <pNode>   relation
%type <pNode>   sum
%type <pNode>   term
%type <pNode>   factor
%type <pNode>   primary
%type <pNode>   declaration_parameter_list
%type <pNode>   declaration_parameter
%type <pNode>   declaration_variable_list
%type <pNode>   declaration_variable
%type <pNode>   declaration_variable_init
%type <pNode>   statement
%type <pNode>   statement_list
%type <pNode>   statement_compound
%type <pNode>   statement_conditional
%type <pNode>   statement_iteration
%type <pNode>   statement_jump
%type <pNode>   statement_computation
%type <pNode>   identifier
%type <pNode>   int_denotation

/* nodes which return an integer type */

%type <sValue>   '='
%type <sValue>   INT_DENOTATION
%type <sValue>   '>'
%type <sValue>   '<'
%type <sValue>   EQ_OP

/* node which returns a string type */

%type <pszValue> IDENTIFIER

/* Evaluation precedence: lowest to highest */

%right '='
%left ','
%left OR_OP
%left AND_OP
%nonassoc '>' '<' EQ_OP
%left '+' '-'
%left '*' '/' '%'

/* the location of the root node */

%start comp3100program


/* Grammatical Rules for the comp3100 program syntax */

%%

/* root node */
comp3100program
	/* read an INT(eger) followed by an identifier then a left bracket followed by 
	 *declaration parameter list followed by right bracket then a statement compound
	 */

        : INT identifier '(' declaration_parameter_list ')' statement_compound
        {
            extern NODE* expTree;

	/* add this node to the tree */

            $$ = AddNode($4, NODE_PROGRAM, $6);

	/* set the root node to this current symbol */

            expTree = $$;
        } 
        ;

expression
        : identifier '=' expression
        {
                $$ = AddNode($1, NODE_ASSIGN, $3);
                ($$)->sTokenValue = $2;
        }
	/* if not an identifier the expression must then reduce to a condition  */
        | condition
        {
                $$ = $1;		/* set yyval to this value */
        }
        ;

condition
        : disjunction
        {
                $$ = $1;
        }
        | disjunction '?' expression ':' condition
        {
                $$ = AddNode($1, NODE_IF_ELSE, AddNode($3, NODE_ELSE, $5));
        }
        ;

disjunction
        : conjunction
        {
                $$ = $1;
        }
        | disjunction OR_OP conjunction
        {
                $$ = AddNode($1, NODE_OR_OP, $3);
        }
        ;

conjunction
        : comparison
        {
                $$ = $1;
        }
        | conjunction AND_OP comparison
        {
                $$ = AddNode($1, NODE_AND_OP, $3);
        }
        ;

comparison
        : relation 
        {
                $$ = $1;
        }
        | comparison EQ_OP relation
        {
                $$ = AddNode($1, NODE_EQ_OP, $3);
        }
        ;
        
relation
        : sum
        {
                $$ = $1;
        }
        | relation '<' sum
        {
                $$ = AddNode($1, NODE_LT_OP, $3);
        }
        | relation '>' sum
        {
                $$ = AddNode($1, NODE_GT_OP, $3);
        }
        ;

sum
        : term
        {
                $$ = $1;
        }
        | sum '+' term
        {
                $$ = AddNode($1, NODE_ADD_OP, $3);
        }
        | sum '-' term
        {
                $$ = AddNode($1, NODE_SUB_OP, $3);
        }
        ;

term
        : factor
        {
                $$ = $1;
        }
        | term '*' factor
        {
                $$ = AddNode($1, NODE_MUL_OP, $3);
        }
        | term '/' factor
        {
                $$ = AddNode($1, NODE_DIV_OP, $3);
        }
        | term '%' factor
        {
                $$ = AddNode($1, NODE_MOD_OP, $3);
        }
        ;

factor
        : primary
        {
                $$ = $1;
        }
        | '!' factor
        {
                $$ = AddNode($2, NODE_NOT_OP, NULL);
        }
        | '-' factor
        {
                $$ = AddNode($2, NODE_NEG_OP, NULL);
        }
        ;

primary
        : int_denotation
        {
                $$ = $1;
        }
        | identifier
        {
                $$ = $1;
        }
        | '(' expression ')'
        {
                /* $$ = AddNode($2, NODE_EXPRESSION, NULL); */
		$$ = $2;
        }
        ;

/*       DECLARATIONS AND STATEMENTS    */

declaration_parameter_list
        : declaration_parameter
        { /* add node */
              $$ = $1;
	}
        | declaration_parameter_list ',' declaration_parameter
	{
	$$ = $1;
            $$ = AppendNode($$, $3);	/* Append the node to the root tree  */
	}
        ;

declaration_parameter
        : INT identifier
        {
                ($2)->sVariableType = TYPE_INTEGER;
                $$ = AddNode($2, NODE_DECLARATION, NULL);
        }
        ;

declaration_variable_list
        : declaration_variable
        {
                $$ = $1;
        }
        | declaration_variable_list declaration_variable
	{
		$$ = $1;
            $$ = AppendNode($$, $2);
	}
        ;

declaration_variable
        : INT declaration_variable_init
	{
		$$ = $2;
	}
        ;

declaration_variable_init
        : identifier ';'
        {
              $$ = AddNode($1, NODE_DECLARATION, NULL);
        }
        | identifier '=' expression ';'
        {
            $$ = AddNode($1, NODE_DECLARATION, $3);
            ($$)->sVariableType = TYPE_INTEGER;
        }
        | identifier '=' expression ',' declaration_variable_init
        {
            $$ = AddNode($1, NODE_DECLARATION, $3);
            ($$)->sVariableType = TYPE_INTEGER;
            $$ = AppendNode($$, $5);
        }
        | identifier ',' declaration_variable_init
        {
            $$ = AddNode($1, NODE_DECLARATION, NULL);
            $$ = AppendNode($$, $3);
        }
        ;

statement
        : statement_compound
        {
                $$ = $1;
        }
        | statement_conditional
        {
                $$ = $1;
        }
        | statement_iteration
        {
                $$ = $1;
        }
        | statement_jump
        {
                $$ = $1;
        }
        | statement_computation
        {
                 $$ = $1;
        }
        ;

statement_list
        : statement
        {
		$$ = $1;
        }
        | statement_list statement
        {
		$$ = $1;
            	$$ = AppendNode($$, $2);
        }
        ;

statement_compound
        : '{' '}'
        {
                $$ = 0;
        }
        | '{' statement_list '}'
        {
                $$ = AddNode(NULL, NODE_BLOCK, $2)
        }
        | '{' declaration_variable_list '}' 
        {
                $$ = AddNode($2, NODE_BLOCK, NULL);
        }
        | '{' declaration_variable_list statement_list '}'
	{
 		$$ = AddNode($2, NODE_BLOCK, $3);
	}
        ;

/*
 * Contains a dangling else ambiguity. Bison chooses shift instead of reduce
 * therefore attaches the else clause to the inner-most if-statement.      
 */

statement_conditional
        : IF '(' expression ')' statement
        {
                $$ = AddNode($3, NODE_IF, $5);
        }
        | IF '(' expression ')' statement ELSE statement
        {
                $$ = AddNode($3, NODE_IF_ELSE, AddNode($5, NODE_ELSE, $7));
        }
        ;

statement_iteration
        : WHILE '(' expression ')' statement
        {
                $$ = AddNode($3, NODE_WHILE, $5);
        }
        ;

statement_jump
        : BREAK ';'
        {
                $$ = AddNode(NULL, NODE_BREAK, NULL);
        }
        | CONTINUE ';'
        {
                $$ = AddNode(NULL, NODE_CONTINUE, NULL);
        }
        | RETURN expression ';'
        {
                $$ = AddNode($2, NODE_RETURN, NULL);
        }
        ;

statement_computation
        : ';'
        {
                $$ = 0;
        }
        | expression ';'
        {
		$$ = $1;
        }
        ;

identifier
        : IDENTIFIER
        {
                $$ = AddVariable($1);	/* create a node with the value equal to this identifier */
        }
        ;

int_denotation
        : INT_DENOTATION
        {
                $$ = AddNumber($1);	/* create a ndoe with the value equal to this digit */
        }
        ;

%% 	/* end of rules */

*** tests: directory ***

::::::::::::::
xalloc.c
::::::::::::::
/*
 * xalloc.c - general purpose memory allocations error checking wrappers
 * $Id: xalloc.c,v 1.6 2002/10/31 02:46:44 mathomas Exp $
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#include "xalloc.h"
#include "debug.h"

extern int errno;

/*
 * malloc(3) NULL-checking wrapper.
 */

void *
xmalloc(size_t size)
{
	void *ptr = NULL;

	if ((ptr = malloc(size)) == NULL)
		fatal("malloc(): %s\n", (void *) strerror(errno));

	memset(ptr, 0, size); /* malloc(3) neglects to zero out memory */
	
	return ptr;
}

/*
 * calloc(3) NULL-checking wrapper.
 */

void *
xcalloc(size_t nmemb, size_t size)
{
	void *ptr = NULL;

	if ((ptr = calloc(nmemb, size)) == NULL)
		fatal("calloc(): %s", (void *) strerror(errno));
	
	return ptr;
}


/*
 * realloc(3) NULL-checking wrapper.
 */

void *
xrealloc(void *pt, size_t size)
{
	void *ptr = NULL;
	
	if ((ptr = realloc(pt, size)) == NULL)
		fatal("realloc(): %s", (void *) strerror(errno));

	return ptr;
}

/*
 * free(3) NULL-checking wrapper
 *  - ANSI allows NULL, however it often causes arbitary problems elsewhere.
 */

void
xfree(void *ptr)
{
	assert(ptr != NULL);
	free(ptr);
}


/*
 * strdup(3) NULL-checking wrapper
 *
 */

void *
xstrdup(const char *str)
{ 
	char *copy; 
	copy = xmalloc(strlen(str) + 1); 
	strcpy(copy, str); 
	return copy; 
} 

::::::::::::::
xalloc.h
::::::::::::::
#ifndef XALLOC_H
#define XALLOC_H

/* general purpose memory allocation prototype definitions */

extern void *xmalloc(size_t size);
extern void *xcalloc(size_t nmemb, size_t size);
extern void *xrealloc(void *ptr, size_t size);
extern void xfree(void *ptr);
extern void *xstrdup(const char *);

/* macro definitions to handle type casting */

#define XMALLOC(type, num)		((type *) xmalloc(num * sizeof(type)))
#define XCALLOC(type, num)		((type *) xcalloc(num, sizeof(type)))
#define XREALLOC(type, ptr, num)	((type *) xrealloc(ptr, num * sizeof(type)))
#define XFREE(ptr)			do { xfree(ptr); ptr = NULL; } while (0);

/*
 * Example: char *ptr = XMALLOC(char, sizeof(buf)); 
 */

#endif /* XALLOC_H */

