/* eval2.c */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define false		(0)
#define true		(!false)
#define MaxTokenLen	(10)
#define MaxStmtLen	(100)

typedef char	token_t[MaxTokenLen+1];	// Leave one extra character for the terminating null.

FILE	*input;
char	statement[MaxStmtLen];
int		StmtLen,
		StmtIndex;

token_t	token;

// Support routines. -----------------------------------------------------------

int equal (token_t a, token_t b) {
	return stricmp (a, b) == 0;	// Case sensitive or not?  Decide here.
}

// Lexical analysis. -----------------------------------------------------------

void GetNextToken (void) {
	int	TokLen;

	// Skip leading whitespace.
	while ((StmtIndex < StmtLen) && (strchr (" \t", statement[StmtIndex]) != 0) ){
		++StmtIndex;
	}
	if (StmtIndex == StmtLen) exit (1);			// No more tokens to get.
	token[0] = statement[StmtIndex];
	TokLen = 1;
	++StmtIndex;

	if (isalpha (token[0])) {
		// Token is an identifier.
		// Read in the remainder of the symbol name.
		while (	StmtIndex < StmtLen					// Are there any more characters?
				&& TokLen < MaxTokenLen				// Have we room for more characters?
				&& isalnum (statement[StmtIndex])	// Do we want them?
		) {
			token[TokLen] = statement[StmtIndex];
			++TokLen;
			++StmtIndex;
		}
		if (StmtIndex < StmtLen						// Is another character available?
			&& TokLen == MaxTokenLen				// Have we run out of room for it?
			&& isalnum (statement[StmtIndex])		// Did we want it?
		) {
			exit (1);	// Identifier is too long for our token buffer.
		}
	} else if (isdigit (token[0])) {
		// Token is a number - a 'literal numerical constant'.
		// Read in the remainder of the value.
		while (	StmtIndex < StmtLen					// Are there any more characters?
				&& TokLen < MaxTokenLen				// Have we room for more characters?
				&& isdigit (statement[StmtIndex])	// Do we want them?
		) {
			token[TokLen] = statement[StmtIndex];
			++TokLen;
			++StmtIndex;
		}
		if (StmtIndex < StmtLen						// Is another character available?
			&& TokLen == MaxTokenLen				// Have we run out of room for it?
			&& isdigit (statement[StmtIndex])		// Did we want it?
		) {
			exit (1);	// Number is too long for our token buffer.
		}
	} else {
		// Hopefully an operator of some kind.
	}
	token[TokLen] = 0;	// Terminate token string.
}

void InitLexer (void) {
	if (fgets (statement, sizeof (statement), input)) {
		StmtLen = strlen (statement);
	} else {
		StmtLen = 0;
	}
	StmtIndex = 0;

	GetNextToken ();
}

// Syntax analysis. ------------------------------------------------------------

void ParseExpression (void);	// Forward declaration.

void ParseFactor (void) {
	if (equal ("(", token)) {
		GetNextToken ();
		ParseExpression ();
	} else {
		printf (" %s", token);	// Token should be a primary expression.
	}
	GetNextToken ();
}

void ParseTerm (void) {
	ParseFactor ();
	while (equal ("*", token) || equal ("/", token)) {
		token_t	op;

		strcpy (op, token);
		GetNextToken ();
		ParseFactor ();
		printf (" %s", op);
	}
}

void ParseExpression (void) {
	ParseTerm ();
	while (equal ("+", token) || equal ("-", token)) {
		token_t	op;

		strcpy (op, token);
		GetNextToken ();
		ParseTerm ();
		printf (" %s", op);
	}
}

// Top level of program. -------------------------------------------------------

int main (void) {
	input = fopen ("eval2.dat", "r");	// Choose your source of input.
	//input = stdin;

	if (input != NULL) {
		do {
			InitLexer ();
			ParseExpression ();
			if (!equal ("\n", token)) exit (1); // Hopefully, token is actually a newline.
			printf ("\n");
		} while (!feof (input));
	}

	return 0;
}