#include	"global.h"
#include	"list.h"
#include	"source.h"
#include	"lex.h"
#include	"parser.h"
#include	"irep.h"
#include	"lexparse.h"
#include	"fsa.h"
#include	"fsatab.h"

// The constructor function for FsaTable converts the FSA transitions
// into a table form for convenient output.

FsaTable::FsaTable(list<odfsaState *> *x)
{
	int offset = 0;
	listIter<odfsaState *> each(x);
	odfsaState **s;
	Transition *t;
	maxChar = (Transition::maxChar > 127 ? 255 : 127);
	states = x->length();
	table = (short int **) allocate(states * sizeof(short int *));
	final = (LexRule **) allocate(states * sizeof(LexRule *));
	for (int i=0; i<states; i++) {
	    s = each();
	    table[i] = (short int *) allocate(maxChar * sizeof(short int));
	    if (!offset)
		offset = (*s)->id();
	    if (odfsaState::initialPartition == (*s))
		initState = (*s)->id() - offset;
	    final[i] = (*s)->associatedToken();
	    for (int j=1; j<=maxChar; j++) {
		t = (*s)->transitions.findTrigger(j);
		table[i][j-1] = (t ? t->destination()->id() - offset: -1);
	    }
	}
}

// The following are member functions for printing out appropriate code
// fragements in response to the predetermined markers in the template
// file.

void FsaTable::pr_nomodsWarning(FILE *ofdes) {
	fprintf(ofdes, "This is a generated file. Modifications are futile.");
}

void FsaTable::pr_initialState(FILE *ofdes)
{
	fprintf(ofdes, "%d", initState);
}

void FsaTable::pr_states(FILE *ofdes)
{
	fprintf(ofdes, "%d", states);
}

void FsaTable::pr_charSet(FILE *ofdes)
{
	fprintf(ofdes, "%d", maxChar+2);
}

void FsaTable::pr_finalStates(FILE *ofdes)
{
	fprintf(ofdes, "{\n");
	for (int i=0; i<states; i++) {
	    if (i != 0)
		fprintf(ofdes, ",\n");
	    if (final[i]) {
		if (final[i]->isIgnored())
		    fprintf(ofdes, "\t{ 0, ");
		else
		    fprintf(ofdes, "\t{ %s, ", final[i]->name());
	        if (final[i]->filter())
		    fprintf(ofdes, "_fil_%s }", final[i]->name());
		else
		    fprintf(ofdes, "0 }");
	    } else
		fprintf(ofdes, "\t{ -1, 0 }");
	}
	fprintf(ofdes, "}");
}

void FsaTable::pr_filters(FILE *ofdes)
{
	for (int i=0; i<states; i++)
	    if (final[i] && final[i]->filter()) {
		for (int j=0; j<i; j++)
		    if (final[j] == final[i])
			goto skip;
		fprintf(ofdes, "void _fil_%s", final[i]->name());
		fprintf(ofdes, "(GLexer *lex, LexToken &token)\n");
		fprintf(ofdes, "{%s\n%s\n}\n",
			"if (!lex) abort();", final[i]->filter());
		skip: ;
	    }
}

void FsaTable::pr_prelude(FILE *ofdes)
{
	if (LexGenParser::prelude)
		fprintf(ofdes, "%s\n", LexGenParser::prelude);
}

void FsaTable::pr_postlude(FILE *ofdes)
{
	if (LexGenParser::postlude)
		fprintf(ofdes, "%s\n", LexGenParser::postlude);
}

// The writer class produces formatted tables.  This is useful for the
// initialisation of large arrays to represent transition functions.

class writer {
	FILE *fdes;
	int col, first;
	char buf[16];
public:
	void print(int);
	void print(char *);
	writer(FILE *);
	~writer();
};

void FsaTable::pr_stateTransition(FILE *ofdes)
{
	writer v(ofdes);
	for (int i=0; i<states; i++) {
		v.print("\n");
		{ writer w(ofdes);
		  w.print(-1); w.print(-1);
		  for (int j=1; j<=maxChar; j++)
			w.print(table[i][j-1]);
		}
	}
}

void writer::print(char *s)
{
	if (!first) {
		fprintf(fdes, ", "); col += 2;
	}
	first = FALSE;
	col += strlen(s);
	if (col > 70) {
		col = 0;
		fprintf(fdes, "\n");
	}
	fprintf(fdes, "%s", s);
}

void writer::print(int i)
{
	if (!first) {
		fprintf(fdes, ", "); col += 2;
	}
	first = FALSE;
	sprintf(buf, "%d", i);
	col += strlen(buf);
	if (col > 70) {
		col = 0;
		fprintf(fdes, "\n");
	}
	fprintf(fdes, "%s", buf);
}

writer::writer(FILE *fd)
{
	fdes = fd;
	col = 0;
	first = TRUE;
	fprintf(fdes, "{");
}

writer::~writer()
{
	fprintf(fdes, "}");
}


syntax highlighted by Code2HTML, v. 0.9.1