#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "symtab.h"
#include "y.tab.h"

struct init
{
   char *fname;
   value (*fcnt)(const value &);
};
struct init2
{
   char *fname;
   value (*fcnt)(const value &,const value &);
};
struct init3
{
   char *fname;
   value (*fcnt)(void);
};

struct init arith_fncts[] =
{ 
#include "value.fn"
  0,0
};

struct init2 arith_fncts2[] =
{ 
#include "value.fn2"
  0,0
};

struct init3 arith_proc[] =
{
#include "value.fn0"
  0,0
};

symrec *sym_table=(symrec *)0;

void init_table(void)
{
   if(sym_table!=(symrec *)0)
      return;
   symrec *ptr;
   int i;
   for(i=0;arith_fncts[i].fname!=0;i++)
   {
      ptr=putsym(arith_fncts[i].fname,PARSERfunction);
      ptr->ivalue.fnctptr=arith_fncts[i].fcnt;
   }
   for(i=0;arith_fncts2[i].fname!=0;i++)
   {
      ptr=putsym(arith_fncts2[i].fname,PARSERfunction2);
      ptr->ivalue.fnctptr2=arith_fncts2[i].fcnt;
   }
   for(i=0;arith_proc[i].fname!=0;i++)
   {
      ptr=putsym(arith_proc[i].fname,PARSERprocedure);
      ptr->ivalue.procptr=arith_proc[i].fcnt;
   }
}

symrec * putsym(char *sym_name,int sym_type)
{
   symrec *ptr;
#ifdef DEBUG
   printf("putsym(%s,%d);\n",sym_name,sym_type);
#endif
   ptr=new symrec();// (symrec *)malloc(sizeof(symrec));
   ptr->name=(char *)malloc(strlen(sym_name)+1);
   strcpy(ptr->name,sym_name);
   ptr->type=sym_type;
   ptr->var=value(0);
   ptr->next=(struct symrec*)sym_table;
   sym_table=ptr;
   return ptr;
}

symrec * getsym(char *sym_name)
{
   symrec *ptr;
#ifdef DEBUG
   printf("getsym(%s);\n",sym_name);
#endif
   if(sym_table==(symrec *)0)
      init_table();
   for(ptr=sym_table;ptr!=(symrec *)0;ptr=(symrec*)ptr->next)
      if(strcmp(ptr->name,sym_name)==0)
         return ptr;
   return 0;
}

symrec * getsym(char *sym_name,int demanded_type)
{
   symrec *ptr;
#ifdef DEBUG
   printf("getsym(%s);\n",sym_name);
#endif
   if(sym_table==(symrec *)0)
      init_table();
   for(ptr=sym_table;ptr!=(symrec *)0;ptr=(symrec*)ptr->next)
      if(strcmp(ptr->name,sym_name)==0 && ptr->type==demanded_type)
         return ptr;
   return 0;
}

void * set_string_input(char *); 
int yyparse (void);  
void reset_input(void *);
extern value result;

value evaluate(const symrec *a)
{
   // preferred: PARSERprocedure
   symrec *b;
   
   if(a->type!=PARSERprocedure && (b=getsym(a->name,PARSERprocedure))!=0)
      a=b;
      
   switch(a->type)
   {
      case PARSERprocedure:
         return (*(a->ivalue.procptr))();
      case PARSERfunction:
         return (*(a->ivalue.fnctptr))(value());
      case PARSERfunction2:
         return (*(a->ivalue.fnctptr2))(value(),value());
      case PARSERuserfunction:
         {   
            int  i;
		      char *var;
		      symrec *varrec;
		      value old;
		      char *body=a->ivalue.body;
            void *buffer;
		      
		      for(i=1;i<strlen(body) && body[i]!=')' && body[i]!=',';i++);
		      
		      var=(char*)malloc(i);
		      
		      for(i=1;i<strlen(body) && body[i]!=')' && body[i]!=',';i++)
		         var[i-1]=body[i];
		      
		      var[i-1]=0;
#ifdef DEBUG		      
                      printf("Variable: %s Body: %s\n",var,body+i+2);
#endif
		      varrec=getsym(var);
		      if(varrec==0)
		         varrec=putsym(var,PARSERvariable);
		      
		      old=varrec->var;

		      varrec->var=value();

		      for(;i<strlen(body) && body[i]!=')';i++);
		      
		      for(;i<strlen(body) && (body[i]==' ' || body[i]=='\t' || body[i]=='=' || body[i]==')');i++);

            buffer=set_string_input(body+i);
		      
            yyparse();

            reset_input(buffer);

            free(var);

            varrec->var=old;
            
            return result;
		   }
      default:
         return value((symrec *)a);
   }
}

value evaluate(const symrec *a,const value &v)
{
   // preferred: PARSERuserfunction then PARSERfunction
   symrec *b;
   
   if(a->type!=PARSERuserfunction && (b=getsym(a->name,PARSERuserfunction))!=0)
      a=b;
   else if(a->type!=PARSERfunction && (b=getsym(a->name,PARSERfunction))!=0)
      a=b;   

   switch(a->type)
   {
      case PARSERprocedure:
         return (*(a->ivalue.procptr))();
      case PARSERfunction:
         return (*(a->ivalue.fnctptr))(v);
      case PARSERfunction2:
         return (*(a->ivalue.fnctptr2))(v,value());
      case PARSERuserfunction:
         {   
            int  i;
		      char *var;
		      symrec *varrec;
		      value old;
		      char *body=a->ivalue.body;
            void *buffer;
		      
		      for(i=1;i<strlen(body) && body[i]!=')' && body[i]!=',';i++);
		      
		      var=(char*)malloc(i);
		      
		      for(i=1;i<strlen(body) && body[i]!=')' && body[i]!=',';i++)
		         var[i-1]=body[i];
		      
		      var[i-1]=0;
#ifdef DEBUG		      
                      printf("Variable: %s Body: %s\n",var,body+i+2);
#endif
		      varrec=getsym(var);
		      if(varrec==0)
		         varrec=putsym(var,PARSERvariable);
		      
		      old=varrec->var;

		      varrec->var=v;

		      for(;i<strlen(body) && body[i]!=')';i++);

		      for(;i<strlen(body) && (body[i]==' ' || body[i]=='\t' || body[i]=='=' || body[i]==')');i++);

            buffer=set_string_input(body+i);
		      
            yyparse();

            reset_input(buffer);

            free(var);

            varrec->var=old;
            
            return result;
		   }
      default:
         return value();
   }
}

value evaluate(const symrec *a,const value &v1,const value &v2)
{
   // preferred: PARSERfunction2 
   symrec *b;
   
   if(a->type!=PARSERfunction2 && (b=getsym(a->name,PARSERfunction2))!=0)
      a=b;

   switch(a->type)
   {
      case PARSERprocedure:
         return (*(a->ivalue.procptr))();
      case PARSERfunction:
         return (*(a->ivalue.fnctptr))(v1);
      case PARSERfunction2:
         return (*(a->ivalue.fnctptr2))(v1,v2);
      case PARSERuserfunction:
         {   
            int  i;
		      char *var;
		      symrec *varrec;
		      value old;
		      char *body=a->ivalue.body;
            void *buffer;
		      
		      var=(char*)malloc(i);
		      
		      for(i=1;i<strlen(body) && body[i]!=')' && body[i]!=',';i++)
		         var[i-1]=body[i];
		      
		      var[i-1]=0;
#ifdef DEBUG		      
                      printf("Variable: %s Body: %s\n",var,body+i+2);
#endif
		      varrec=getsym(var);
		      if(varrec==0)
		         varrec=putsym(var,PARSERvariable);
		      
		      old=varrec->var;

		      varrec->var=v1;

		      for(;i<strlen(body) && body[i]!=')';i++);
		      
		      for(;i<strlen(body) && (body[i]==' ' || body[i]=='\t' || body[i]=='=' || body[i]==')');i++);

            buffer=set_string_input(body+i);
		      
            yyparse();

            reset_input(buffer);

            free(var);

            varrec->var=old;
            return result;
		   }
      default:
         return value();
   }

}

value evaluate_n(const symrec *a,const valuematrix &v)
{
   // preferred: PARSERfunction2 
   symrec *b;
   
   if(a->type!=PARSERfunction2 && (b=getsym(a->name,PARSERfunction2))!=0)
      a=b;

   switch(a->type)
   {
      case PARSERprocedure:
         return (*(a->ivalue.procptr))();
      case PARSERfunction:
//         return (*(a->ivalue.fnctptr))(cell(v,1));
         return (*(a->ivalue.fnctptr))(v);
      case PARSERfunction2:
         return (*(a->ivalue.fnctptr2))(cell(v,1),cell(v,2));
      case PARSERuserfunction:
         {   
            int  i,k;
		      char *var;
		      symrec *varrec;
		      char *body=a->ivalue.body;
            void *buffer;
            
            for(i=0,k=1;i<strlen(body) && body[i]!=')';i++)
               if(body[i]==',')
                  k++;

            valuematrix old(k,1,0,0);
            
            int ii=0;
		      k=0;
		      
		      do {
		         ii++;
		         for(i=ii;i<strlen(body) && body[i]!=')' && body[i]!=',';i++);
		      
		         var=(char*)malloc(i-ii+1);
		      
		         for(i=ii;i<strlen(body) && body[i]!=')' && body[i]!=',';i++)
		            var[i-ii]=body[i];
		      
		         var[i-ii]=0;
		         ii=i;
#ifdef DEBUG		      
                      printf("Variable: %s\n",var);
#endif
   		      varrec=getsym(var);
	   	      if(varrec==0)
		            varrec=putsym(var,PARSERvariable);
		      
		         old(k,0)=varrec->var;
		         
		         if(k<size(v))   
		            varrec->var=cell(v,k+1);
		         
		         k++;   
		         free(var);
            } while(body[ii]==',');


		      for(i=ii;i<strlen(body) && (body[i]==' ' || body[i]=='\t' || body[i]=='=' || body[i]==')');i++);

#ifdef DEBUG		      
                      printf("Body: %s\n",body+i);
#endif

            buffer=set_string_input(body+i);
		      
            yyparse();

            reset_input(buffer);
            
            k=ii=0;

		      do {
		         ii++;
		         for(i=ii;i<strlen(body) && body[i]!=')' && body[i]!=',';i++);
		      
		         var=(char*)malloc(i-ii+1);
		      
		         for(i=ii;i<strlen(body) && body[i]!=')' && body[i]!=',';i++)
		            var[i-ii]=body[i];
		      
		         var[i-ii]=0;
		         ii=i;
#ifdef DEBUG		      
                      printf("Variable: %s\n",var);
#endif
   		      varrec=getsym(var);
	   	      if(varrec==0)
		            varrec=putsym(var,PARSERvariable);
		      
		         varrec->var=old(k,0);
		         k++;
		         free(var);
            } while(body[ii]==',');


            return result;
		   }
      default:
         return value();
   }

}

int arguments(const symrec *a) // returns max number of arguments
{
   // preferred: PARSERfunction2 
   symrec *b;
   
   if(a->type!=PARSERfunction2 && (b=getsym(a->name,PARSERfunction2))!=0)
      a=b;

   switch(a->type)
   {
      case PARSERprocedure:
         return 0;
      case PARSERfunction:
         return 1;
      case PARSERfunction2:
         return 2;
      case PARSERuserfunction:
         {   
            int  i,k;
		      char *body=a->ivalue.body;
            
            for(i=0,k=1;i<strlen(body) && body[i]!=')';i++)
               if(body[i]==',')
                  k++;
            return k;
		   }
      default:
         return 0;
   }
}


syntax highlighted by Code2HTML, v. 0.9.1