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,""); 
}