/*
Adriane Boyd

Grammar class.

*/

#include <iostream.h>
#include <string.h>
#include <ctype.h>
#include "tlist.h"
#include "grammar.h"

// Constructor
Grammar::Grammar()
{
	numrules = 0;
}

// Destructor
Grammar::~Grammar()
{
	int i;

	for(i = 0; i < numrules; i++)
	{
		delete rules[i];
	}
}

// Reads the grammar from the given file
// Tokens are separated by whitespace and tokens which contain any uppercase
// letters are considered to be non-terminal symbols
int Grammar::read(ifstream& file)
{
	int i, j, isterm, newrule;
	char line[MAX_LINE_LEN];
	char tokenname[MAX_NAME_LEN];

	while(!file.eof())
	{
		file.getline(line, MAX_LINE_LEN);

		i = 0;

		newrule = 0;

		while(line[i] != '\0' && numrules < MAX_NUM_RULES)
		{
			strcpy(tokenname, "");
			isterm = 1;

			while(isspace(line[i]))
			{
				i++;
			}
			j = 0;
			while(!isspace(line[i]) && line[i] != '\0')
			{
				tokenname[j] = line[i];
				i++;
				j++;
				if(isupper(line[i]))
				{
					isterm = 0;
				}
			}
			tokenname[j] = '\0';

			if(strcmp(tokenname, "") != 0)
			{
				if(newrule == 0)
				{
					rules[numrules] = new TList;
					newrule = 1;
				}
				rules[numrules]->insertLast(tokenname, isterm);
			}
		}
		if(newrule == 1)
		{
			numrules++;
		}
	}
}

// The first symbol in the first rule is assumed to be the start symbol and
// is returned
char *Grammar::getStartSymbol()
{
	return rules[0]->getName(0);
}

// Returns a TList of the right hand side of the num-th occurance of symbol on
// the left hand side; the first element is a token whose term is the number
// of the rule returned and the following elements are the actual RHS
TList *Grammar::getRHS(char *symbol, int num)
{
	int i, mcount = 0;
	TList *rhs;

	for(i = 0; i < numrules; i++)
	{
		if(strncmp(rules[i]->getName(0), symbol, MAX_NAME_LEN) == 0)
		{
			if(mcount == num)
			{
				rhs = rules[i]->duplicate();
				rhs->deleteFirst();
				rhs->insertFirst("", i);
				return rhs;
			}
			mcount++;
		}
	}

	return NULL;
}

// Returns the number of times symbol is the LHS of a rule
int Grammar::getNumMatches(char *symbol)
{
	int i, count = 0;

	for(i = 0; i < numrules; i++)
	{
		if(strncmp(rules[i]->getName(0), symbol, MAX_NAME_LEN) == 0)
		{
			count++;
		}
	}

	return count;
}

// Prints the grammar
void Grammar::print()
{
	int i;

	cout << "Grammar: " << endl;
	for(i = 0; i < numrules; i++)
	{
		cout << i << ": ";
		rules[i]->print();
	}
}
