www.pudn.com > calc.rar > parse.y
/* parse.y */
/* Notes on the stacks that have been added.
* There are two stacks. argStack and varStack.
* The argStack contains objects of type Argument which you will find in
* calc.h. They contain various bits of information about arguments.
* The varStack is what is passed to the functions. It contains pointers
* to the _actual_ arguments. This saves much typing when making the wrapper
* functions.
*/
%{
#include
#include
#include
#include
#include "integer.h"
#include "fun.h"
#include "calc.h"
#include "stack.h"
#define POLYID 'X'
union {
MPI *mpi;
POLYI polyi;
} retval;
int rettype; /* 0 for nothing, 1 for MPI, 2 for POLYI, 3 for failure of
* function */
int yyparse(void);
int yylex(void);
%}
%union {
MPI *val; /* actual value */
POLYI pol;
Stack argStack;
MPIA arr;
Symbol *sym; /* symbol table pointer */
}
%token NUMBER
%token POL
%token ARGSTACK
%token ANARRAY
%token ARRAY POLYVAR VAR POLYTERM BLTIN BLTINV BLTINP UNDEF
%type expr varassign VOID
%type polyassign polyexpr
%type arrayassign arraylist
%type arguments arglist
%right '=' /*lowest precedence */
%left '+' '-'
%left '*' '/' '%' ','
%right '^'
%left UNARYMINUS /* highest precedence */
%%
list:
| list '\n'
| list varassign '\n'
{
retval.mpi = $2;
rettype=RET_MPI;
}
| list arrayassign '\n'
{
rettype=RET_MPIA;
}
| list expr '\n'
{
retval.mpi = $2;
if (!(rettype == FUNC_FAIL)) {
PRINTI($2);
printf("\n");
}
rettype = RET_MPI;
}
| list VOID '\n'
{
rettype=0;
}
| list error '\n'
{
yyerrok;
}
| list polyexpr '\n'
{
retval.polyi=$2;
if (!(rettype == FUNC_FAIL)) {
PRINTPI($2);
printf("\n");
}
rettype=RET_POLY;
}
| list polyassign '\n'
{
retval.polyi = $2;
rettype=RET_POLY;
};
;
polyassign: POLYVAR '=' polyexpr /* covers case where old variable is
* reassigned */
{
DELETEPI($1->u.sympval);
$1->u.sympval=$3;
$$ = COPYPI($3);
};
| VAR '=' polyexpr
{
if ($1->type == VAR)
FREEMPI($1->u.symval);
$1->u.sympval = $3;
$1->type=POLYVAR;
$$=COPYPI($3);
}
polyexpr:
POLYVAR
{
if ($1->type == UNDEF)
execerror("is an undefined variable", $1->name);
else if( $1->u.sympval != (POLYI) NULL)
$$ = COPYPI($1->u.sympval);
else
$$ = (POLYI) NULL;
}
| POLYTERM /* handles the case of just x */
{
MPI *ONE;
ONE = ONEI();
$$ = NULL;
PINSERTPI(1, ONE, &$$, 1);
FREEMPI(ONE);
}
| expr POLYTERM /*handles the case of cx where c is a constant */
{
$$ = NULL;
PINSERTPI(1, $1, &$$, 1);
FREEMPI($1);
}
| expr POLYTERM "^" expr
{
$$ = NULL;
PINSERTPI(CONVERTI($4), $1, &$$,1);
FREEMPI($1);
FREEMPI($4);
}
| POLYTERM "^" expr
{
MPI *O;
O = ONEI();
$$ = NULL;
PINSERTPI(CONVERTI($3), O, &$$,1);
FREEMPI(O);
FREEMPI($3);
}
| polyassign
{
}
| polyexpr '+' polyexpr
{
$$ = ADDPI($1,$3);
DELETEPI($1);
DELETEPI($3);
}
/* I may take the following two out later as well */
| polyexpr '%' polyexpr
{
$$ = MODPI($1,$3);
DELETEPI($1);
DELETEPI($3);
}
| polyexpr '/' polyexpr
{
$$ = DIVPI($1, $3);
DELETEPI($1);
DELETEPI($3);
}
| '-' polyexpr %prec UNARYMINUS
{
POLYI Z;
Z = ZEROPI(); /* returns zero polynomial */
$$ = SUBPI(Z, $2);
DELETEPI(Z);
DELETEPI($2);
}
| polyexpr '-' polyexpr
{
$$ = SUBPI($1, $3);
DELETEPI($1);
DELETEPI($3);
}
| polyexpr '+' expr
{
POLYI O, P;
O = ONEPI();
P = SCALARPI($3, O);
$$ = ADDPI($1, P);
DELETEPI(O);
DELETEPI(P);
DELETEPI($1);
FREEMPI($3);
}
| expr '+' polyexpr
{
POLYI O, P;
O = ONEPI();
P = SCALARPI($1, O);
$$ = ADDPI($3, P);
DELETEPI(O);
DELETEPI(P);
DELETEPI($3);
FREEMPI($1);
}
| polyexpr '-' expr
{
POLYI O, P;
O = ONEPI();
P = SCALARPI($3, O);
$$ = SUBPI($1, P);
DELETEPI(O);
DELETEPI(P);
DELETEPI($1);
FREEMPI($3);
}
| expr '-' polyexpr
{
POLYI O, P;
O = ONEPI();
P = SCALARPI($1, O);
$$ = SUBPI(P, $3);
DELETEPI(O);
DELETEPI(P);
DELETEPI($3);
FREEMPI($1);
}
| expr '*' polyexpr
{
$$ = SCALARPI($1,$3);
FREEMPI($1);
DELETEPI($3);
}
| polyexpr '*' expr
{
$$ = SCALARPI($3, $1);
FREEMPI($3);
DELETEPI($1);
}
| polyexpr '*' polyexpr
{
$$ = MULTPI($1, $3);
DELETEPI($1);
DELETEPI($3);
}
| polyexpr '^' expr
{
$$ = POWERPI($1, CONVERTI($3));
DELETEPI($1);
FREEMPI($3);
}
| '(' polyexpr ')'
{
$$ = $2;
}
| BLTINP arglist
{
Stack varStack;
if ((varStack = checkArgs($1))) {
$$ = (*($1->u.ptrp))(varStack);
stackFree(&varStack);
} else {
rettype = FUNC_FAIL; /* return failure of function */
$$ = NULL;
}
}
/* Note on arrays. To save excessive reallocation an array is
* initially allocated 11 slots (including zero slot). However the
* array size will be set to the value of the first subscript. This
* must be remembered when freeing arrays */
arrayassign: ARRAY '[' expr ']' '=' expr
{
unsigned n = CONVERTI($3);
if ($1->type == UNDEF) {
$1->u.symarr = BUILDMPIA();
$1->type = ARRAY;
}
ADD_TO_MPIA($1->u.symarr, $6, n);
FREEMPI($3);
FREEMPI($6);
}
| ARRAY '[' ']' '=' '{' arraylist
{
if ($1->type != UNDEF)
FREEMPIA($1->u.symarr);
$1->u.symarr = $6;
$1->type=ARRAY;
}
arraylist: expr '}'
{
$$ = BUILDMPIA();
ADD_TO_MPIA($$, $1, 0);
FREEMPI($1);
}
| expr ',' arraylist
{
MPIA_INSERT($3, $1, 0);
FREEMPI($1);
$$ = $3;
};
varassign: VAR '=' expr
{
if($1->type!=UNDEF && $1->u.symval != NULL)
FREEMPI($1->u.symval);
$1->u.symval=$3;
if ( $1->u.symval != (MPI *) NULL)
$$ = COPYI($1->u.symval);
else
$$ = (MPI *) NULL;
$1->type = VAR;
};
expr: NUMBER
{
$$ = $1;
}
| VAR
{
if ($1->type == UNDEF)
execerror("is an undefined variable", $1->name);
else
$$ = COPYI($1->u.symval);
}
/* I may remove this. This allows one to evaluate a polynomial expression
* simply by placing a set of brackets after the expression and placing
* a value within it
* eg. 3x^4(1) = 3.
*/
| polyexpr '(' expr ')'
{
$$ = VALPI($1, $3);
FREEMPI($3);
DELETEPI($1);
}
| POLYVAR '(' expr ')'
{
$$ = VALPI($1->u.sympval, $3);
FREEMPI($3);
}
| ARRAY '[' expr ']'
{
int ind;
if ($1->type == UNDEF)
{
FREEMPI($3);
execerror("[] is an undefined array", $1->name);
}
ind = (int)CONVERTI($3);
if(ind >= $1->u.symarr->size)
{
FREEMPI($3);
execerror("array is too small", $1->name);
}
$$ = COPYI($1->u.symarr->A[ind]);
FREEMPI($3);
}
| varassign
{
}
| expr '+' expr
{
$$ = ADDI($1, $3);
FREEMPI($1);
FREEMPI($3);
}
| expr '-' expr
{
$$ = SUBI($1, $3);
FREEMPI($1);
FREEMPI($3);
}
| expr '*' expr
{
$$ = MULTI($1, $3);
FREEMPI($1);
FREEMPI($3);
}
| expr '/' expr
{
if(($3)->S <= 0)
{
FREEMPI($1);
FREEMPI($3);
execerror(" divisor <= 0", "");
}
$$ = INTI($1, $3);
FREEMPI($1);
FREEMPI($3);
}
| expr '%' expr
{
if(($3)->S <= 0)
{
FREEMPI($1);
FREEMPI($3);
execerror(" divisor <= 0", "");
}
$$ = MOD($1, $3);
FREEMPI($1);
FREEMPI($3);
}
| expr '^' expr
{
if (($3)->S < 0)
{
FREEMPI($1);
FREEMPI($3);
execerror("negative exponent", "");
}
if (($3)->D > 0)
{
FREEMPI($1);
FREEMPI($3);
execerror("exponent >= R0", "");
}
$$ = POWERI($1, (unsigned int)(CONVERTI($3)));
FREEMPI($1);
FREEMPI($3);
}
| '-' expr %prec UNARYMINUS
{
$$ = MINUSI($2);
FREEMPI($2);
}
| '(' expr ')'
{
$$ = $2;
}
| BLTIN arglist
{
Stack varStack;
if ((varStack = checkArgs($1))) {
$$ = (*($1->u.ptr))(varStack);
stackFree(&varStack);
} else {
$$ = NULL;
rettype = FUNC_FAIL;
}
};
VOID: BLTINV arglist
{
Stack varStack;
if ((varStack = checkArgs($1))) {
(*($1->u.ptrv))(varStack);
stackFree(&varStack);
} else {
rettype = FUNC_FAIL;
}
}
| ARRAY '[' ']'
{
if ($1->type != UNDEF){
PRINTIA($1->u.symarr);
} else {
execerror("undefined array", $1->name );
}
};
arglist: '(' ')'
{
}
| '(' arguments
{
};
arguments: expr ')'
{
stackPush(argStack, createArg($1, NUM, 0));
}
| polyexpr ')'
{
stackPush(argStack, createArg($1, POLY, 0));
}
| ARRAY '[' ']' ')'
{
if ($1->type != UNDEF) {
stackPush(argStack, createArg($1, ARR, 0));
} else {
execerror("[] is an undefined array", $1->name);
rettype = FUNC_FAIL;
}
}
| '&' ARRAY '[' ']' ')'
{
/* S.Seefried. Normally one would free an old array if it
* existed. I have deferred this until I am sure all arguments
* on the command line are valid for the function in question.
* See checkArgs. It is here that I free. */
if ($2->type != UNDEF)
stackPush(argStack, createArg($2, ARRADR, 1));
else
stackPush(argStack, createArg($2, ARRADR, 0));
$2->type=ARRAY;
}
| '&' VAR ')'
{
if ($2->type != UNDEF)
stackPush(argStack, createArg($2, VARADR, 1));
else
stackPush(argStack, createArg($2, VARADR, 0));
$2->type=VAR;
}
| '&' VAR ',' arguments
{
if ($2->type != UNDEF)
stackPush(argStack, createArg($2, VARADR, 1));
else
stackPush(argStack, createArg($2, VARADR, 0));
$2->type=VAR;
}
| expr ',' arguments
{
stackPush(argStack, createArg($1, NUM, 0));
}
| polyexpr ',' arguments
{
stackPush(argStack, createArg($1, POLY, 0));
}
| ARRAY '[' ']' ',' arguments
{
if ($1->type != UNDEF) {
stackPush(argStack, createArg($1, ARR, 0));
} else {
rettype = FUNC_FAIL;
}
}
| '&' ARRAY '[' ']' ',' arguments
{
/* S.Seefried. Normally one would free an old array if it
* existed. I have deferred this until I am sure all arguments
* on the command line are valid for the function in question.
* See checkArgs. It is here that I free. */
if ($2->type != UNDEF)
stackPush(argStack, createArg($2, ARRADR, 1));
else
stackPush(argStack, createArg($2, ARRADR, 0));
$2->type=ARRAY;
};
%%
static char *p;
static Stack argStack =NULL;
void Parse(s)
char *s;
{
p = s;
argStack = stackNew();
yyparse();
switch (rettype) {
case RET_MPI:
FREEMPI(retval.mpi);
break;
case RET_POLY:
DELETEPI(retval.polyi);
break;
}
rettype=RET_NULL;
stackFree(&argStack);
}
/* Checks if the arguments contained in the source stack match the arguments
* of the function whose information is stored in the supplied symbol.
* If the arguments match then the function returns a variable stack that
* can be sent straight to a wrapper function (see note at top of file)
* If the arguments do not match then an error message is printed, and the
* function returns NULL.
* Regardless of whether the match is successful or not, all the arguments on
* the globar variable argStack are popped, leaving an empty stack.
*/
Stack checkArgs(Symbol *s)
{
Stack varStack=stackNew();
Stack tmpStack=stackNew();
int *argTypes = s->argTypes;
int nArgs=argTypes[0];
int quitFlag=0;
int i;
Argument Arg=NULL;
for (i=1; ; i++) {
if (i > nArgs && stackEmpty(argStack))
break;
if (!stackEmpty(argStack))
Arg = stackPop(argStack);
else
quitFlag = 1; /* This means there are too few arguments sent to this
* function */
/* oh no! we quit if this is true */
if (quitFlag == 1 || Arg->type != argTypes[i]) { /* short circuit eval! */
int j;
/* pop all entries off argument stack */
if (!quitFlag) { /* only free these if the reason we are exiting is
* that there are too few Arguments */
freeArg(Arg);
while (!stackEmpty(argStack)) {
Arg = stackPop(argStack);
freeArg(Arg);
}
}
/* pop all entries off stack to be returned
* It is helpful that i contains a value one greater than the number
* of elements on the stack to be returned. */
while (!stackEmpty(tmpStack)) {
Arg = stackPop(tmpStack);
switch(Arg->type) {
case NUM:
FREEMPI(Arg->u.num);
break;
case POLY:
DELETEPI(Arg->u.poly);
break;
/* we do not free arrays, array address or variable addresses */
}
}
printf("This function has the format: %s(", s->name);
if (nArgs > 0) {
for (j=1;j<=nArgs;j++) {
switch(argTypes[j]) {
case NUM:
printf("number");
break;
case VARADR:
printf("&var");
break;
case ARR:
printf("array[]");
break;
case ARRADR:
printf("&array[]");
break;
case POLY:
printf("poly");
break;
}
if (j!=nArgs)
printf(", ");
else
printf(")\n");
}
} else
printf(")\n");
stackFree(&tmpStack);
return NULL;
}
stackPush(tmpStack, Arg); /* put it back in the stack. in reverse order */
}
while (!stackEmpty(tmpStack)) {
Arg = stackPop(tmpStack);
switch(Arg->type) {
case NUM:
stackPush(varStack, Arg->u.num);
break;
case VARADR:
if ( Arg->defined == 1) /* if the variable has previously been assigned.
*/
FREEMPI(*(Arg->u.varAdr));
stackPush(varStack, Arg->u.varAdr);
break;
case ARR:
stackPush(varStack, Arg->u.array);
break;
case ARRADR:
if ( Arg->defined == 1) /* if the variable has previously been assigned.
*/
FREEMPIA(*(Arg->u.arrayAdr));
stackPush(varStack, Arg->u.arrayAdr);
break;
case POLY:
stackPush(varStack, Arg->u.poly);
break;
}
}
stackFree(&tmpStack);
return varStack;
}
int yylex()
{
MPI *Temp;
char c;
int typ;
while ((c = *p++) == ' ' || c == '\t')
;
if (c == '\0')
return 0;
if (isdigit((int)c))
{
yylval.val = CHANGE((USL)(c - '0'));
while (isdigit((int)*p))
{
Temp = yylval.val;
yylval.val = MULT_I(yylval.val, 10L);
FREEMPI(Temp);
Temp = yylval.val;
yylval.val = ADD0_I(yylval.val, (USL)(*p++ - '0'));
FREEMPI(Temp);
}
return NUMBER;
}
p--;
if ( isalpha((int)c))
{
Symbol *s;
char sbuf[100], *tmp = sbuf;
do {
*tmp++ = *p;
p++;
c=(*p);
} while (c && isalnum((int)c));
*tmp = '\0';
if(c=='[')
typ=ARRAY;
else if ( (c=='^' && *(tmp-1) == POLYID && (tmp-1) == sbuf ) ||
(*(p-1)==POLYID && strlen(sbuf) == 1 )) {
return POLYTERM; /* don't want to install this */
} else
typ=VAR;
s = lookup(sbuf,typ);
if (s == NULL)
s = lookup(sbuf, BLTIN);
if (s == NULL)
s = lookup(sbuf, BLTINV);
if (s == NULL)
s = lookup(sbuf, BLTINP);
if (s == NULL)
s = lookup(sbuf,POLYVAR);
if (s == NULL)
s = install(sbuf, UNDEF);
yylval.sym = s;
if (s->type == UNDEF)
return(typ);
else
return (s->type);
}
p++;
return (int)c; /* returns +, -, ^, *, / etc */
}
void yyerror(s)
char *s;
{
warning(s,"");
}