/* Calc.c */
/* Calculator for any system supporting ANSI C
    (ints are assumed >=16 bits long) */
/* (c) rrw1000@uk.ac.cam.phx 26-12-92 */


#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include "string.h"
#include "time.h"


/* *********************************************************************
	 THE FOLLOWING IS THE TEXT OF PART OF STAX.H AND STAX.C
			  - A DYNAMIC STACK UTILITY.
	   (USE OF STAX IS PERMITTED UNDER THE SAME CONDITIONS AS
				USE OF CALC)
   *********************************************************************  */

/* stax.h */
/* Header for the block-allocating stack software */

typedef struct {
char *pointer;
unsigned long high_water;
size_t member_size;
unsigned long block_size;
} STACK;

/* extern STACK *stackopen(size_t,unsigned long);
extern int stackpop(STACK *,void *);
extern int stackpush(STACK *,void *);
extern void stackclose(STACK *);	    */

/* END FILE */

/* stax.c */
/* Some stack software */

/* #include "stdlib.h"
#include "stax.h" */

STACK *stackopen(size_t,unsigned long);
int stackpop(STACK *,void *);
int stackpush(STACK *,void *);
void stackclose(STACK *);

/* ** THE CODE APPEARS LATER ** */
/* ******************************************************************* */

#define WHERE_RUNNING "IBM 3084/CAM.PHX"
#define NORMAL_RETURN 0
#define ERROR_RETURN 16
#define ERROR_CODE -1
#define MAX_REALS 256
#define MAX_INTS 256
#define PI 3.14159265358979323846    /* If there aren't enough */
#define EXP_E 2.71828182845904523536  /* figures here, tough ! */
#define BITS_IN_LONG 32
#define STACK_SIZE1 128
#define STACK_SIZE2 256


int main(int,char *[]);
int match_token(char *);
void error(char *);
double evaluate(int *,double *,long *,int);
int token_len(int);
void act_on_token(int,STACK *,unsigned long *);
void iact_on_token(int,STACK *,unsigned long *);
int p_ranking(int);
STACK *stack_open(size_t,int);
void stack_push(STACK *,void *);
void stack_pop(STACK *,void *);
void version(void);
void help(void);
void legal(void);
void shortfns(void);
void technical(void);
void porting(void);
void functions(void);
void precedence(void);
void defs(void);

/* Globals .. */

struct {
    int show_actions;
    int show_parsed;
    int show_expr;
    int int_mode;
    int int_hex;
    } gflags;

static char ct[1256],common2[128];

void version() {
   printf("CALC v. 1.31 (C) rrw1000@uk.ac.cam.phx 27-12-92 running at %s.\n",WHERE_RUNNING);
    }

void defs() {
    double pi=PI,e=EXP_E;
    printf("\n       #define directives contain :\n\n");
    printf(" WHERE_RUNNING              %s\n",WHERE_RUNNING);
    printf(" NORMAL_RETURN              %d\n",NORMAL_RETURN);
    printf(" ERROR_RETURN               %d\n",ERROR_RETURN);
    printf(" ERROR_CODE                 %d\n",ERROR_CODE);
    printf(" PI                         %1.15lf\n",pi);
    printf(" EXP_E                      %1.15lf\n",e);
    printf(" MAX_INTS                   %d\n",MAX_INTS);
    printf(" MAX_REALS                  %d\n",MAX_REALS);
    printf(" BITS_IN_LONG               %d\n",BITS_IN_LONG);
    printf(" STACK_SIZE1                %d\n",STACK_SIZE1);
    printf(" STACK_SIZE2                %d\n\n",STACK_SIZE2);
    }
void help() {
    printf("CALC is a general purpose infix expression evaluator designed\n");
    printf(" for those awkward moments where you need the answer to, say,\n");
    printf(" 3*PI/4 or 32/LG(36) but haven't got a calculator handy.\n");
    printf(" Syntax : CALC [<switches>] [<expression>]\n");
    printf("  [<switches>] is a string containing one or more of :\n");
    printf("    -h/-H  Gives help rather than evaluating an expression.\n");
    printf("    -v/-V  Gives the version number and doesn't evaluate.\n");
    printf("    -s/-S  Gives the version number and evaluates.\n");
    printf("    -o/-O  Displays the operations being performed whilst evaluating.\n");
    printf("            (useful for checking that the expression being \n");
    printf("             evaluated is the expression you thought you typed).\n");
    printf("    -n/-N  Doesn't reprint the expression when answering.\n");
    printf("    -l/-L  Gives the conditions of use.\n");
    printf("    -f/-F  Gives the functions recognised by CALC.\n");
    printf("    -t/-T  Gives technical details on CALC.\n");
    printf("    -p/-P  Gives operator precedence information.\n");
    printf("    -m/-M  Gives porting information.\n");
    printf("    -j/-J  Gives a full list of functions and tokens.\n");
    printf("    -i/-I  Selects integer mode.\n");
    printf("            (which allows logic functions and shifts)\n");
    printf("    -x/-X  When used with integer mode, suppresses output in hex. & bin.\n");
    printf("           In real mode, it truncates the output (losing some accuracy \n");
    printf("            in the process.\n\n");
    printf("                   *** RETURN TO CONTINUE ***");
    getchar();
    printf("\n\n It is recommended that you read the conditions of use now if you\n");
    printf(" have not already done so.\n");
    printf("  [<expression>] may be omitted if the first argument begins with -.\n");
    printf("    Note that unary minus is ~ not -.\n");
    printf("    You may enter integers in decimal, or in hexadecimal (suffixed with H),\n");
    printf("     or in binary (suffixed with B) or Octal (suffix O).\n");
    printf("    Note also that due to speed restrictions on the parser in small \n");
    printf("    systems, there is a small but finite chance that an incorrectly \n");
    printf("    typed expression will produce an erroneous answer rather than an \n");
    printf("    error message. This is not a problem in an unmodified version of CALC.\n\n");
    printf(" CALC was written by rrw1000@uk.ac.cam.phx and is Copyright (C) rrw1000\n");
    printf("  26.12.1992 . All rights reserved. You are hereby granted a licence to\n");
    printf("  use and copy CALC as long as this is done in accordance with the \n");
    printf("  conditions of use outlined in CALC -l.\n");
    printf(" The Source code is available from whoever gave you CALC and from the author.\n");
    printf("  Enjoy!\n");
    printf("                                             rrw1000@uk.ac.cam.phx\n\n");
    }


void shortfns() {
    version();
    printf("Functions supported :\n");
    printf("+,-,*,/,~,(,[,),],{,},^,& (AND),# (OR),$ (XOR),% (MOD),! (NOT),<< (LSL),\n");
    printf(">> (LSR),SIN,COS,TAN,SEC,COSEC,COT,SINH,COSH,TANH,SECH,COSECH,COTANH,\n");
    printf("LOG,LN,EXP,LG,ARCSIN,ARCCOS,ARCTAN,ABS,RND,RAN#,RAD,DEG.\n\n");
}

void precedence() {
    version();
    printf("Operator precedence is as follows :\n\n");
    printf("+/- < */divide < ^ (exponentiate) < Logic (&,#,$,%) < Trig. functions\n");
    printf(" < Hyperbolic functions < Log/Ln/Exp functions < Arc Trig \n");
    printf(" < ABS,RND,RAN#,RAD,DEG < ~ (unary -)/! (Logical NOT).\n\n");
    }


void technical() {
    version();
    printf("Technical Notes : \n\n");
    printf("    CALC accepts its input via the command line and runs it through\n");
    printf(" a fairly primitive parser (which is just an FA pared down to the bones\n");
    printf(" to run faster) to get the tokens. It matches tokens one at a time, moving\n");
    printf(" a pointer to the expression on by the length of the token every time one\n");
    printf(" is found. Reals are found and decoded using atof(), and placed in an array\n");
    printf(" of reals of size MAX_REALS. The token for a real is 0x100+ its index in the\n");
    printf(" reals array. The tokenised expression is placed in a dynamically allocated \n");
    printf(" integer array of length = 4 * length of the initial expression (in chars).\n");
    printf(" (which means the array will always be long enough for the expression).\n");
    printf(" This array, and the reals array are fed to the evaluate() function which \n");
    printf(" uses two stacks (set up by the STAX module which is embedded in this file \n");
    printf(" ) to evaluate the infix expression direct with the aid of a function to\n");
    printf(" evaluate tokens. This result is then printed. All very simple, really.\n");
    printf("                    *** RETURN TO CONTINUE ***\n");
    getchar();
    printf("   Though, of course, there are some widgets to remove errant spaces\n");
    printf(" (not that there should be any) and for error reporting etc. . The STAX module\n");
    printf(" implements dynamically allocated linked stack blocks of arbitrary numbers of\n");
    printf(" stack elements. Stacks are polymorphic, but once opened, their type cannot\n");
    printf(" be changed (though due to C's weak typing this cannot be checked, the size of\n");
    printf(" a stack item is written into the stack descriptor block (also dynamically \n");
    printf(" allocated at open time)). When stacks are closed, their blocks are free()d.\n");
    printf(" And,er... that's about it. \n");
    printf("  Apart, of course, from int mode - that works by replacing the evaluate\n");
    printf(" routine and using some if statements and the polymorphism of STAX.\n");
    printf("  Hex, Binary and Octal numbers are done via. special number parser\n");
    printf(" routines kicking about in main() somewhere.\n\n");

    printf(" If you want more details, you can look in the source\n");
    printf(" code because I can't remember them.         rrw1000@uk.ac.cam.phx 26-12-92.\n\n");
}

void porting() {
    version();
    printf("Porting considerations : \n\n");
    printf(" This program has been designed to be portable. To port it to any\n");
    printf("  system which supports ANSI C, just change the #defines at the beginning\n");
    printf("  of the program, make any adjustments necessary if your system doesn't\n");
    printf("  support command line arguments {eg. writing file input routines}, and \n");
    printf("  run it through your local ANSI C compiler.\n");
    printf(" The program tends to assume that ints are 16 bits or larger, and that \n");
    printf("  long ints are 32 bits for printing purposes. The relevant printf() \n");
    printf("  are at the end of the main() function if you need to change them.\n");
    printf(" The program also uses more dynamic memory than is strictly necessary - \n");
    printf("  this can be changed by modifying MAX_REALS and MAX_INTS and the \n");
    printf("  stack_open() calls at the beginning of evaluate(). This should not be \n");
    printf("  and issue for machines which can afford >64k of runtime store.\n\n");
    printf("  And that's it.   rrw1000 26-12-92.\n\n");
    printf(" (NB. On IBM PCs, this program requires a larger stack than 2048 bytes -\n");
    printf("   16384 seems to work well).\n");
    }

void legal() {
    version();
    printf("Conditions of use :\n\n");
    printf("This program may be freely used and copied by all provided :\n");
    printf("\n 1. That this program is not distributed for profit.\n");
    printf(" 2. That this program is not compiled for profit.\n");
    printf(" 3. That these conditions of use are not changed in any way.\n");
    printf(" 4. That any changes to the program are clearly documented\n");
    printf("    in CALC -h, CALC -v, CALC -t AND CALC -l, and that the\n");
    printf("    author's name is not removed from any part of the program.\n");
    printf(" 5. That if you distribute this program as anything other \n");
    printf("    than C source code, you make the C source available as well.\n");
    printf(" 6. THIS PROGRAM IS NOT PUBLIC DOMAIN. It remains the copyright\n");
    printf("     of the author.\n");
    printf("                   *** PRESS RETURN TO CONTINUE ***");
    getchar();
	printf(" 7. This program is supplied 'as is'. No responsibility will be\n");
    printf("    assumed for any consequence of the use, misuse, abuse or inability\n");
    printf("    to use this program. Having said that, MAILing me with error reports\n");
    printf("    may prompt a bug fix, but if you can fix it yourself please do - I\n");
    printf("    am busy enough as it is !\n");
	printf("\n\n THE AUTHOR RESERVES THE RIGHT TO WITHDRAW THIS LICENCE AT ANY\n");
    printf("   TIME IN CASES WHERE HE FEELS LIKE IT. THIS WILL BE COMMUNICATED IN\n");
    printf("   WRITING OR MAIL.\n\n");
    printf(" End conditions. Written by rrw1000@uk.ac.cam.phx 26-12-1992.\n\n");
    }

void functions() {
     version();
     printf("Functions recognised :\n");

printf("	Function		    Token\n\n");
printf("	Real number		    0x00 + number (as a double)\n");
printf("	+			    0x01\n");
printf("	-			    0x02 (binary -)\n");
printf("	*			    0x03           \n");
printf("	/			    0x04           \n");
printf("	(/[			    0x05           \n");
printf("	)/]			    0x06           \n");
printf("	{/}			    Used to enclose comments. \n");
printf("	~			    0x07 Unary - (as in ML)   \n");
printf("				    (Unary + not supported)   \n");
printf("	^			    0x08                      \n");
printf("	&			    0x09 (fix + binary AND)   \n");
printf("	#			    0x0a (fix + binary OR)    \n");
printf("	$			    0x0b (fix + binary XOR)   \n");
printf("	SIN			    0x0c                      \n");
printf("	COS			    0x0d                      \n");
printf("	TAN			    0x0e                      \n");
printf("                   *** RETURN TO CONTINUE ***\n");
getchar();
printf("	SEC			    0x0f                      \n");
printf("	COSEC			    0x10                      \n");
printf("	COTAN			    0x11                      \n");
printf("	SINH			    0x12                      \n");
printf("	COSH			    0x13                      \n");
printf("	TANH			    0x14                      \n");
printf("	SECH			    0x15                      \n");
printf("	COSECH			    0x16                      \n");
printf("	COTANH			    0x17                      \n");
printf("	LOG			    0x18                      \n");
printf("	LN			    0x19                      \n");
printf("	EXP			    0x1A                      \n");
printf("	ARCSIN			    0x1B                      \n");
printf("	ARCCOS			    0x1C                      \n");
printf("	ARCTAN			    0x1D                      \n");
printf("	ABS			    0x1E                      \n");
printf("	RND			    0x1F (Round argument)     \n");
printf("	RAN#			    0x20 (Random no. 0<=r<=1, no arguments) \n");
printf("                   *** RETURN TO CONTINUE ***\n");
getchar();
printf("	PI			    0x21                      \n");
printf("	E			    0x22                      \n");
printf("	RAD			    0x23                      \n");
printf("	DEG			    0x24                      \n");
printf("	LG			    0x25 (LOG to the base 2)  \n");
printf("	SQRT			    0x26                      \n");
printf("        !                           0x27 (Logical NOT)        \n");
printf("        <<                          0x28 (ASL) (Ints only)    \n");
printf("        >>                          0x29 (ASR) (Ints only)    \n");
printf("        %c                           0x2a (A MOD B)            \n\n",'%');

printf("    The fixed constants PI = 3.1415 .... and E = 2.718....     \n");
printf("     may be included in expressions. Expressions are passed    \n");
printf("     on the command line.                                     \n\n");
}

STACK *stack_open(size_t a,int b) {
STACK *t;

if ((t=stackopen(a,b))==NULL) error("Could not open stack.");

/* printf("Stack opened ... size %d blocks %d\n",a,b);
getchar(); */
return t;
}

void stack_push(STACK *a,void *b) {

if (stackpush(a,b)==0) error("Stack error (PUSH).");

/* printf("Pushed %d (%f) on stack %d\n",*((int *)b),*((double *)b),a);
getchar(); */
}

void stack_pop(STACK *a,void *b) {

if (stackpop(a,b)==0) error("Stack error (POP).");

/* printf("Pulled %d (%f) from stack %d\n",*((int *)b),*((double *)b),a);
getchar(); */
}


int p_ranking(int a) {

if (a<0x03) return 1; /* +,- */
if (a<0x05) return 2; /* * and / */
if (a==0x07) return 13; /* Unary - */
if (a==0x08) return 6; /* ^ */
if (a==0x05) return -1; /* ( has lowest priority, ) does not occur */
if (a<0x0c) return 7; /* Logic operators */
if (a==0x27) return 13;
    if (a>0x26 && a<0x2B) return 7;  /* More logic */
if (a<0x12) return 8; /* Trig functions */
if (a<0x17) return 9; /* Hyperbolic Functions */
if (a<0x1b) return 10; /* Log, ln, exp-type functions */
if (a==0x26) return 10; /* LG */
if (a<0x1e) return 11; /* Misc. functions */
return 12;
}

void iact_on_token(int opcode,STACK *oprn,unsigned long *oprnsptr) {
unsigned long oprns=*oprnsptr;
long a,b,c;
int i;

stack_pop(oprn,&b); oprns--;
stack_pop(oprn,&a);

/* ^^^ Arguments come off the stack in reverse order */


/* The following actions map c-> a,b */

switch (opcode) {
	case 0x01: c=a+b; break;
	case 0x02: c=a-b; break; /* NOTE THE ORDER OF OPERATION ! */
	case 0x03: c=a*b; break;
	case 0x04: c=a/b; break;
	case 0x07: c=-b; break; /* UNARY OPERATOR - IGNORE 1ST ARGUMENT */
	case 0x08: c=1; for (i=0;i<b;i++) c*=a; break;
	case 0x09: c=a & b; break; /* fix(a) & fix(b) */
	case 0x0a: c=a | b; break;
	case 0x0b: c=a ^ b; break;
	case 0x18: c=(long)log10((double)b); break;
	case 0x19: c=(long)log((double)b); break;
	case 0x1f: c=b; break;
	case 0x20: c=rand(); break;
	case 0x25: c=(long)(log((double)b)/log(2)); break;
	case 0x26: c=(long)sqrt((double)b); break;
	case 0x27: c=~b; break;
	case 0x28: c=a>>b; break;
	case 0x29: c=a<<b; break;
	case 0x2a: c=a%b; break;
	default: error("Invalid operation on an Int. Try again without the -i switch.");break;
	}

if (gflags.show_actions) {
sprintf(ct,"%2x",opcode);
for (i=0;i<2;i++) if (ct[i]==0x20) ct[i]='0';
printf("ACTION: Integer Operation 0x%s applied to %ld,%ld giving %ld\n",ct,a,b,c); }

    stack_push(oprn,&c);
*oprnsptr=oprns;

    }

void act_on_token(int opcode,STACK *oprn,unsigned long *oprnsptr) {
unsigned long oprns=*oprnsptr;
double a,b,c;
int i;


stack_pop(oprn,&b); oprns--;
stack_pop(oprn,&a);
/* ^^^ Arguments come off the stack in reverse order */


/* The following actions map c-> a,b */

switch (opcode) {
	case 0x01: c=a+b; break;
	case 0x02: c=a-b; break; /* NOTE THE ORDER OF OPERATION ! */
	case 0x03: c=a*b; break;
	case 0x04: c=a/b; break;
	case 0x07: c=-b; break; /* UNARY OPERATOR - IGNORE 1ST ARGUMENT */
	case 0x08: c=pow(a,b); break;
	case 0x09: c=(double)(((long)a) & ((long)b)); break; /* fix(a) & fix(b) */
	case 0x0a: c=(double)(((long)a) | ((long)b)); break;
	case 0x0b: c=(double)(((long)a) ^ ((long)b)); break;
	case 0x0c: c=sin(b); break;
	case 0x0d: c=cos(b); break;
	case 0x0e: c=tan(b); break;
	case 0x0f: c=1.0/cos(b); break;
	case 0x10: c=1.0/sin(b); break;
	case 0x11: c=1.0/tan(b); break;
	case 0x12: c=sinh(b); break;
	case 0x13: c=cosh(b); break;
	case 0x14: c=tanh(b); break;
	case 0x15: c=1.0/cosh(b); break;
	case 0x16: c=1.0/sinh(b); break;
	case 0x17: c=1.0/tanh(b); break;
	case 0x18: c=log10(b); break;
	case 0x19: c=log(b); break;
	case 0x1a: c=exp(b); break;
	case 0x1b: c=asin(b); break;
	case 0x1c: c=acos(b); break;
	case 0x1d: c=atan(b); break;
	case 0x1e: c=fabs(b); break;
	case 0x1f: modf(b,&c); break;
	case 0x20: c=((double)rand()/(double)RAND_MAX); break;
	case 0x23: c=PI*b/180.0;break;
	case 0x24: c=180.0*b/PI; break;
	case 0x25: c=log(b)/log(2); break;
	case 0x26: c=sqrt(b); break;
	case 0x27: c=-b;break;
	case 0x28: error("Invalid operation for non-integer.");break;
	case 0x29: error("Invalid operation for non-integer.");break;
	case 0x2a: c=a; while (c>=b) c-=b; break;
	default: error("Unrecognised operation (EVAL).");break;
	}

if (gflags.show_actions) {
sprintf(ct,"%2x",opcode);
for (i=0;i<2;i++) if (ct[i]==0x20) ct[i]='0';
printf("ACTION: Operation 0x%s applied to %g,%g giving %g\n",ct,a,b,c); }

    stack_push(oprn,&c);
*oprnsptr=oprns;

    }

double evaluate(int *expr,double *reals,long *ints,int expl) {
STACK *oper,*oprn;
unsigned long i,j,opers,oprns,incount;
double a;
long z;
int topchar;



/* Infix evaluation algorithm - see
    Data structures, Algorithms, and program style using C,
    Korsh & Garett p. 203 */

/* Initialise a couple of stacks */
/* 1 + 2 */

oper=stack_open(sizeof(int),STACK_SIZE1);
if (gflags.int_mode) oprn=stack_open(sizeof(long),STACK_SIZE2); else
    oprn=stack_open(sizeof(double),STACK_SIZE2);

if (oper==0 || oprn==0) error("Stack error (OPEN).");

/* 3 */

incount=0;	/* Input counter */
opers=0; /* Operator stack members */
oprns=0; /* Operand stack members */




    while (incount<expl) {
    i=expr[incount]; incount++;
     if (i==0x05) {
	   stack_push(oper,&i); opers++;}
	if (i>0xff) {
	     if (gflags.int_mode==0) { a=reals[i-0x100]; stack_push(oprn,&a);}
		else { z=ints[i-0x100]; stack_push(oprn,&z);};
	    oprns++;
	     }
	if (i<=0xff && i!=0x06 && i!=0x05) {
	       if (opers>0) {
		   stack_pop(oper,&j);
		 if (p_ranking(i)<=p_ranking(j)) {
		   if (!gflags.int_mode) act_on_token(j,oprn,&oprns);
		    else iact_on_token(j,oprn,&oprns);
			opers--;
		    }
		  else stack_push(oper,&j);
		    }
		  stack_push(oper,&i); opers++;}


      if (i==0x06) {
		 stack_pop(oper,&topchar);opers--;
	       while (topchar!=0x05) {
		  if (!gflags.int_mode) act_on_token(topchar,oprn,&oprns);
		    else iact_on_token(topchar,oprn,&oprns);
		  stack_pop(oper,&topchar);opers--;
		  }




	    }
	  } /* I _!think!_ that's right */

/* 4 */

while (opers>0) {
      stack_pop(oper,&topchar); opers--;
      if (!gflags.int_mode) act_on_token(topchar,oprn,&oprns);
	   else iact_on_token(topchar,oprn,&oprns);
      }

/* 5 */

a=0;
if (gflags.int_mode) stack_pop(oprn,&ints[0]); else stack_pop(oprn,&a);

stackclose(oper);
stackclose(oprn);

return a;
}

int main(int argn,char *args[]) {
unsigned long i,j,k,l,m,n;
long z;
int base;
double a;
int *expr,ex,cup;
char x,*exptr,*chrdptr,cmn[130],blk[128];
static double reals[MAX_REALS];
static signed long ints[MAX_INTS];


/* Seed the random number generator with the time ... */

i=0;

srand((unsigned int)time((time_t *)&i));

for(i=0;i<20;i++) rand();

/* Basically, we parse the expression to a dynamic array of size = exp .size */
/* This array will not even be slightly full. */
/* Up to 256 real numbers are permitted - reals are stored as :
  token = 0x100 + index */

if (argn<2) error("No expression.");
if (argn>3) error("Too many arguments.");

ex=argn-1;
exptr=args[ex];

/* Assume the expression is in args[1] ... */
/* And the switches are in args[2]. */
/* Switches : */


if (exptr[0]=='-') { argn=3; exptr=args[2];}; /* Force switch processing */

gflags.show_actions=0;
gflags.show_expr=1;
gflags.int_mode=0;
gflags.int_hex=1;

if (argn>=3) {
    for (i=0;i<strlen(args[1]);i++)
	    args[1][i]=toupper(args[1][i]);

   if (strstr(args[1],"-O")!=NULL)
			gflags.show_actions=1;
   if (strstr(args[1],"-H")!=NULL) {
			help(); return NORMAL_RETURN; };
   if (strstr(args[1],"-V")!=NULL) {
			version(); defs(); return NORMAL_RETURN;};
   if (strstr(args[1],"-S")!=NULL) {
			version(); defs();}
   if (strstr(args[1],"-N")!=NULL)
			 gflags.show_expr=0;

   if (strstr(args[1],"-L")!=NULL) {
		legal(); return NORMAL_RETURN;};
   if (strstr(args[1],"-F")!=NULL) {
		shortfns(); return NORMAL_RETURN;};
   if (strstr(args[1],"-T")!=NULL) {
		technical(); return NORMAL_RETURN;};
    if (strstr(args[1],"-J")!=NULL) {
		functions(); return NORMAL_RETURN;};
    if (strstr(args[1],"-P")!=NULL)  {
		precedence(); return NORMAL_RETURN;};
    if (strstr(args[1],"-M")!=NULL)   {
		porting(); return NORMAL_RETURN;};
    if (strstr(args[1],"-I")!=NULL) gflags.int_mode=1;
    if (strstr(args[1],"-X")!=NULL) gflags.int_hex=0;


	 /* Rest of the switches go here .... */
   }

if (gflags.int_mode) printf("Integer mode set.\n");
i=0;
while (exptr[0]==' ' && exptr[0]!=0x00) exptr++;
    while (exptr[i]!=0x00) {
    exptr[i]=toupper(exptr[i]); i++;}; /* Expensive but it has to be done */
if (i<=0) error("Expression is non-existent or too long");
if ((expr=malloc(i*sizeof(int)))==NULL) { error("Insufficient store (EXPR)."); };

j=0; /* String counter .. */
k=2; /* Real counter - starts at 2 because of E and PI	*/
m=0; /* expr counter */
/* Parse loop ... */

/* In order to satistfy the infix routine (which expects expressions to
    have only binary operators), reals[0]=0 initially, and this
     is placed before all binary operators. */

/* ********** THE FOLLOWING MUST BE UPDATED ****** */
reals[0]=PI; ints[0]=0;
reals[1]=EXP_E; ints[1]=0xffffffff;
/* *********************************************** */

do {
     if ((l=match_token(&exptr[j]))==ERROR_CODE) {
     sprintf(ct,"Parse failed reading token at : %s.",exptr+j);
     error(ct);
     }
  /*
   l now holds the matching token */
  /* ... */
  if (l==0xff) {
       /* Comment */
       while (((exptr[j]))!='}' && j<i ) j++;
	if (j>=i) error("End of expression in a comment.");
	j++;
    } else {
      if (l==0) {

	n=(j--);
     if (gflags.int_mode) {
	 do {
	j++;
	x=((exptr[j]));
	ct[j-n]=x;
	    } while (x=='0' || x=='1' || x=='2'
	    || x=='3' || x=='4' || x=='5' || x=='6' || x=='7'
	    || x=='8' || x=='9' || x=='.' || x=='A' || x=='B'
	    || x=='C' || x=='D' || x=='E' || x=='F');
     ct[j+1]=0x00;
	base=10;
	if (x=='H') base=16;
	if (exptr[j-1]=='B' && base!=16)  base=2;
	if (x=='O') base=8;

		if (base!=10) j++;
z=strtol(ct,&chrdptr,base);
		ints[k]=z;k++;
		if (k>(MAX_INTS-1)) {
		     sprintf(ct,"Ran out of ints (%d maximum).\n Recompile with larger MAX_INTS.",MAX_INTS);
		error(ct);	 }
		} else {

		 do {
	j++;
	x=((exptr[j]));
	ct[j-n]=x;
	    } while (x=='0' || x=='1' || x=='2'
	    || x=='3' || x=='4' || x=='5' || x=='6' || x=='7'
	    || x=='8' || x=='9' || x=='.' || x=='E' || x=='e');
     ct[j+1]=0x00;

	a=atof(ct);

    /* Finished ! */
     reals[k]=a; k++;
      if (k>(MAX_REALS-1)) {
	sprintf(ct,"Ran out of reals (%d maximum).\n Recompile with larger MAX_REALS.",MAX_REALS);
	error(ct);
	}
    }
    expr[m]=0x100+(k-1);
    m++;
    /* Incremented j by the appropriate amount... */
   } else {
      j+=token_len(l);
      if (token_len(l)==ERROR_CODE) error("Unknown Operator (LEN).");
      if ((l>0x0b || l==0x07) && l!=0x21 && l!=0x22 && l!=0x2a) { expr[m]=0x100; m++;};
      if (l==0x20) { expr[m]=0x100;m++;}; /* RAN# has no operands */
      if (l==0x21 || l==0x22) { l=(0x100+l-0x21);};
      expr[m]=l;m++;
      }
    }
    while (j<i && (exptr[j]==' ' || exptr[j]==';' || exptr[j]==':')) j++;	/* Strip spaces & ;s.. */
    } while (j<i);


/* OK. Done parsing */
/* Expression is now tokenised in the reals and expr arrays */
/*  Now evaluate and exit */

a=evaluate(expr,reals,ints,m);

cup=0;sprintf(cmn,"ERROR");
if (gflags.int_mode && gflags.int_hex) {
    cup=125; cmn[126]=0x00;
	z=ints[0];

  for (i=0;i<BITS_IN_LONG;i++) {
    if (cup%5==0) cmn[cup--]=' ';
    if (z&1==1) cmn[cup]='1'; else cmn[cup]='0';
    cup--; z>>=1;
   }
	  }


if (gflags.show_expr) {
memset(blk,' ',50);
blk[50]=0x00;

    if (gflags.int_mode) {
	if (gflags.int_hex) {
	       blk[30]=0x00;
	       printf("%s\n%s = %ld\n",exptr,blk,ints[0]);
	       printf("%s = %08lXH\n",blk,ints[0]);
	       printf("%s = %012loO\n",blk,ints[0]);
	       printf("%s = %sB\n",blk,cmn+cup+1);
	      }
		  else
	  { printf("%s\n%s = %ld",exptr,blk,ints[0]); }
	 }
	else
	{ if (gflags.int_hex) printf("%s\n%s= %.15lf\n",exptr,blk,a);
	       else printf("%s\n%s = %lg\n",exptr,blk,a); }
	  }  else {

  if (gflags.int_mode)	{
    if (gflags.int_hex)  {printf("Value = %ld\n",ints[0]);
	printf(" = %08lXH  ",ints[0]);
	printf(" = %012loO ",ints[0]);
	printf("  = %sB",cmn+cup+1);} else
	printf("Value = %ld\n",ints[0]); } else
      { if (gflags.int_hex) printf("Value = %.15lf\n",a);
			   else printf("Value = %lg\n",a);
      } }

free((char *)expr);
return NORMAL_RETURN;
}





int token_len(int token) {

/* This part of the program could be coded much better by including it in the
parser (in match_token) */

if (token==0x00) return ERROR_CODE;
if (token>0x00 && token<0x0c) return 1;
if (token>0x0b && token<0x10) return 3;
if (token==0x10 || token==0x11) return 5;
if (token>0x11 && token<0x16) return 4;
if (token==0x16 || token==0x17) return 6;
if (token==0x18) return 3;
if (token==0x19) return 2;
if (token==0x1a) return 3;
if (token>0x1a && token<0x1e) return 6;
if (token==0x20) return 4;
if (token>0x1d && token<0x21) return 3;
if (token==0x23 || token==0x24) return 3;
if (token==0x21) return 2;
if (token==0x22 || token==0x27 || token==0x2a) return 1;
if (token==0x25) return 2;
if (token==0x26) return 4;
if (token==0x28 || token==0x29) return 2;

/* If we get here, unrecognised opcode so ... */
return ERROR_CODE;

}




void error(char *what) {
printf("\n ERROR : %s\nHas occured.\n CALC dying (type CALC -h for help).\n\n",what);
exit(ERROR_RETURN);
}

int match_token(char *token) {

/* NOTE : Formalising the code below would be a good thing to do
if someone has the time to do it. */
/* A parser generator would have been a good idea if I'd had one */

switch (token[0]) {
    case '0':case '1':case '2':case '3':case '4':
	case '5':case '6':case '7':case '8': case '9' : case '.' : case 'B':
	     case 'F':
	    return 0x00; break;
	/* NB. The above code requires special action
	    on the part of the caller. Note that
       if (token[0]>='0' && token[0]<='9') .... would not
	 work on all systems because 0-9 may not always
	 be adjacent. Also '0' may not always be the lowest
	 value or '9' the highest. */
    case '<' : return 0x29; break; /* Must be << */
    case '>' : return 0x28; break; /* must be >> */
    case '!' : return 0x27; break;
    case '+' : return 0x01 ;break;
    case '-' : return 0x02 ;break;
    case '*' : return 0x03 ;break;
    case '/' : return 0x04 ;break;
    case '(' : case '[' : return 0x05; break;
    case ')' : case ']' : return 0x06; break;
    case '{' : return 0xff; break; /* <<< this also requires special action */
    case '~' : return 0x07; break;
    case '^' : return 0x08; break;
    case '&' : return 0x09; break;
    case '#' : return 0x0a; break;
    case '$' : return 0x0b; break;
    case '%' : return 0x2a; break;
    case 'S' : /* Codes beginning with S */
	switch(token[1]) {
	    case 'Q' : /* Token must be SQRT */
			return 0x26;break;
	    case 'I' : /* Token must  be SIN or SINH*/
		      switch(token[3]) {
			 case 'H': return 0x12; break;
			  default : return 0x0c; break;
			    }
			break;
	    case 'E' : /* Token must be SEC or SECH*/
		      switch (token[3]) {
			 case 'H' : return 0x15; break;
			 default : return 0x0f; break;
			    }
		      break;
	    default: return ERROR_CODE; break;
	    }
	     break;
    case 'C' : if (gflags.int_mode) { /* It must be a number */
				    return 0;};
	/* ... and here we go again ! */
	 switch(token[3]) {
	       case 'E': /* Token must be COSEC or COSECH */
		   switch (token[5]) {
		      case 'H': return 0x16; break;
		      default : return 0x10; break;
			} break;
	       case 'A': /* Token must be COTAN or COTANH */
		       switch (token[5]) {
			case 'H': return 0x17; break;
			default : return 0x11; break;
			    } break;
	       case 'H': /* Token must be COSH */
			return 0x13;break;
	       default : /* Token is COS */
			return 0x0d;break;
		  }
		break;
    case 'T' : /* TAN et al. */
	   switch (token[3]) {
		case 'H': return 0x14;break;
		default : return 0x0e;break;
		    }
	    break;
    case 'L' : /* LOG & LN */
	      switch (token[1]) {
		  case 'O': return 0x18; break;
		  case 'N': return 0x19; break;
		  case 'G': return 0x25;break;
		  default : return ERROR_CODE; break;
		    }
		break;
    case 'E' : if (gflags.int_mode) return 0;	/* Must be a number */
	/* EXP or E */
	   switch (token[1]) {
	     case 'X':
	      return 0x1a; break;
	     default : return 0x22; break;
		}
	    break;

    case 'A' : if (gflags.int_mode) return 0; /* Must be a number */
	/* ARCSIN, ARCCOS, ARCTAN, ABS ... */
	    switch (token[1]) {
		case 'B': /* ABS */
			 return 0x1e; break;
		case 'R':
		    switch (token[3]) {
			case 'S': return 0x1b; break;
			case 'C': return 0x1c; break;
			case 'T': return 0x1d; break;
			default : return ERROR_CODE; break;
			} break;

		default: return ERROR_CODE;break;
		}

    case 'R' : /* RND, RAN# */
	    switch (token[1]) {
		 case 'N': return 0x1f; break;
		 case 'A':  /* Could be RAN# or RAD */
		    switch (token[2]) {
		      case 'D': return 0x23; break;
		      case 'N': return 0x20; break;
		      default : return ERROR_CODE; break;
			}; break;
		 default : return ERROR_CODE; break;
		    }
	     break;
     case 'P' : /* PI */
		 return 0x21; break;

     case 'D': if (gflags.int_mode) return 0; /* Must be a number */
		/* DEG */
		return 0x24; break;

   default: return ERROR_CODE; break;
  }

/* If we find ourselves here, our parser has let us down badly */
/* but it's an error condition anyway, so .. */

error("Parser fault (DROPTHROUGH).");
return ERROR_CODE;

}


/* THE STAX ROUTINES ... */

void stackclose(STACK *h) {
char *a;

do {
    if (*(char **)h->pointer!=0) {
	a=*(char **)h->pointer;
				  free(h->pointer);
				  h->pointer=a; };
    } while (*(char **)h->pointer!=0);

free(h->pointer);
free(h);
/* Stack closed */
}

STACK *stackopen(size_t size,unsigned long pack_number) {
STACK *handle;


if (pack_number<4) pack_number=4;

if ((handle=(STACK *)malloc(sizeof(STACK)))==NULL) return NULL;

handle->high_water=0;
handle->member_size=size;
handle->block_size=pack_number;
if ((handle->pointer=(char *)malloc(handle->block_size*handle->member_size+sizeof(char *)))==NULL) return NULL;

*((char **)handle->pointer)=0;

return handle;
}

int stackpop(STACK *h,void *here) {
char *a;

if (h->high_water>0) {
	       h->high_water--;
	       memcpy((char *)here,(char*)(h->pointer+(h->member_size*h->high_water)+sizeof(char *)),h->member_size);
	       return 1;
	       } else {

		/* chain back into previous block and free this one */

	       a=*((char **)h->pointer); /* Get the address of the last block */
	       if (a==0) return 0; /* Bottom of the stack */
	       free(h->pointer); /* Free the memory taken up */
	       h->pointer=a; h->high_water=h->block_size;
	       /* call yourself to execute the previous bit again... */
	       return stackpop(h,here);
	       }

     }

int stackpush(STACK *h,void *there) {
    char *a;

    if (h->high_water<h->block_size) {
	    /* There is space in this block */
	    memcpy((char *)(h->pointer+sizeof(char *)+(h->member_size*h->high_water)),(char *)there,h->member_size);
	    h->high_water++;
	    return 1;
	    } else {
       /* We have to assign another block (sigh ...) */
	 if ((a=malloc((h->member_size*h->block_size)+sizeof(char *)))==NULL) { return 0;};
	 *(char **)a=h->pointer;
	 h->pointer=a;
	 h->high_water=0;
	 stackpush(h,there);
	 }

}

/* END FILE - CALC.C */

