# ###################################################################
# function init() initialized the generation of the c++ classes
#  required to track units and dimensions throughout as the 
#  calculation progresses
# ###################################################################
function init() {
  NUMNUM=25
  newName[ 1]="UnsignedChar"; 		oldName[ 1]="unsigned char"
  newName[ 2]="Char";			oldName[ 2]="char"
  newName[ 3]="UnsignedShort"; 		oldName[ 3]="unsigned short"
  newName[ 4]="Short";			oldName[ 4]="short"
  newName[ 5]="UnsignedInt"; 		oldName[ 5]="unsigned int"
  newName[ 6]="Int";			oldName[ 6]="int"
  newName[ 7]="UnsignedLong"; 		oldName[ 7]="unsigned long"
  newName[ 8]="Long";			oldName[ 8]="long"
  newName[ 9]="UnsignedLongLong"; 	oldName[ 9]="unsigned long"
  newName[10]="LongLong"; 		oldName[10]="long long"
  newName[11]="Float";			oldName[11]="float"
  newName[12]="Double";			oldName[12]="double"
  newName[13]="LongDouble";		oldName[13]="long double"
  ind[0]=""
  ind[1]="  "
  ind[2]=ind[1] ind[1]
  ind[3]=ind[2] ind[1]
  ind[4]=ind[3] ind[1]
  ind[5]=ind[4] ind[1]
  # -----------------------------------
  aOpers[ 1]="+"  # -----> Arithmetic Operators
  aOpers[ 2]="-"
  aOpers[ 3]="*"
  aOpers[ 4]="/"
  aOpers[ 5]="+=" # -----> 5,6,7 and 8 require units/dimensions checking
  aOpers[ 6]="-="
  aOpers[ 7]="*="
  aOpers[ 8]="/="
  aopers=8
  # -----------------------------------
  pOpers[ 1]="++" # -----> Prefix/Postfix Operators
  pOpers[ 2]="--"
  popers=2
  # -----------------------------------
  iOpers[ 1]="%"    # -----> Operators that require integer operands
  iOpers[ 2]="&"
  iOpers[ 3]="^"
  iOpers[ 4]="|"
  iOpers[ 5]="<<"
  iOpers[ 6]=">>"
  iOpers[ 7]= "%="
  iOpers[ 8]= "&="
  iOpers[ 9]= "|="
  iOpers[10]= "^="
  iOpers[11]="<<="
  iOpers[12]=">>="
  iopers=12
  # -----------------------------------
  skip[ 9]=1
  skip[10]=1
  skip[13]=1
  # -----------------------------------
  skip1[11]=1
  skip1[12]=1
  skip1[13]=1
  
}

# ###################################################################
#  function gen_aOpers(i,j ,k,n) generates the +, - *, /, +=, -= *=, /=
#    functions for units and dimensions tracking.
# ###################################################################
function gen_aOpers(i,j ,k,n,cast1,cast2) {
  if(j in skip) return
  n=i>j?i:j
  if(i==j) { # -----> Generate Member arithmetic functions
    for(k=1; k<=aopers; k++) {
      printf("%s%s operator %-3s (%s& r); // 2a\n" ,ind[2],newName[i],aOpers[k],newName[i]) > fouth
      printf("// **********************************************************************************************************\n") > foutc
      printf("%s%s %s::operator %-3s (%s& r) { // 1a\n" ,ind[0],newName[i],newName[i],aOpers[k],newName[i]) > foutc
      printf("%s%s num;\n",ind[1],newName[n]) > foutc
      printf("%snum.val = (val %s r.val);\n",ind[1],aOpers[k]) > foutc
      printf("%snum.u = (u %-3s r.u);\n",ind[1],aOpers[k]) > foutc
      printf("%sreturn num;\n",ind[1]) > foutc
      printf("%s}\n\n",ind[0]) > foutc
    }
  } else {
    for(k=1; k<=aopers; k++) { # -----> Generate friend arithmetic Functions
      printf("%sfriend %s operator %-3s (%s& , %s&); // 4a\n" ,ind[2],newName[n],aOpers[k],newName[i],newName[j]) > fouth
      printf("// **********************************************************************************************************\n") > foutc
      printf("%s%s operator %-3s (%s& l , %s& r) { // 3a\n"   ,ind[0],newName[n],aOpers[k],newName[i],newName[j]) > foutc
      printf("%s%s num;\n",ind[1],newName[n]) > foutc
      cast1=cast2=""
      if(match(aOpers[k],"[=]")<=0) {
        printf("%snum.val = (l.val %s r.val);\n",ind[1],aOpers[k]) > foutc
      } else {
        cast1=sprintf("(%s)",oldName[n])
        cast2=sprintf("(%s)",oldName[i])
        printf("%snum.val = %s(l.val %s %sr.val);\n",ind[1],cast1,aOpers[k],cast2) > foutc
      }
      printf("%snum.u = (l.u %-3s r.u);\n",ind[1],aOpers[k]) > foutc
      printf("%sreturn num;\n",ind[1]) > foutc
      printf("%s}\n\n",ind[0]) > foutc
    }
  }
  for(k=1; k<=aopers; k++) { # -----> Generate friend arithmetic Functions
    # --------------------------------------------------------------------------------------------------------
    printf("%sfriend %s operator %-3s (%s& , %s&); // 5a\n" ,ind[2],newName[n],aOpers[k],newName[i],oldName[j]) > fouth
    printf("// **********************************************************************************************************\n") > foutc
    printf("%s%s operator %-3s (%s& l , %s& r) {   // 6a\n" ,ind[0],newName[n],aOpers[k],newName[i],oldName[j]) > foutc
    printf("%s%s num;\n",ind[1],newName[n]) > foutc
    cast1=cast2=""
    if(match(aOpers[k],"[=]")<=0) {
      if(ij) cast2=sprintf("(%s)",oldName[n])
      printf("%snum.val = (%sl.val %s %sr);\n",ind[1],cast1,aOpers[k],cast2) > foutc
    } else {
      cast1=sprintf("(%s)",oldName[n])
      cast2=sprintf("(%s)",oldName[i])
      printf("%snum.val = %s(l.val %s %sr);\n",ind[1],cast1,aOpers[k],cast2) > foutc
    }
    printf("%snum.u = l.u;\n",ind[1]) > foutc
    printf("%sreturn num;\n",ind[1]) > foutc
    printf("%s}\n\n",ind[0]) > foutc
    # --------------------------------------------------------------------------------------------------------
    printf("%sfriend %s operator %-3s (%s& , %s&); // 7a\n" ,ind[2],newName[n],aOpers[k],oldName[i],newName[j]) > fouth
    printf("// **********************************************************************************************************\n") > foutc
    printf("%s%s operator %-3s (%s& l , %s& r) {   // 8a\n" ,ind[0],newName[n],aOpers[k],oldName[i],newName[j]) > foutc
    printf("%s%s num;\n",ind[1],newName[n]) > foutc
    cast1=cast2=""
    if(match(aOpers[k],"[=]")<=0) {
      if(ij) cast2=sprintf("(%s)",oldName[n])
      printf("%snum.val = (%sl %s %sr.val);\n",ind[1],cast1,aOpers[k],cast2) > foutc
    } else {
      cast1=sprintf("(%s)",oldName[n])
      cast2=sprintf("(%s)",oldName[i])
      printf("%snum.val = %s(l %s %sr.val);\n",ind[1],cast1,aOpers[k],cast2) > foutc
    }
    printf("%snum.u = r.u;\n",ind[1]) > foutc
    printf("%sreturn num;\n",ind[1]) > foutc
    printf("%s}\n\n",ind[0]) > foutc
  }
}

# ###################################################################
#  function gen_iOpers(i,j) generates the %, &, ^, | , <<, >>,
#    %=, &=, ^=, |=, <<=, >>=  functions for units and dimensions
#    tracking.
# ###################################################################
function gen_iOpers(i,j ,k,n) {
  if(j in skip || j  in skip1) return
  if(i in skip || i  in skip1) return
  n=i>j?i:j
  if(i==j) { # -----> Generate Member bitwise functions
    for(k=1; k<=iopers; k++) {
      printf("// **********************************************************************************************************\n") > foutc
      printf("%s%s operator %-3s (%s& r); // 2i\n" ,ind[2],newName[n],iOpers[k],newName[i]) > fouth
      printf("%s%s %s::operator %-3s (%s& r) { // 1i\n" ,ind[0],newName[n],newName[i],iOpers[k],newName[i]) > foutc
      printf("%s%s num;\n",ind[1],newName[n]) > foutc
      printf("%snum.val = (val %s r.val);\n",ind[1],iOpers[k]) > foutc
      printf("%snum.u = (u %-3s r.u);\n",ind[1],iOpers[k]) > foutc
      printf("%sreturn num;\n",ind[1]) > foutc
      printf("%s}\n\n",ind[0]) > foutc
    }
  } else {
    for(k=1; k<=iopers; k++) { # -----> Generte friend bitwise Functions
      printf("%sfriend %s operator %-3s (%s& , %s&); // 4i\n" ,ind[2],newName[n],iOpers[k],newName[i],newName[j]) > fouth
      printf("// **********************************************************************************************************\n") > foutc
      printf("%s%s operator %-3s (%s& l , %s& r) { // 3i\n"   ,ind[0],newName[n],iOpers[k],newName[i],newName[j]) > foutc
      printf("%s%s num;\n",ind[1],newName[n]) > foutc
      printf("%snum.val = (l.val %s r.val);\n",ind[1],iOpers[k]) > foutc
      printf("%snum.u = (l.u %-3s r.u);\n",ind[1],iOpers[k]) > foutc
      printf("%sreturn num;\n",ind[1]) > foutc
      printf("%s}\n\n",ind[0]) > foutc
    }
  }
  for(k=1; k<=iopers; k++) { # -----> Generte friend bitwise Functions
    # --------------------------------------------------------------------------------------------------------
    printf("%sfriend %s operator %-3s (%s& , %s&); // 5i\n" ,ind[2],newName[n],iOpers[k],newName[i],oldName[j]) > fouth
    printf("// **********************************************************************************************************\n") > foutc
    printf("%s%s operator %-3s (%s& l , %s& r) { // 6i\n"   ,ind[0],newName[n],iOpers[k],newName[i],oldName[j]) > foutc
    printf("%s%s num;\n",ind[1],newName[n]) > foutc
    printf("%snum.val = (l.val %s r);\n",ind[1],iOpers[k]) > foutc
    printf("%snum.u = l.u;\n",ind[1],iOpers[k]) > foutc
    printf("%sreturn num;\n",ind[1]) > foutc
    printf("%s}\n\n",ind[0]) > foutc
    # --------------------------------------------------------------------------------------------------------
    printf("%sfriend %s operator %-3s (%s& , %s&); // 7i\n" ,ind[2],newName[n],iOpers[k],oldName[i],newName[j]) > fouth
    printf("// **********************************************************************************************************\n") > foutc
    printf("%s%s operator %-3s (%s& l , %s& r) { // 8i\n"   ,ind[0],newName[n],iOpers[k],oldName[i],newName[j]) > foutc
    printf("%s%s num;\n",ind[1],newName[n]) > foutc
    printf("%snum.val = (l %s r.val);\n",ind[1],iOpers[k]) > foutc
    printf("%snum.u = r.u;\n",ind[1],iOpers[k]) > foutc
    printf("%sreturn num;\n",ind[1]) > foutc
    printf("%s}\n\n",ind[0]) > foutc
  }
}

# ###################################################################
#  function gen_pOpers(i,j) generates the i++, and ++i pre and post
#    increment functions for units and dimensions tracking.
# ###################################################################
function gen_pOpers(i ,k,arg) {
  arg[1]="void"
  arg[2]="int"
  # -----> Generate Member pre and post increment functions
  for(j=1; j<=2; j++) {
    if(j==1) c="Prefix operator"
    if(j==2) c="Postfix operator"
    for(k=1; k<=popers; k++) {
      printf("// **********************************************************************************************************\n") > foutc
      printf("%s%s %s::operator %s(%s) { // 1p, %s\n",ind[0],newName[i],newName[i],pOpers[k],arg[j],c) > foutc
      printf("%s%s operator %s(%s);  // 2p, %s\n",ind[2],newName[i],pOpers[k],arg[j],c) > fouth
      if(j==1) printf("%s %sval;\n",ind[1],pOpers[k]) > foutc
      if(match(newName[i],"Unsigned")==1 &&  k==2) printf("%sassert(val>=1);\n",ind[1]) > foutc
      if(j==2) printf("%s val%s;\n",ind[1],pOpers[k]) > foutc
      printf("%sreturn *this;\n",ind[1]) > foutc
      printf("%s}\n\n",ind[0]) > foutc
    }
  }
}
# ###################################################################
#  function gen_constructors(i) generates the constructors and
#    destructors for each class
# ###################################################################
function gen_constructors(i ,k,arg) {
  printf("// *********************************************************************************************************\n") > foutc
  printf("%s// First class %s constructor\n",ind[0],newName[i]) > foutc
  printf("// *********************************************************************************************************\n") > foutc
  printf("%s%s::%s() {\n",ind[0],newName[i],newName[i]) > foutc
  printf("%sval=0;\n",ind[1]) > foutc
  printf("%sstate=UNDEF;\n",ind[1]) > foutc
  printf("%su.init();\n",ind[1]) > foutc
  printf("%s}\n",ind[0]) > foutc
  
  printf("// *********************************************************************************************************\n") > foutc
  printf("%s// Second class %s constructor\n",ind[0],newName[i]) > foutc
  printf("// *********************************************************************************************************\n") > foutc
  printf("%s%s::%s(char* str) {\n",ind[0],newName[i],newName[i]) > foutc
  printf("%sval=0;\n",ind[1]) > foutc
  printf("%sstate=UNDEF;\n",ind[1]) > foutc
  printf("%su.init(str);\n",ind[1]) > foutc
  printf("%s}\n",ind[0]) > foutc
  
  printf("// *********************************************************************************************************\n") > foutc
  printf("%s// First class %s destructor\n",ind[0],newName[i]) > foutc
  printf("// *********************************************************************************************************\n") > foutc
  printf("%s%s::~%s() {\n",ind[0],newName[i],newName[i]) > foutc
  printf("%sval=0;\n",ind[1]) > foutc
  printf("%sstate=UNDEF;\n",ind[1]) > foutc
  printf("%su.init();\n",ind[1]) > foutc
  printf("%s}\n",ind[0]) > foutc
}

# ###################################################################
#  Main 'gen.awk' Routine
# ###################################################################
BEGIN {
  foutc="test.cpp"
  fouth="test.h"
  init()
  printf("#include \n") > foutc
  printf("#include \"units.h\"\n") > foutc
  printf("#include \"test.h\"\n") > foutc
  # ----- Generate the class declarations
  for(i=1;i<=13; i++) {
     if(i in skip) continue
     printf("class %s;\n",newName[i]) > fouth
  }
  for(i=1;i<=13; i++) {
    if(i in skip) continue
    printf("%s// %s ----------------------------------------------------------------\n",ind[0],i) > foutc
    printf("%s%s temp_%s[%d];\n",ind[0],newName[i],newName[i],NUMNUM) > foutc
    printf("%sint %s_index=0;\n",ind[0],newName[i]) > foutc
  }
  for(i=1; i<=13; i++) {
    if(i in skip) continue
    printf("class %s {\n",newName[i]) > fouth
    printf("%spublic:\n",ind[1]) > fouth
    printf("%sstatic char bf[200];\n",ind[2]) > fouth
    printf("%s%s val;\n",ind[2],oldName[i]) > fouth
    printf("%sUnits u;\n",ind[2]) > fouth
    printf("%s/* Units and dimensions associated with this numeric object */\n",ind[2]) > fouth
    printf("%sUNITS_t  state;   /* State=DUMMY/SET */\n",ind[2]) > fouth
    printf("%s// First class %s constructor\n",ind[2],newName[i]) > fouth
    printf("%s%s();\n",ind[2],newName[i]) > fouth
    printf("%s// Second class %s constructor\n",ind[2],newName[i]) > fouth
    printf("%s%s(char*);\n",ind[2],newName[i]) > fouth
    printf("%s// First class %s destructor\n",ind[2],newName[i]) > fouth
    printf("%s~%s();\n",ind[2],newName[i]) > fouth
    gen_constructors(i)
    for(j=1;j<=13; j++) {
      gen_aOpers(i,j)
    }
    for(j=1;j<=13; j++) gen_iOpers(i,j)
    gen_pOpers(i)
    printf("}; // -----> end of class %s\n\n",newName[i]) > fouth
  }
  close(fouth)
  close(foutc)
}