%token EMPTY
%token NO_TOKEN
%token EOI

%token NAME
%token INTEGER
%token HEXVAL

%token OR
%token XOR
%token AND
%token LOG 
%token LN
%token LG
%token EXP
%token ABS
%token SIN
%token COS
%token TAN
%token ASIN
%token ACOS
%token ATAN
%token NOT
%token DIV
%token CNP
%token ANP
%token POW

%%

macro	: 	expr EOI;

expr	: 	stmt Zexpr;

Zexpr	: 	EMPTY |
			'+' expr | 
			'-' expr | 
			OR expr |
			XOR expr ;

stmt	:	term Zstmt;

Zstmt	:	EMPTY |
			'*' term | 
			'/' term |
			'%' term |
			AND term ;

term	:	number |
			'(' expr ')'  |
			LOG '(' expr ')'  |
			LN '(' expr ')'  |
			LG '('  expr ')'  |
			EXP '(' expr ')'  |
			ABS '(' expr ')'  |
			SIN '(' expr ')'  |
			COS '(' expr ')'  |
			TAN '(' expr ')'  |
			ASIN '(' expr ')'  |
			ACOS '(' expr ')'  |
			ATAN '(' expr ')'  |
			NOT '(' expr ')'  |
			DIV '(' expr ',' expr ')' |
			CNP '(' expr ',' expr ')' |
			POW '(' expr ',' expr ')' |
			ANP '(' expr ',' expr ')' ;
 
number	:	HEXVAL |
			afloat |
			'+' afloat |
			'-' afloat |
			NAME ;

afloat		: INTEGER decimal exponent ;

decimal	: 	EMPTY | '.' INTEGER ;

exponent: 	EMPTY | 
			'E' Eexp;

Eexp:	 	INTEGER |
			'-' INTEGER |
			'+' INTEGER ;


%%
/* User Section */

char *p="";
char *yytext="";		/* pointer to character pattern of token */
char *yylast="";		/* pointer to last token */
int yyleng=0;			/* length of current token */
int lookahead=NO_TOKEN;	/* look-ahead token */
char inbuf[LINELEN]={'\0'};
double result=0.0;		/* Return value for the expression */

int yylex(void){
	int ret;

	if (!*p) return EOI;
	while(isspace(*p)) p++; /* skip spaces */

	yytext=p;yyleng=1;
	/* Always point to next symbol before returning ! */
	/* Front line tests do not increment p */
	/* Terminal Symbols */
	if ((*p == '+') || (*p == '-') || (*p == '(') || (*p == ')') || 
		(*p == ',') || (*p == '.') || (*p == '*') || (*p == '/') || 
		(*p == '%') ) 
		ret= *p++;			/* return symbol and point to next char */
	/* Integers & Hex values */
	else if (isdigit(*p)) {
			p++;
			/* Hex value must start with 0x */
			if (*(p-1) == '0' && *p == 'x') {
				p++;yyleng=1;
				if (isxdigit(*p++)) {
					while(isxdigit(*p)) {yyleng++;p++;}
					ret = HEXVAL;
				}
				else ret = NO_TOKEN;
			}
			else {
				while(isdigit(*p)) {yyleng++;p++;}
				ret = INTEGER;
			}
		}
	/* macros start with & and a letter, then a-z 0-9 */
	else if (*p == '&') {
		p++;
		if (isalpha(*p++)) {
			while (isalnum(*p)) {yyleng++;p++;}
			ret = NAME;
		}
		else ret = NO_TOKEN;
	}
	/* all other terminals */
	else if (isalpha(*p)) {
		p++;
		while (isalpha(*p)) {yyleng++;p++;}
		/* Check that it matches any of the known functions */
		switch (yyleng) {
			case 1:
				if ((*yytext == 'E') ||
					(*yytext == 'e')) ret = 'E';
				else ret = NO_TOKEN;
				break;
			case 2:
				if (!strncmp(yytext,"ln",2)) ret = LN;
				else if (!strncmp(yytext,"lg",2)) ret = LG;
				else if (!strncmp(yytext,"or",2)) ret = OR;
				else ret = NO_TOKEN;
				break;
			case 3:
				if (!strncmp(yytext,"Anp",3)) ret = ANP;
				else if (!strncmp(yytext,"pow",3)) ret = POW;
				else if (!strncmp(yytext,"abs",3)) ret = ABS;
				else if (!strncmp(yytext,"and",3)) ret = AND;
				else if (!strncmp(yytext,"Cnp",3)) ret = CNP;
				else if (!strncmp(yytext,"cos",3)) ret = COS;
				else if (!strncmp(yytext,"div",3)) ret = DIV;
				else if (!strncmp(yytext,"exp",3)) ret = EXP;
				else if (!strncmp(yytext,"log",3)) ret = LOG;
				else if (!strncmp(yytext,"not",3)) ret = NOT;
				else if (!strncmp(yytext,"sin",3)) ret = SIN;
				else if (!strncmp(yytext,"tan",3)) ret = TAN;
				else if (!strncmp(yytext,"xor",3)) ret = XOR;
				else ret = NO_TOKEN;
				break;
			default:
				ret = NO_TOKEN;
				break;
		}
	}
	else ret= NO_TOKEN;
	return ret;
}
/* match a token */
int match(int t){
	if(NO_TOKEN==lookahead)
		lookahead=yylex();
	return lookahead==t;
}
/* advance the lookahead to the next token */
void next(void){
	yylast = yytext;
	lookahead=yylex();
}

void yyerror(char *msg){
	printf("Error: %s\n",msg);
	return;
}

void main(int argc,char *argv[])
{
	if (argc>1) p = argv[1];
	yyparse();	
	printf("Value: %g\n",result);
}
/* ------ Last line should be blank for leopurd ------ */

