/***(OperatorStack.m)**********************************************************
*H* Push down stack for numeric operators                     V0.0, 09-FEB-91 *
*C* V0.0 09-FEB-91 Initial version                                      --MDM *
******************************************************************************/

/* Standard C Library includes */
#import <stdio.h>   	    /* Standard I/O functions and definitions */
#import <stdlib.h>  	    /* Standard C memory allocation prototypes */

#import "OperatorStack.h"	    /* OperatorStack interface specification */


/* Class Private Data */
typedef struct OSoperator
    {
    char *name;
    int	  precedence;
    int   n_operands;
    } OToperator;

/* Table describing each operator */
static OToperator OVopTable[OPCODE_OpCodes] =
    {
    	{ "Equals",   	 4, 1 },
    	{ "Plus",   	14, 2 },
    	{ "Minus",  	14, 2 },
    	{ "Multiply", 	15, 2 },
    	{ "Divide", 	15, 2 },
    	{ "OpenParen",	 5, 0 },
    	{ "CloseParen",  6, 0 },
    	{ "SIN",        17, 1 },
    	{ "ASIN",       17, 1 },
    	{ "SINH",       17, 1 },
    	{ "ASINH",      17, 1 },
    	{ "COS",        17, 1 },
    	{ "ACOS",       17, 1 },
    	{ "COSH",       17, 1 },
    	{ "ACOSH",      17, 1 },
    	{ "TAN",        17, 1 },
    	{ "ATAN",       17, 1 },
    	{ "TANH",       17, 1 },
    	{ "ATANH",      17, 1 },
    	{ "EXP",    	17, 1 },
    	{ "LN",	    	17, 1 },
    	{ "LOG",    	17, 1 },
    	{ "10^X",   	17, 1 },
    	{ "X^Y",    	16, 2 },
    	{ "XrootY", 	16, 2 },
    	{ "XSquared",	17, 1 },
    	{ "SqrRoot",	17, 1 },
    	{ "1overX", 	17, 1 },
    	{ "Factorial",  17, 1 },
    	{ "Pi",         17, 1 },
    	{ "Modify",     15, 2 },
    	{ "Integer",    17, 1 },
    	{ "And",        10, 2 },
    	{ "Or",          8, 2 },
    	{ "Not",        17, 1 },
    	{ "Xor",         9, 2 },
    	{ "LShift",     17, 1 },
    	{ "RShift",     17, 1 }
    };



@implementation OperatorStack


/* Private Object Wide Definitions */
#define OCnullStack 	(OToperStackItem *) 0



/******************************************************************************
* INSTANCE METHOD:- init    	    	    	    	    	    	      *
*   Initialize a new instance of a OperatorStack class.     	   	      *
******************************************************************************/
- init

{/* BEGIN:-init */
self = [super init];
OVstackTop  = OCnullStack;
OVstackSize = 0;
return self;
}/* END:-init */



/******************************************************************************
* INSTANCE METHOD:- free 	    	    	    	    	    	      *
*   All data currently on the OperatorStack is poped and freed, returning the *
* allocated memory back to the system pool. 	    	    	    	      *
******************************************************************************/
- free

{   /* Local Variables */
    OToperStackItem *tmp_blink;

/* BEGIN free */
while (OVstackTop != OCnullStack)
    {/* Get pointer to lower stack item and free top item */
    tmp_blink = OVstackTop->blink;
    free( (char *) OVstackTop );
    OVstackTop  = tmp_blink;
    OVstackSize = 0;
    }

/* Request super class to perform its free method */
return [super free];
}/* END free */



/******************************************************************************
* INSTANCE METHOD:- ClearStack 	    	    	    	    	    	      *
*   Pop and free each element on the stack until the stack is empty.          *
******************************************************************************/
- ClearStack

{   /* Local Variables */
    OToperStackItem  *tmp_blink;

/* BEGIN Clear */
while ( OVstackTop )
    {/* Stack is not empty, free top item */
    tmp_blink  = OVstackTop->blink;
    free ( (char *) OVstackTop );
    OVstackTop = tmp_blink;
    }

OVstackSize = 0;
return self;
}/* END ClearStack */



/******************************************************************************
* INSTANCE METHOD:- ComparePrecedence       	    	    	    	      *
*   Compares the  precedence  of  opcode against the opcode on the top of the *
* stack and returns the difference in the result argument.  The comparison is *
* made by subtracting the  numerical  precedence value of the supplied opcode *
* with that of the opcode on the top of the stack.  If the stack is empty the *
* supplied  opcode  is  compared  against  a  precedence  value of zero.  The *
* returned value has the following meanings:	    	  	    	      *
*   	result >= 1: opcode has higher precedence stack top opcode.    	      *
*   	result == 0: opcode and stack top opcode are of equal precedence.     *
*   	result <= 1: opcode is of lesser precedence than stack top opcode.    *
******************************************************************************/
- ComparePrecedence: (int) opcode: (int *) result

{/* BEGIN ComparePrecedence */
if (opcode < 0 || opcode > OPCODE_LastOpCode)
    return nil;    /* return failure status */

if ( OVstackSize > 0 )
    /* Stack is not empty, use precedence of opcode on stack top */
    *result = OVopTable[opcode].precedence - OVopTable[OVstackTop->opcode].precedence;
else
    /* Stack is empty, assume a precedence value of zero */
    *result = OVopTable[opcode].precedence - 0;

return self;
}/* END ComparePrecedence */



/******************************************************************************
* INSTANCE METHOD:- GetSize    	    	    	    	    	    	      *
*   Return the current number of items in the Value Stack.  	    	      *
******************************************************************************/
- (unsigned long) GetSize

{/* BEGIN GetSize */
return OVstackSize;
}/* END GetSize */



/******************************************************************************
* INSTANCE METHOD:- NumberOfOperands   	    	    	    	    	      *
*   Return the operands that the given opcode requires.	    	    	      *
******************************************************************************/
- NumberOfOperands :(int)opcode :(int*)noperands

{/* BEGIN NumberOfOperands */
if ( opcode >= OPCODE_Equals && opcode <= OPCODE_LastOpCode )
    {/* The caller supplied a legal opcode, return successfully */
    *noperands = OVopTable[opcode].n_operands;
    return self;
    }

else
    /* The caller supplied an invalid opcode, return with error status */
    return nil;
}/* END NumberOfOperands */



/******************************************************************************
* INSTANCE METHOD:- Peek    	    	    	    	    	    	      *
*   Return the value on the top  of  the  stack  without removing it from the *
* stack.    	    	    	    	    	    	    	    	      *
******************************************************************************/
- Peek: (int *) opcode

{/* BEGIN Peek */
if ( OVstackTop )
    {/* The stack is not emptry */
    *opcode = OVstackTop->opcode;
    return self;    /* succesful status */
    }
else
    {/* Report illegal reference to standard error */
#ifdef DEBUG
    fprintf(stderr, "OperatorStack: Peek on empty stack returning -1\n");
#endif
    *opcode = -1;
    return nil;    /* failure status */
    }
}/* END Peek */



/******************************************************************************
* INSTANCE METHOD:- Pop      	    	    	    	    	    	      *
*   Return the value opcode on the top of the stack and free top stack item.  *
******************************************************************************/
- Pop: (int *) opcode

{   /* Local Variables */
    OToperStackItem  *tmp_blink;

/* BEGIN Pop */
if ( OVstackTop )
    {/* Stack is not empty, free top item and return top value */
    *opcode = OVstackTop->opcode;
    tmp_blink  = OVstackTop->blink;
    free ( (char *) OVstackTop );
    OVstackTop = tmp_blink;
    OVstackSize--;
    return self;
    }

else
    {/* Stack is empty report error, return -1 */
#ifdef DEBUG
    fprintf(stderr, "OperatorStack: Pop on empty stack returning -1\n");
#endif
    *opcode = -1;
    return nil;	    /* failure status */
    }
}/* END Pop */



/******************************************************************************
* INSTANCE METHOD:- Push      	    	    	    	    	    	      *
*   Push an opcode value on the stack.   We allocate a new stack item setting *
* its opcode field to the supplied opcode value, and its blink field to point *
* to the current stack top.  If a new stack item cannot be allocated an error *
* message is written to stderr.	    	    	    	    	    	      *
******************************************************************************/
- Push: (int) opcode

{   /* Local Variables */
    OToperStackItem  *new_item;

/* BEGIN Push */
/* Allocate a new stack item */
new_item = (OToperStackItem *) malloc(sizeof(OToperStackItem));

if ( new_item )
    {/* New stack item allocated, initialize and link in new stack top */
    new_item->opcode = opcode;
    new_item->blink = OVstackTop;
    OVstackTop = new_item;
    OVstackSize++;
    return self;    
    }

else
    {/* Allocation failed, report error to stderr */
#ifdef DEBUG
    fprintf(stderr, "OperatorStack: Push allocation failure\n");
#endif
    return nil;
    }
}/* END Push */



/******************************************************************************
* INSTANCE METHOD:- PrintStack      	    	    	    	    	      *
*   Print out the contents of the stack to standard output. 	    	      *
******************************************************************************/
- PrintStack

{   /* Local Variables */
    OToperStackItem  *trace_link;
    int	    	      oti;  	    /* operator table index */
    long  	      level;

/* BEGIN PrintStack */
if ( OVstackTop )
    {/* The stack is not empty so dump its contents */
    trace_link = OVstackTop;
    level      = 0;

    while ( trace_link )
    	{/* Not at bottom, print this item */
    	oti = trace_link->opcode;
#ifdef DEBUG
    	printf("%s\t%d\t%d\t:(%ld)\n",
    	       OVopTable[oti].name,
    	       OVopTable[oti].precedence,
    	       OVopTable[oti].n_operands,
    	       level--);
#endif
    	trace_link = trace_link->blink;
    	}
    }

else
    {/* Stack is empty so print a message */
#ifdef DEBUG
    printf("OperatorStack: stack empty\n");
#endif
    }

return self;
}/* END PrintStack */



@end /* ValueStack Implementation */
