// Rascal, the Advanced Scientific CALculator
// Copyright (C) 2001, 2002, Sebastian Ritterbusch (Rascal@Ritterbusch.de)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//

#include <iostream.h>
#include <stdlib.h>
#include <string.h>
#include <fstream.h>

#define MAX_TYPES    256
#define MAX_HELP     1024
#define MAX_LENGTH   1024

#define MAX_FUNCTION 256
#define MAX_OVERLOAD 256

int   typean=0;
char *atypename[MAX_TYPES];
char *ctypename[MAX_TYPES];
int   constructor[MAX_TYPES];

int   functionan=0;
char *function[MAX_FUNCTION];
int   overloadan[MAX_FUNCTION];
int   nr_ary[MAX_FUNCTION]; // -1 means implicit cast
char *overload[MAX_FUNCTION][MAX_OVERLOAD][4];
int   overload_done[MAX_FUNCTION][MAX_OVERLOAD];
int   implicit_order[MAX_FUNCTION][MAX_OVERLOAD];
int   implicit_an=0;

int   CPPan=0;
char *CPPs[MAX_TYPES];
int   HPPan=0;
char *HPPs[MAX_TYPES];
int   TEXan=0;
char *TEXs[MAX_TYPES];
int   MAKan=0;
char *MAKs[MAX_TYPES];

int   HELPan=0;
char *HELPname[MAX_HELP];
char  *HELPfile[MAX_HELP];

int   MODULEan=0;
char *MODULEname[MAX_TYPES];


char *configuration="custom";

int level=0;

int   datatype_count=0;
int   function_count=0;
int   function2_count=0;
int   cast_count=0;

void show_statistics(void)
{
//   cerr << configuration << ": " << typean << "+2 data types " << cast_count << " implicit casts "<< functionan << " functions " << function_count << "+" << function2_count << " overloads\r";
}

void show_final_statistics(void)
{
   cerr << configuration << ": " << typean << "+2 data types " << cast_count << " implicit casts "<< functionan << " functions " << function_count << "+" << function2_count << " overloads" << endl;
}

void findcast(int fromtype,int & i1,int & i2, int fintype, double & length)
{
   level++;
#ifdef DEBUG
   cout << length << endl;
#endif
   
   if(length<0)
      return;
   
   if(fromtype==fintype || fintype==typean)
   {
      length=0;
      i1=-2;
      i2=-2;
      level--;
#ifdef DEBUG
            cout << "*" << atypename[fromtype] << " to " << atypename[fintype] << " costs " << length << endl;
#endif
      return;
   }
   int i,j;
   int found=0;
   for(i=0;i<functionan && length>0;i++)
      if(nr_ary[i]==-1)
         for(j=0;j<overloadan[i];j++)
            if(strcmp(atypename[fromtype],overload[i][j][1])==0 
               || (overload[i][j][1][0]=='*' && length>1))
            {
               int k;
               double currentcost=((overload[i][j][1][0]=='*'?4.0:1)+double(implicit_an-implicit_order[i][j]-1)/implicit_an);

               if(currentcost<=length)
               {

                  for(k=0;k<typean && strcmp(overload[i][j][0],atypename[k]);k++);
                  if(k==fintype)
                  {
                     i1=i;
                     i2=j;
                     length=currentcost;
                     found=1;
                  } else
                  {
//                  if(length>2 || (overload[i][j][1][0]!='*' && length>1))
                     {
                        double newlength=length-currentcost;
                        int j1=-1,j2=-1;
                     
                        if(level<typean+4)
                           findcast(k,j1,j2,fintype,newlength);
//                      else
//                         cerr << "Warning! Recursion in implicit casts!" << endl;
                        newlength+=currentcost;
                        
                        if(j1!=-1 && j2!=-1 && newlength<=length)
                        {
                           i1=i;
                           i2=j;
                           found=1;
                           length=newlength;
                        }
                     }
                  }
               }
            }
   level--;
   
#ifdef DEBUG
   if(found)
      cout << atypename[fromtype] << " to " << atypename[fintype] << " costs " << length << endl;
#endif
}

void doImplicitCastExtension(void)
{
   int i;
   for(i=0;i<functionan;i++)
      if(nr_ary[i]==1)
      {
         int k;
         int newoverloadan=overloadan[i];
         for(k=0;k<typean;k++)
         {
            int l;
            for(l=0;l<overloadan[i] && strcmp(atypename[k],overload[i][l][1])!=0;l++);
            if(l==overloadan[i])
            {
               int fromtype=k;
               int castindex1=-1;
               int castindex2=-1;
               double length=5; // maxlength
#ifdef DEBUG               
               cout << function[i] << "(" << atypename[k] << ")" << endl;  
#endif               
               for(l=0;l<overloadan[i];l++)
               {
                  int m;
                  for(m=0;m<typean && strcmp(overload[i][l][1],atypename[m]);m++);
                  double ol=length;
                  if(m<typean) // no cast to defaults
                     findcast(fromtype,castindex1,castindex2,m,length);
#ifdef DEBUG
                  if(ol!=length)
                     cout << atypename[m] << " " << length << endl;                  
#endif
               }
               if(castindex1!=-1 && castindex2!=-1)
               {
                  int m;
                  cout << function[i] << "(" << atypename[k] << ") is "
                       << function[i] << "(" << function[castindex1] << ")" << endl;
                  
                  overload[i][newoverloadan][0]="VALUE"; // evil =:>
                  overload[i][newoverloadan][1]=atypename[fromtype]; // evil =:>
                  
                  overload[i][newoverloadan][2]=new char[2+strlen(function[i])+2+8+strlen(overload[castindex1][castindex2][0])+1+7];
                  strcpy(overload[i][newoverloadan][2],function[i]);
                  strcat(overload[i][newoverloadan][2],"(value(va,value::");
                  strcat(overload[i][newoverloadan][2],overload[castindex1][castindex2][0]);
                  strcat(overload[i][newoverloadan][2],"))");
                  newoverloadan++;
                  function2_count++;show_statistics();

               }
            }
         }
         overloadan[i]=newoverloadan;
      } else
      if(nr_ary[i]==2)
      {
         int k1,k2;
         int newoverloadan=overloadan[i];
         for(k1=0;k1<typean;k1++)
         for(k2=0;k2<typean;k2++)
         {
            int l;
            for(l=0;l<overloadan[i] && 
                  (   (strcmp(atypename[k1],overload[i][l][1])!=0
                       && overload[i][l][1][0]!='*') 
                   || (strcmp(atypename[k2],overload[i][l][2])!=0
                       && (overload[i][l][2][0]!='*' || overload[i][l][1][0]=='*')));l++);
            if(l==overloadan[i])
            {
               int fromtype1=k1;
               int fromtype2=k2;
               int castindex11=-1,castindex12=-1;
               int castindex21=-1,castindex22=-1;
               double length=5; // maxlength
               
               for(l=0;l<overloadan[i];l++)
               {
                  int m1,m2;
                  for(m1=0;m1<typean && strcmp(overload[i][l][1],atypename[m1]);m1++);
                  for(m2=0;m2<typean && strcmp(overload[i][l][2],atypename[m2]);m2++);
                  int c11=-1,c12=-1,c21=-1,c22=-1;
                  double l1=length,l2;
                  if(m1!=typean || m2!=typean) // no cast to defaults
                     findcast(fromtype1,c11,c12,m1,l1);
                  l2=length-l1;
                  if(c11!=-1)
                     findcast(fromtype2,c21,c22,m2,l2);
                  if(c21!=-1 && !(c11==-2 && c21==-2))
                  {
                     length=l1+l2;
                     castindex11=c11;
                     castindex12=c12;
                     castindex21=c21;
                     castindex22=c22;
                  }
               }
               if(castindex11!=-1)
               {
                  int m;
                  cout << function[i] << "(" << atypename[k1] 
                       << "," << atypename[k2] << ") is "
                       << function[i] << "(";
                  if(castindex11==-2)
                     cout << atypename[k1];
                  else 
                     cout << function[castindex11];
                  cout << ",";
                  if(castindex21==-2)
                     cout << atypename[k2];
                  else 
                     cout << function[castindex21];
                  cout << ")" << endl;
                  
                  overload[i][newoverloadan][0]="VALUE"; // evil =:>
                  overload[i][newoverloadan][1]=atypename[fromtype1]; // evil =:>
                  overload[i][newoverloadan][2]=atypename[fromtype2]; // evil =:>
                  
                  if(castindex11==-2)
                     overload[i][newoverloadan][3]=new char[
                       +2
                       +strlen(function[i])
                       +strlen(overload[castindex21][castindex22][0])
                       +1   +10+11+2+14];                  
                  else if(castindex21==-2)
                     overload[i][newoverloadan][3]=new char[
                        strlen(overload[castindex11][castindex12][0])
                       +strlen(function[i])
                       +2
                       +1   +10+11+2+14];
                  else
                     overload[i][newoverloadan][3]=new char[
                        strlen(overload[castindex11][castindex12][0])
                       +strlen(function[i])
                       +strlen(overload[castindex21][castindex22][0])
                       +1   +10+11+2+14];
                  strcpy(overload[i][newoverloadan][3],function[i]);
                  strcat(overload[i][newoverloadan][3],"(");
                  if(castindex11==-2)
                     strcat(overload[i][newoverloadan][3],"va");
                  else
                  {
                     strcat(overload[i][newoverloadan][3],"value(va,value::"); // 10
                     strcat(overload[i][newoverloadan][3],overload[castindex11][castindex12][0]);
                     strcat(overload[i][newoverloadan][3],")");
                  }
                  strcat(overload[i][newoverloadan][3],",");
                  if(castindex21==-2)
                     strcat(overload[i][newoverloadan][3],"vb");
                  else
                  {
                     strcat(overload[i][newoverloadan][3],"value(vb,value::");// 11
                     strcat(overload[i][newoverloadan][3],overload[castindex21][castindex22][0]);
                     strcat(overload[i][newoverloadan][3],")");
                  }
                  strcat(overload[i][newoverloadan][3],")");      // 2
                  
                  newoverloadan++;
                  function2_count++;show_statistics();
               }
            }
         }   
         overloadan[i]=newoverloadan;
      }
}

int existoverload(int i,char *p1,char *p2,int jfrom=0)
{
   int j;
   for(j=jfrom;j<overloadan[i];j++)
      if(strcmp(overload[i][j][1],p1)==0 
      && strcmp(overload[i][j][2],p2)==0)
         return 1;
   return 0;
}

void  readFromStream(istream & fin)
{
   char  command[MAX_LENGTH];
   
   while(fin >> command)
   {
      if(strlen(command))
      {
         if(strcmp(command,"INCLUDE")==0)
         {
            fin >> command;
            ifstream fin2(command);
            readFromStream(fin2);
         } else
         if(strcmp(command,"CPP")==0)
         {
            fin >> command;
            CPPs[CPPan]=new char[strlen(command)+1];
            strcpy(CPPs[CPPan++],command);
         } else
         if(strcmp(command,"HPP")==0)
         {
            fin >> command;
            HPPs[HPPan]=new char[strlen(command)+1];
            strcpy(HPPs[HPPan++],command);
         } else
         if(strcmp(command,"TEX")==0)
         {
            fin >> command;
            TEXs[TEXan]=new char[strlen(command)+1];
            strcpy(TEXs[TEXan++],command);
         } else 
         if(strcmp(command,"MAK")==0)
         {
            fin >> command;
            MAKs[MAKan]=new char[strlen(command)+1];
            strcpy(MAKs[MAKan++],command);
         } else
         if(strcmp(command,"CONFIGURATION")==0)
         {
            fin >> command;
            configuration=new char[strlen(command)+1];
            strcpy(configuration,command);
         } else
         if(strcmp(command,"HELP")==0)
         {
            fin >> command;
            HELPname[HELPan]=new char[strlen(command)+1];
            strcpy(HELPname[HELPan],command);
            fin >> command;
            HELPfile[HELPan]=new char[strlen(command)+1];
            strcpy(HELPfile[HELPan++],command);
         } else
         if(strcmp(command,"MODULE")==0)
         {
            fin >> command;
            HELPname[HELPan]=new char[strlen(command)+1];
            strcpy(HELPname[HELPan],command);
            MODULEname[MODULEan]=new char[strlen(command)+1];
            strcpy(MODULEname[MODULEan++],command);
            fin >> command;
            HELPfile[HELPan]=new char[strlen(command)+1];
            strcpy(HELPfile[HELPan++],command);
         } else
         if(strcmp(command,"TYPES")==0)
         {
            while((fin >> command) && strcmp(command,"END"))
            {
               atypename[typean]=new char[strlen(command)+1];
               strcpy(atypename[typean],command);
               fin >> command;
               ctypename[typean]=new char[strlen(command)+1];
               strcpy(ctypename[typean],command);
               constructor[typean]=0;
               typean++;
               datatype_count++;show_statistics();
            }            
         } else
         if(strcmp(command,"BINARYFUNCTIONS")==0)
         {
            while((fin >> command) && strcmp(command,"END"))
            {
               int i;
               for(i=0;i<functionan && (strcmp(command,function[i])!=0 || nr_ary[i]!=2);i++);
               if(i==functionan)
               {
                  function[i]=new char[strlen(command)+1];
                  strcpy(function[i],command);
                  overloadan[i]=0;
                  nr_ary[i]=2;
                  functionan++;
               }              
               int j;
               for(j=0;j<4;j++)
               {
                  fin >> command;
                  overload[i][overloadan[i]][j]=new char[strlen(command)+1];
                  strcpy(overload[i][overloadan[i]][j],command);
                  if((j==1 || j==2) && command[0]!='*' && strcmp(command,"VALUE")!=0)
                  {
                     int k;
                     for(k=0;k<typean && strcmp(command,atypename[k]);k++);
                  
                     if(k==typean)
                     {
                        cerr << function[i] << "\t";
                        for(k=0;k<j;k++)
                           cerr << overload[i][overloadan[i]][k] << "\t";
                        cerr << endl << "Unknown type " << command << endl;
                        exit(1);
                     }
                  }
               }
               overload_done[i][overloadan[i]]=0;
               overloadan[i]++;
               function_count++;show_statistics();
            }
         } else
         if(strcmp(command,"UNARYFUNCTIONS")==0)
         {
            while((fin >> command) && strcmp(command,"END"))
            {
               int i;
               for(i=0;i<functionan && (strcmp(command,function[i])!=0 || nr_ary[i]!=1);i++);
               if(i==functionan)
               {
                  function[i]=new char[strlen(command)+1];
                  strcpy(function[i],command);
                  overloadan[i]=0;
                  nr_ary[i]=1;
                  functionan++;
               }              
               int j;
               for(j=0;j<3;j++)
               {
                  fin >> command;
                  overload[i][overloadan[i]][j]=new char[strlen(command)+1];
                  strcpy(overload[i][overloadan[i]][j],command);
                  if(j==1 && command[0]!='*' && strcmp(command,"VALUE")!=0)
                  {
                     int k;
                     for(k=0;k<typean && strcmp(command,atypename[k]);k++);
                  
                     if(k==typean)
                     {
                        cerr << function[i] << "\t";
                        for(k=0;k<j;k++)
                           cerr << overload[i][overloadan[i]][k] << "\t";

                        cerr << endl << "Unknown type " << command << endl;
                        exit(1);
                     }
                  }
               }
               overload_done[i][overloadan[i]]=0;
               overloadan[i]++;
               function_count++;show_statistics();
            }
         } else
         if(strcmp(command,"PROCEDURES")==0)
         {
            while((fin >> command) && strcmp(command,"END"))
            {
               int i;
               for(i=0;i<functionan && (strcmp(command,function[i])!=0 || nr_ary[i]!=0);i++);
               if(i==functionan)
               {
                  function[i]=new char[strlen(command)+1];
                  strcpy(function[i],command);
                  overloadan[i]=0;
                  nr_ary[i]=0;
                  functionan++;
               }              
               int j;
               for(j=0;j<2;j++)
               {
                  fin >> command;
                  overload[i][overloadan[i]][j]=new char[strlen(command)+1];
                  strcpy(overload[i][overloadan[i]][j],command);
                  if(j==0 && strcmp(command,"VALUE")!=0)
                  {
                     int k;
                     for(k=0;k<typean && strcmp(command,atypename[k]);k++);
                  
                     if(k==typean)
                     {
                        cerr << function[i] << "\t";
                        for(k=0;k<j;k++)
                           cerr << overload[i][overloadan[i]][k] << "\t";

                        cerr << endl << "Unknown type " << command << endl;
                        exit(1);
                     }
                  }
               }
               overload_done[i][overloadan[i]]=0;
               overloadan[i]++;
               function_count++;show_statistics();
            }
         } else
         if(strcmp(command,"IMPLICITCAST")==0)
         {
            while((fin >> command) && strcmp(command,"END"))
            {
               int i;
               for(i=0;i<functionan && (strcmp(command,function[i])!=0 || nr_ary[i]!=-1);i++);
               if(i==functionan)
               {
                  function[i]=new char[strlen(command)+1];
                  strcpy(function[i],command);
                  overloadan[i]=0;
                  nr_ary[i]=-1;
                  functionan++;
               }              
               int j;
               implicit_order[i][overloadan[i]]=implicit_an++;
               for(j=0;j<3;j++)
               {
                  // fin >> command; already done
                  overload[i][overloadan[i]][j]=new char[strlen(command)+1];
                  strcpy(overload[i][overloadan[i]][j],command);
                  if(j!=2 && command[0]!='*' && strcmp(command,"VALUE")!=0)
                  {
                     int k;
                     for(k=0;k<typean && strcmp(command,atypename[k]);k++);
                  
                     if(k==typean)
                     {
                        cerr << function[i] << "\t";
                        for(k=0;k<j;k++)
                           cerr << overload[i][overloadan[i]][k] << "\t";

                        cerr << endl << "Unknown type " << command << endl;
                        exit(1);
                     }
                  }
                  if(j<2)
                     fin >> command;
               }
               overload_done[i][overloadan[i]]=0;
               overloadan[i]++;
               cast_count++;show_statistics();
            }
         } else
            cerr << "unexpected " << command << endl;
      }
   }
}



int main(void)
{
   char command[MAX_LENGTH];
   
   ifstream fin("value.in");
   
   readFromStream(fin);
   doImplicitCastExtension();
   
   int i;
   
   ofstream fout("value.out");
   ofstream fout_c("value.cpp");
   ofstream fout2("value.fn");
   ofstream fout3("value.fn2");
   ofstream fout4("value.fn0");
   
   fout << "// Rascal, the Advanced Scientific CALculator" << endl;
   fout << "// Copyright (C) 2001, 2002, Sebastian Ritterbusch (Rascal@Ritterbusch.de)" << endl;
   fout << "//" << endl;
   fout << "// This program is free software; you can redistribute it and/or" << endl;
   fout << "// modify it under the terms of the GNU General Public License" << endl;
   fout << "// as published by the Free Software Foundation; either version 2" << endl;
   fout << "// of the License, or (at your option) any later version." << endl;
   fout << "//" << endl;
   fout << "// This program is distributed in the hope that it will be useful," << endl;
   fout << "// but WITHOUT ANY WARRANTY; without even the implied warranty of" << endl;
   fout << "// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the" << endl;
   fout << "// GNU General Public License for more details." << endl;
   fout << "//" << endl;
   fout << "// You should have received a copy of the GNU General Public License" << endl;
   fout << "// along with this program; if not, write to the Free Software" << endl;
   fout << "// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." << endl;
   fout << "//" << endl;

   fout << "// This is an automatically generated file. Do not edit!" << endl;
   fout << endl;

   fout_c << "// Rascal, the Advanced Scientific CALculator" << endl;
   fout_c << "// Copyright (C) 2001, 2002, Sebastian Ritterbusch (Rascal@Ritterbusch.de)" << endl;
   fout_c << "//" << endl;
   fout_c << "// This program is free software; you can redistribute it and/or" << endl;
   fout_c << "// modify it under the terms of the GNU General Public License" << endl;
   fout_c << "// as published by the Free Software Foundation; either version 2" << endl;
   fout_c << "// of the License, or (at your option) any later version." << endl;
   fout_c << "//" << endl;
   fout_c << "// This program is distributed in the hope that it will be useful," << endl;
   fout_c << "// but WITHOUT ANY WARRANTY; without even the implied warranty of" << endl;
   fout_c << "// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the" << endl;
   fout_c << "// GNU General Public License for more details." << endl;
   fout_c << "//" << endl;
   fout_c << "// You should have received a copy of the GNU General Public License" << endl;
   fout_c << "// along with this program; if not, write to the Free Software" << endl;
   fout_c << "// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." << endl;
   fout_c << "//" << endl;

   fout_c << "// This is an automatically generated file. Do not edit!" << endl;
   fout_c << endl;
   
   fout_c << "#include \"value.hpp\"" << endl << endl;

   fout << "#ifndef VALUE_OUT_INCLUDED" << endl;
   fout << "#define VALUE_OUT_INCLUDED" << endl;
   fout << endl;
   fout << "#define VALUE_CONFIGURATION \"" << configuration << "\"" << endl;   
   fout << endl;
   for(i=0;i<HPPan;i++)
      fout << "#include \"" << HPPs[i] << "\"" << endl;
   
   fout << endl;
   
   fout << "class value" << endl;
   fout << "{" << endl;
   
   fout << "   private:" << endl;
   fout << "      enum TYPE {";
   for(i=0;i<typean;i++)
   if(i>0)
      fout << atypename[i] << ',';
   else
      fout << atypename[i] << "=1,";
   fout << "VALUE,VALUEERROR};" << endl << endl;
   fout << "      TYPE type;" << endl <<endl;
   fout << "      union" << endl;
   fout << "      {" << endl;
   for(i=0;i<typean;i++)
      fout << "         " << ctypename[i] << " *i"<<atypename[i] << ";" << endl;
   fout << "      } iValue;" << endl;
   fout << "   public:" << endl;
   for(i=0;i<typean;i++)
   {
      if(constructor[i]==0)
      {
         fout << "      value(const " << ctypename[i] << " & a" 
              << ctypename[i]  << ",TYPE aType=" << atypename[i]<<")";
              
         fout << ";" << endl;
         
         fout_c << "value::value(const " << ctypename[i] << " & a" 
                << ctypename[i]  << ",TYPE aType)";
         
         fout_c << "      {" << endl;
         fout_c << "         switch(aType)" << endl;
         fout_c << "         {" << endl;
         int j;
         for(j=i;j<typean;j++)
         {
            if(strcmp(ctypename[i],ctypename[j])==0)
            {
               fout_c << "            case " << atypename[j] << ":" << endl;
               fout_c << "               iValue.i" <<atypename[i] 
                    << "= new " << ctypename[i] << "(a" << ctypename[i] 
                    << ");" << endl;
               fout_c << "               type=aType;" << endl;
               fout_c << "               break;" << endl;
               constructor[j]=1;
            }
         }
         fout_c << "            default:" << endl;
         fout_c << "               type=VALUEERROR; " << endl;
         fout_c << "               break;" << endl;
         fout_c << "         }" << endl;
         fout_c << "      }" << endl;
      }
   }
   fout << "      value(void);" << endl;
   fout_c << "value::value(void)" << endl;
   fout_c << "      {" << endl;
   fout_c << "         type=VALUEERROR;" << endl;
   fout_c << "      }" << endl;
   fout << "      value(const value & va,TYPE into=VALUE);" << endl;
   fout_c << "value::value(const value & va,TYPE into) : type(va.type)" << endl;
   fout_c << "      {" << endl;
   fout_c << "         if(into==type) into=VALUE; // then it isn't a cast" << endl;
   fout_c << "         switch(into)" << endl;
   fout_c << "         {" << endl;
   fout_c << "            case VALUE:" << endl;
   fout_c << "               switch(type)" << endl;
   fout_c << "               {" << endl;
   for(i=0;i<typean;i++)
   {
      fout_c << "                  case " << atypename[i] << ": " 
           << "iValue.i" << atypename[i] << "=new " << ctypename[i] 
           <<"(*(va.iValue.i" << atypename[i] << ")); break;" << endl; 
   }   
   fout_c << "                     default: type=VALUEERROR; break; // impossible case" << endl;
   fout_c << "               } break;" << endl;
   for(i=0;i<functionan;i++)
      if(nr_ary[i]==-1)
      {
         int j,k;
         fout_c << "            case " << function[i] << ":" << endl;
         fout_c << "               switch(type)" << endl;
         fout_c << "               {" << endl;
         int defaultdone=0;
         for(j=0;j<overloadan[i];j++)
         {
            for(k=j+1;k<overloadan[i] && strcmp(overload[i][j][1],overload[i][k][1])!=0;k++);
            if(k>=overloadan[i]) 
            {           
               if(overload[i][j][1][0]!='*')
                  fout_c << "                  case " << overload[i][j][1] << ":" << endl;
               else
               {
                  if(defaultdone)
                     cerr << "Error! Multiple defaults for cast to " << function[i] << endl;
                  else
                  {
                     defaultdone=1;
                     fout_c << "                  default:" << endl;
                  }
               }   
               fout_c << "                  {" << endl;
               for(k=0;k<typean && strcmp(overload[i][j][1],atypename[k]);k++);
               if(k<typean)
                  fout_c << "                     const " << ctypename[k] << "& a(*(va.iValue.i"
                       << atypename[k] << "));" << endl;
               else
                  fout_c << "                     const value & a(va);" <<endl;
               for(k=0;k<typean && strcmp(overload[i][j][0],atypename[k]);k++);
               fout_c << "                     iValue.i" 
                    << atypename[k] << "=new " << ctypename[k] 
                    <<"("<<overload[i][j][2]<<");" << endl; 
               fout_c << "                     type=into;" << endl;
               fout_c << "                  } break;" << endl;
            }
         }
         if(!defaultdone)
            fout_c << "                  default: type=VALUEERROR; break; // undefined cast" << endl;
         fout_c << "               }" << endl;
         fout_c << "               break;" << endl;
         
      }
   fout_c << "            default: type=VALUEERROR; break;" << endl;
   fout_c << "         }" << endl;
   fout_c << "      }" << endl;
   
   fout << "      value & operator = (const value & from);" << endl;
   fout_c << "value & value::operator = (const value & from)" << endl;
   fout_c << "      {" << endl;
   fout_c << "         value newvalue(from);" << endl;
   fout_c << "         switch(type)" << endl;
   fout_c << "         {" << endl;
   for(i=0;i<typean;i++)
   {
      fout_c << "            case " << atypename[i] << ": " 
           << "delete iValue.i" << atypename[i] << "; break;" << endl; 
   }   
   fout_c << "            default: break; " << endl;
   fout_c << "         }" << endl;
   fout_c << "         type=newvalue.type;" << endl;
   fout_c << "         switch(type)" << endl;
   fout_c << "         {" << endl;
   for(i=0;i<typean;i++)
   {
      fout_c << "            case " << atypename[i] << ": " 
           << "iValue.i" << atypename[i] << "=new "<<ctypename[i]<<"(*(newvalue.iValue.i"<<atypename[i]
           << ")); break;" << endl; 
   }   
   fout_c << "            default: break;" << endl;
   fout_c << "         }" << endl;
   fout_c << "         return *this;" << endl;
   fout_c << "      }" << endl;
   
   fout << "      ~value(void);" << endl;
   fout_c << "value::~value(void)" << endl;
   fout_c << "      {" << endl;
   fout_c << "         switch(type)" << endl;
   fout_c << "         {" << endl;
   for(i=0;i<typean;i++)
   {
      fout_c << "            case " << atypename[i] << ": " 
           << "delete iValue.i" << atypename[i] << "; break;" << endl; 
   }   
   fout_c << "            default: break; " << endl;
   fout_c << "         }" << endl;
   fout_c << "      }" << endl;
   
   for(i=0;i<typean;i++)
   {
      fout << "      int is" << atypename[i] << "(void) const { return (type=="
           << atypename[i] << "); }" << endl;
      fout << "      const " << ctypename[i] << " & as" << atypename[i] 
           << "(void) const { return *(iValue.i"<<atypename[i]<<"); }" 
           << endl << endl;
      fout << "            " << ctypename[i] << " & as" << atypename[i] 
           << "(void) { return *(iValue.i"<<atypename[i]<<"); }" 
           << endl << endl;
   }
   fout << "      string Typename(void) const" << endl;
   fout << "      {" << endl;
   fout << "         switch(type)" << endl;
   fout << "         {" << endl;
   for(i=0;i<typean;i++)
   {
      fout << "            case " << atypename[i] << ": return \"" 
           << atypename[i] << "\";" << endl;
   }
   fout << "            default: return \"VALUEERROR\";" << endl;
   fout << "         }" << endl;
   fout << "      }" << endl << endl;
   
   fout << "      // This does not have type-safety yet!" << endl;
   fout << "      friend int   operator <(const value &va, const value &vb) { value temp(less(va,vb)); if(temp.isINTEGER()) return temp.asINTEGER(); else return 0; }" << endl;
   fout << "      friend int   operator <=(const value &va, const value &vb){ value temp(lesseq(va,vb)); if(temp.isINTEGER()) return temp.asINTEGER(); else return 0; }" << endl;
   fout << "      friend int   operator >(const value &va, const value &vb) { value temp(greater(va,vb)); if(temp.isINTEGER()) return temp.asINTEGER(); else return 0; }" << endl;
   fout << "      friend int   operator >=(const value &va, const value &vb){ value temp(greatereq(va,vb)); if(temp.isINTEGER()) return temp.asINTEGER(); else return 0; }" << endl;
   fout << "      friend int   operator ==(const value &va, const value &vb){ value temp(eq(va,vb)); if(temp.isINTEGER()) return temp.asINTEGER(); else return 0; }" << endl;
   fout << "      friend int   operator !=(const value &va, const value &vb){ value temp(neq(va,vb)); if(temp.isINTEGER()) return temp.asINTEGER(); else return 1; }" << endl;
   fout << "      friend value operator &(const value &va, const value &vb) { return And(va,vb); }" << endl;
   fout << "      friend value operator |(const value &va, const value &vb) { return Or(va,vb); }" << endl;
   fout << "      friend value operator +(const value &va, const value &vb) { return add(va,vb); }" << endl;
   fout << "      friend value operator -(const value &va, const value &vb) { return sub(va,vb); }" << endl;
   fout << "      friend value operator -(const value &va) { return neg(va); }" << endl;
   fout << "      friend value operator *(const value &va, const value &vb) { return mul(va,vb); }" << endl;
   fout << "      friend value operator /(const value &va, const value &vb) { return div(va,vb); }" << endl;
   fout << "      friend value operator %(const value &va, const value &vb) { return mod(va,vb); }" << endl;
   fout << "      friend int   operator !(const value &va) { value temp(Not(va)); if(temp.asINTEGER()) return temp.asINTEGER(); else return 1; }" << endl;

   fout << "      friend value & operator +=(value &va, const value &vb) { return va=add(va,vb); }" << endl;
   fout << "      friend value & operator -=(value &va, const value &vb) { return va=sub(va,vb); }" << endl;
   fout << "      friend value & operator *=(value &va, const value &vb) { return va=mul(va,vb); }" << endl;
   fout << "      friend value & operator /=(value &va, const value &vb) { return va=div(va,vb); }" << endl;
   fout << "      friend value & operator &=(value &va, const value &vb) { return va=And(va,vb); }" << endl;
   fout << "      friend value & operator |=(value &va, const value &vb) { return va=Or(va,vb); }" << endl;

   fout << "      friend ostream & operator <<(ostream &o, const value &vb) { value out(output(vb));return out.isSTRING()?(o << out.asSTRING()):(o << \"OutputError:\"+vb.Typename()); }" << endl;
      

   fout << endl << "      // binary functions" << endl;
   fout_c << endl << "// binary functions" << endl;   
      
      
   for(i=0;i<functionan;i++)
   if(nr_ary[i]==2)
   {
      if(strncmp(function[i],"operator",8))
         fout3 << "   \"" << function[i] << "\", " << function[i] << "," << endl;

      fout << "      friend value " << function[i] 
           << "(const value &va,const value &vb);" << endl;
      fout_c << "value " << function[i] 
           << "(const value &va,const value &vb)" << endl;
           
      fout_c << "      {" << endl;
      fout_c << "         switch(va.type)" << endl;
      fout_c << "         {" << endl;
      int j,defaultdone=0;
      for(j=0;j<overloadan[i];j++)
      if(overload_done[i][j]==0)
      {
         int k;
         if(overload[i][j][1][0]!='*')
            fout_c << "            case value::" << overload[i][j][1] << ":" << endl;
         else 
         {
            defaultdone=1;
            fout_c << "            default:" << endl;
         }         
         fout_c << "            {" << endl;
         for(k=0;k<typean && strcmp(overload[i][j][1],atypename[k]);k++);
         if(k<typean)
            fout_c << "               const " << ctypename[k] << "& a(*(va.iValue.i"
                 << atypename[k] << "));" << endl;
         else
            fout_c << "               const value & a(va);" <<endl;
            
         fout_c << "               switch(vb.type)" << endl;
         fout_c << "               {" << endl;
         
         int innerdefaultdone=0;
                  
         for(k=0;k<overloadan[i];k++)
         {
            if((strcmp(overload[i][k][1],overload[i][j][1])==0 &&
               overload_done[i][k]==0 &&
               !existoverload(i,overload[i][k][1],overload[i][k][2],k+1)
               // no later override
               ) 
            || (overload[i][k][1][0]=='*' && overload[i][k][2][0]!='*'
                && !existoverload(i,overload[i][j][1],overload[i][k][2])
                   // no other exact hit
                && !existoverload(i,overload[i][j][1],"*",k+1)
                   // a later inexact hit 
               ))
            {
               if(overload[i][k][2][0]!='*')
                  fout_c << "                  case value::" << overload[i][k][2] 
                       << ":" << endl;
               else
               {
                  innerdefaultdone=1;
                  fout_c << "                  default:" << endl;
               }
               fout_c << "                  {" << endl;
               int l;
               for(l=0;l<typean && strcmp(overload[i][k][2],atypename[l]);l++);
               
               if(l<typean)
                  fout_c << "                     const " << ctypename[l] 
                       << "& b(*(vb.iValue.i" << atypename[l] << "));" << endl;
               else
                  fout_c << "                     const value & b(vb);" << endl;
                  
               fout_c << "                     return value(" 
                    << overload[i][k][3] << ",value::" << overload[i][k][0] << ");"
                    << endl;
               fout_c << "                  }  break;" << endl;
               overload_done[i][k]=1;
            } else
            if(strcmp(overload[i][k][1],overload[i][j][1])==0 &&
               overload_done[i][k]==0 &&
               existoverload(i,overload[i][k][1],overload[i][k][2],k+1)
               // a later override
               )
            {
               // still this case has to be marked as "done"
               overload_done[i][k]=1;
            } 
            
         }
         if(innerdefaultdone==0)
         {
            for(k=0;k<overloadan[i] && innerdefaultdone==0;k++)
               if(overload[i][k][1][0]=='*' && overload[i][k][2][0]=='*')
               {
                  fout_c << "                  default:" << endl;
                  fout_c << "                     return value(" 
                       << overload[i][k][3] << ",value::" << overload[i][k][0] << ");"
                       << endl;
                  fout_c << "                     break;" << endl;
                  innerdefaultdone=1;
               }            
            if(innerdefaultdone==0)
            {
               fout_c << "                  default:" << endl;
               fout_c << "                     return value();" << endl;
            }
         }
         fout_c << "               }" << endl;
         fout_c << "            }  break;" << endl;
      }
      if(defaultdone==0)
      {
         fout_c << "            default:" << endl;
         fout_c << "               return value();" << endl;
      }
      fout_c << "         }" << endl;
      fout_c << "      }" << endl;
   }

   fout << endl << "      // unary functions" << endl;
   fout_c << endl << "// unary functions" << endl;   

   for(i=0;i<functionan;i++)
   if(nr_ary[i]==1)
   {
      if(strncmp(function[i],"operator",8))
         fout2 << "   \"" << function[i] << "\", " << function[i] << "," << endl;
      fout << "      friend value " << function[i] 
           << "(const value &va);" << endl;
      fout_c << "value " << function[i] 
           << "(const value &va)" << endl;
      fout_c << "      {" << endl;
      fout_c << "         switch(va.type)" << endl;
      fout_c << "         {" << endl;
      int j;
      int defaultdone=0;
      for(j=0;j<overloadan[i];j++)
      {
         int k;
         for(k=j+1;k<overloadan[i] && strcmp(overload[i][k][1],overload[i][j][1])!=0;k++);
         if(k==overloadan[i]) // okay, no later override
         {
            if(overload[i][j][1][0]!='*')
               fout_c << "            case value::" << overload[i][j][1] << ":" << endl;
            else
            {
               defaultdone=1;
               fout_c << "            default:" << endl;
            }
            
            fout_c << "            {" << endl;
            for(k=0;k<typean && strcmp(overload[i][j][1],atypename[k]);k++);
            if(k<typean)
               fout_c << "               const " << ctypename[k] 
                    << "& a(*(va.iValue.i" << atypename[k] << "));" << endl;
            else
               fout_c << "               const value & a(va);" << endl;
            fout_c << "               return value(" 
                       << overload[i][j][2] << ",value::" << overload[i][j][0] << ");"
                       << endl;
            fout_c << "            }  break;" << endl;
         }
      }
      if(defaultdone==0)
      {
         fout_c << "            default:" << endl;
         fout_c << "               return value();" << endl;
      }
      fout_c << "         }" << endl;
      fout_c << "      }" << endl;
   }

   fout << endl << "      // procedures" << endl;
   fout_c << endl << "// procedures" << endl;   

   for(i=0;i<functionan;i++)
   if(nr_ary[i]==0)
   {
      fout4 << "   \"" << function[i] << "\", " << function[i] << "," << endl;
      fout << "      friend value " << function[i] 
           << "(void);" << endl;
      fout_c << "value " << function[i] 
           << "(void)" << endl;
      fout_c << "      {" << endl;
      fout_c << "         return value(" 
                 << overload[i][0][1] << ",value::" << overload[i][0][0] << ");"
                 << endl;
      fout_c << "      }" << endl;
   }
   fout << "};" << endl;

   for(i=0;i<CPPan;i++)
      fout_c << "#include \"" << CPPs[i] << "\"" << endl;
   
   ofstream fout6("value.tex");
   for(i=0;i<TEXan;i++)
      fout6 << "\\input{" << TEXs[i] << "}" << endl;      
      
   ofstream fout7("value.mak");
   for(i=0;i<MAKan;i++)
      fout7 << "include " << MAKs[i] << endl;

   fout << endl;
   
   fout << "extern char *rascal_module_indices[];" << endl;
   fout << "extern char *rascal_help_indices[];" << endl;
   fout << "extern char *rascal_help_data[];" << endl;

   fout << "#endif" << endl;


   fout_c << endl;
   fout_c << "char *rascal_module_indices[]="<< endl << "{" << endl;
   for(i=0;i<MODULEan;i++)
      fout_c << "   \"" << MODULEname[i] << "\"," << endl; 
   fout_c << "   NULL" << endl;
   fout_c << "};" << endl << endl;
   fout_c << "char *rascal_help_indices[]="<< endl << "{" << endl;
   for(i=0;i<HELPan;i++)
      fout_c << "   \"" << HELPname[i] << "\"," << endl; 
   fout_c << "   NULL" << endl;
   fout_c << "};" << endl << endl;
   
   fout_c << "char *rascal_help_data[]="<< endl << "{" << endl;
   for(i=0;i<HELPan;i++)
   {
      ifstream in(HELPfile[i],ios::binary);
      in.unsetf(ios::skipws);
      char c;
      fout_c << "   \"";
      while(in)
      {
         c=0;
         in >> c;
         if(c=='\n')
            fout_c << "\\n";
         else if(c=='\t')
            fout_c << "\\t";
         else if(c=='\"')
            fout_c << "\\\"";
         else if(c!=0)
            fout_c << c;               
      }
      fout_c << "\"," << endl;
   }
   fout_c << "   NULL" << endl;
   fout_c << "};" << endl << endl;

   show_final_statistics();
   return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1