
#ifndef	PARSER_C
#define	PARSER_C

//	Short:		Command line parser for mathematical expressions.
//	Version:		$VER: Parser.c 1.0 (16.01.96)
//	Copyright:	Copyright © 1996 Constantin Rack. All rights reserved.


//	========================================================= INCLUDES

#include	<ctype.h>							//	Needed for isdigit()
#include	<iostream.h>						//	Needed for standard I/O
#include	<string.h>							//	Needed for string functions


//	========================================================== DEFINES

enum	Consts									//	Some constant values
{
	FALSE		=	0,
	TRUE		=	1,
	Op_Num	=	5,								//	Number of operators
};

enum	OperatorTypes
{
	Op_Err	=	-1,							//	Bad operator
	Op_Add	=	0,								//	+
	Op_Sub	=	1,								//	-
	Op_Mul	=	2,								//	*
	Op_Div	=	3,								//	/
};

struct	Operator
{
	int	op_Type;								//	Type of operator (see above)
	char*	op_Name;								//	Operator as a string
};


//	======================================================== VARIABLES

const char*	Version	=	"$VER: Parser 1.0 (16.01.96)";
char*			ActPtr	=	0;					//	Actual text pointer
int			Error		=	FALSE;			//	Error indicator

struct	Operator	operators[Op_Num]	=
{
	{
		Op_Add,	"+"
	},
	
	{
		Op_Sub,	"-"
	},
	
	{
		Op_Mul,	"*"
	},
	
	{
		Op_Div,	"/"
	},
};			


//	======================================================= PROTOTYPES

long	Expression();
long	Factor();
long	Constant();
long	Operater(); 


//	======================================================== FUNCTIONS


//	--------------------------------------------------------- FUNCTION
//	Operater()
//
//	Short:	Reads an operator and returns its value.
//	Needs:	ctype.h, string.h

long	Operater()
{
	long	result	=	0;
	long	i			=	0;
	char*	string	=	0;
	
	string	=	new char [80];
	result	=	Op_Err;
			
	if( string == 0 )
	{
		return	result;
	}
	
	while( *ActPtr != ' ' && i < 79 )
	{
		string[i++]	=	tolower( *ActPtr++ );
	}

	ActPtr++;

	string[i]	=	'\0';

	for(i=0;i<Op_Num;i++)
	{
		if( strcmp(operators[i].op_Name,string) == 0 )
		{
			result	=	operators[i].op_Type;
		}
	}

	delete	[]	string;

	return result;
}


//	--------------------------------------------------------- FUNCTION
//	Constant()
//
//	Short:	Reads a constant number ("C-Tools", ISBN 3-89090-190-5)
//	Needs:	ctype.h

long	Constant()
{
	long	result	=	0;

	while( *ActPtr != 0 && isdigit(*ActPtr) != 0 )
	{
		result	=	(result * 10) + (*ActPtr++ - '0');
	}

	return result;
}

//	--------------------------------------------------------- FUNCTION
//	Factor()
//
//	Short:	Evaluates an expression. This function is recursive.
//	Needs:	ctype.h

long	Factor()
{
	long	result	=	0;
	long	sign		=	1;

	if( *ActPtr == 0 )
	{
		return result;
	}
		

	if( *ActPtr == '-' )
	{
		sign	=	-1;
		ActPtr++;
	}

	if( isdigit( *ActPtr ) != 0 )
	{
		result	=	Constant();
	}
	else
	{
		if( *ActPtr == '(' )
		{
			result	=	Expression();
		}
	}

	result	*=	sign;

	return	result;
}

//	--------------------------------------------------------- FUNCTION
//	Expression()
//
//	Short:	Evaluates a bracket expression.
//	Needs:	stream.h

long	Expression()
{
	long	result	=	0;
	long	op			=	0;

	if( *ActPtr == '(' )
	{
		ActPtr++;

		op				=	Operater();
		result		=	Factor();

		switch( op )
		{
			case	Op_Add:
					{
						while( *ActPtr++ != ')' )
						{
							result	+=	Factor();
						}
					}		
					break;	
					
			case	Op_Sub:
					{
						while( *ActPtr++ != ')' )
						{
							result	-=	Factor();
						}
					}		
					break;	
					
			case	Op_Mul:
					{
						while( *ActPtr++ != ')' )
						{
							result	*=	Factor();
						}
					}		
					break;	
					
			case	Op_Div:
					{
						long	temp	=	0;
						
						while( *ActPtr++ != ')' )
						{
							temp	=	Factor();
							
							if( temp != 0 )
							{
								result	/=	temp;
							}
							else
							{
								cerr	<<	"** Division by zero\n";
								Error	=	TRUE;
							}		
						}
					}		
					break;	
					
			case	Op_Err:
			default:
            	{
						cerr	<<	"** Bad operator\n";
						Error	=	TRUE;
					}
					break;	
		}
	}
	else
	{
		if( *ActPtr == '?' )
		{
			cerr	<<	"This parser uses a simple praefix notation. Example:\n"
					<<	"\t(+ 1 (* 2 (/ 10 5)))\n"
					<<	"would have the result 5. So always write the operator "
					<<	"first. Parser knows the following operators by now:\n";
					
			{
				int	i	=	0;
				
				for(i=0;i<Op_Num;i++)
				{
					cerr	<<	operators[i].op_Name
							<<	", ";
				}
				
				cerr	<<	"\n";
			}
			
			cerr	<<	"\nCopyright © 1996 Constantin Rack. All rights reserved.\n";
					
			Error	=	TRUE;
		}
		else
		{
			cerr	<<	"** Bad command line\n";
			Error	=	TRUE;
		}
	}		

	return	result;
}

//	--------------------------------------------------------- FUNCTION
//	main()
//
//	Short:	Main function of the parser.
//	Needs:	stream.h, string.h

int	main()
{
	int	okay		=	TRUE;
	long	result	=	0;
	char*	input		=	0;

	input	=	new char [256];
	
	if( input == 0 )
	{
		cerr	<<	"** Memory problem\n";
		return	5;
	}		

	cout	<<	"Parser 1.0 (16.01.96)\n"
			<<	"Short:	Command line parser for mathematical expressions\n"
			<<	"Usage:	Press '?' for more information\n\n";

	while( okay )
	{
		cout	<<	"Expression: ";
		cin.getline(input,255);

		okay	=	strlen(input);
		
		if( okay > 0 )
		{	
			ActPtr	=	&input[0];
			result	=	Expression();

			if( Error == 0 )
			{
				cout	<<	"Result: "
						<<	result
						<<	"\n";
			}
			else
			{
				Error	=	FALSE;
			}
		}	
		else
		{
			cout	<<	"** Parser ended\n";
		}
	}
	
	delete	[]	input;
	
	return	0;
}

#endif	//	PARSER_C
