/* C declarations */
/* vi: set et ts=4: */

%{

#include <stdio.h>
#include <math.h>

int base = 10;

/* Prototypes */
static void yyerror(const char *);
static int fac(int x);

/* import from spascal.l */
extern int lineno;
extern int yylex(void);

%}


/* Start symbol */
%start line

/* Tokens */
%token DIGIT
%token PI
%token OPEN_PAREN CLOSE_PAREN
%token '|'

/* Tokens with precedence assigned */
/* The sooner the operator is defined, the lower its precedence */
%left '-' '+'
%left '*' '/' '%'
%left UMINUS
%left '!'
%right EXPONENT



/* Rules */
%%

line:
         |
         
         line stmt '\n'
         
         |
         
         line error '\n'
         {
           yyerrok;
         }
         ;


stmt:   
        expr
        {
          printf("%d\n",$1);
        }
        ;


expr:   
         OPEN_PAREN expr CLOSE_PAREN
         {
            $$ = $2;
         }
	 
	 |
	 
	 '|' expr '|'
	 {
	    $$ = (int)fabs((double)$2);
	 }
	 
         |

         expr '*' expr
         {
           $$ = $1 * $3;
         }

         |
         
         expr '/' expr
         {
           $$ = $1 / $3;
         }

         |
         
         expr '%' expr
         {
           $$ = $1 % $3;
         }

         |
         
         expr '-' expr
         {
           $$ = $1 - $3;
         }
         
         |
         
         expr '+' expr
         {
           $$ = $1 + $3;
         }
         
         |
         
	 expr '!'
	 {
	    if ($1 < 0) {
	       fprintf(stderr, "Negative values for faculty are undefined.\n");
	       YYERROR;
	    }
	    $$ = fac($1);
	 }
         
	 |
	 
	 expr EXPONENT expr
	 {
	    $$ = (int)pow((double)$1, (double)$3);
	 }
	 
         |
	 
         '-' expr %prec UMINUS
         {
           $$ = -$2;
         }
         
         |
         
         number
         ;


number:  
         PI
         {
           $$ = 3;
         }
         
         |
         
         DIGIT
         {
           $$ = $1;
         }
         
         |
         
         number DIGIT
         {
           $$ = base * $1 + $2;
         }
         ;
%%
/* End of rules, more C code will follow now */


int main()
{
  return yyparse();
}

static void yyerror(const char *s)
{
  fprintf(stderr, "%s\n",s);
}

int yywrap()
{
  return(1);
}

int fac(int x)
{
  return (x > 1) ? x*fac(x-1) : 1;
}