/* ************************************* */
/*   mfg.c                               */
/*   Copyright 2001 Martin L"auter       */
/*   laeuter@mathematik.uni-leipzig.de   */
/* ************************************* */

#include <stdio.h>
#define a (n1-1)
#define b (n2-1)
#define FREQ 4
#define CNTMETHOD 2
#define DIAGNOSIS 0
#define MAX_ANF 32

typedef struct {
  int nr,wlen,slen,inwlen,inslen;
} TInfo;

TInfo *info;
int anf[MAX_ANF];
unsigned char lenneeded[16];

int ctr,mctr,n1,n2,lastp;

gibtext(int i, int j)
{ int p;
  p=j*n1+i;
  if(info[p].wlen) {
    if(info[p-n1].nr>=0) {
      printf("  mask=feld[%d].mask=feld[%d].smask&(*((NODE *)(feld[%d].wnode)));\n",info[p].nr,info[p].nr,info[p].nr);
    } else {
      if(info[p].slen) {
        if(info[p].wlen!=info[p].slen) {
          printf("  mask=feld[%d].mask=feld[%d].smask&(*((NODE *)(feld[%d].wnode)));\n",info[p].nr,info[p].nr,info[p].nr);
        } else {
          printf("  mask=feld[%d].mask=feld[%d].smask;\n",info[p].nr,info[p].nr);
        }
      } else {
        printf("  mask=feld[%d].mask=(*((NODE *)(feld[%d].wnode)));\n",info[p].nr,info[p].nr);
      }
    }
  } else {
    if(info[p-1].nr<0) {
      printf("  mask=feld[%d].mask=feld[%d].smask;\n",info[p].nr,info[p].nr);
    }
  }
  printf("m%d:\n",mctr);
//  printf("fprintf(stderr,\" @%d\");\n",mctr);
  if(mctr) {
    if(DIAGNOSIS) {
      printf("  if(mask==0) { mask=feld[%d].mask; acc[%d]++; goto m%d; }\n",info[lastp].nr,info[p].nr,mctr-1);
    } else {
      printf("  if(mask==0) { mask=feld[%d].mask; goto m%d; }\n",info[lastp].nr,mctr-1);
    }
  } else { printf("  if(mask==0) return;\n"); }
  printf("  maske=mask&(-mask); feld[%d].mask=mask^maske;\n",info[p].nr);
  if((info[p+1].nr>=0)||(info[p+n1].nr>=0)) {
    switch(CNTMETHOD) {
      case 1: printf("  log=(31-__cntlzw(maske))<<2;\n"); break;
      case 2: printf("  log=0; if(maske&0xffff0000) { maske>>=16; log+=64; }\n");
              printf("  if(maske&0xff00) { maske>>=8; log+=32; }\n");
              printf("  log+=logtab[maske];"); break;
      case 3: printf("  log=logtab[(maske*0x4653adf)>>27];\n"); break;
      default: break;
    }
    if(info[p+n1].nr>=0) {
      if(0!=0) { /* evtl. noch Beginn eines Wortes testen */
        printf("  mask=*(uint32 *)(feld[%d].snode=dawg%d+PTR(*(NODE *)(feld[%d].snode+log)));\n",info[p+n1].nr,info[p].inslen,info[p].nr);
        printf("  if((feld[%d].smask=(*(uint32 *)(feld[%d].wnode))&mask)==0) { mask=feld[%d].mask; goto m%d; }\n",info[p+n1].nr,info[p+n1].nr,info[p].nr,mctr);
      } else {
        printf("  feld[%d].smask=*(uint32 *)(feld[%d].snode=dawg%d+PTR(*(NODE *)(feld[%d].snode+log)));\n",info[p+n1].nr,info[p+n1].nr,info[p].inslen,info[p].nr);
      }
    }
    if(info[p+1].nr>=0) {
      if((info[p+1-n1].nr>=0)||(info[p+1].slen>0)) {
        printf("  mask=feld[%d].mask=feld[%d].smask&(*(uint32 *)(feld[%d].wnode=dawg%d+PTR(*(NODE *)(feld[%d].wnode+log))));\n",info[p+1].nr,info[p+1].nr,info[p+1].nr,info[p].inwlen,info[p].nr);
      } else {
        printf("  mask=feld[%d].mask=*(uint32 *)(feld[%d].wnode=dawg%d+PTR(*(NODE *)(feld[%d].wnode+log)));\n",info[p+1].nr,info[p+1].nr,info[p].inwlen,info[p].nr);
      }
    }
    if(--ctr==0)
      { printf("  ausgabe(feld,partstr);\n"); }
    
  }
  mctr++;
  lastp=p;
}  

int main(int argc,char **argv)
{ int s,i,j,sanf0,c,nsp,anzf; FILE *fin;
  n1=n2=0; info=NULL;
  if(fin=fopen(argv[1],"rb")) {
    s=0;
    while((c=getc(fin))!=EOF) {
      if(c=='\n') {
        if(n1<s) n1=s;
        n2++; s=0;
      } else {
        s++;
      }
    }
    fclose(fin);
    n1+=2; n2+=2;
    info=(TInfo *)malloc(sizeof(TInfo)*n1*n2);
  }
  if(info&&(fin=fopen(argv[1],"rb"))) {
    for(i=n2*n1-1;i>=0;i--) {
      info[i].nr=-1;
      info[i].wlen=info[i].slen=info[i].inwlen=info[i].inslen=0;
    }
    j=n1; s=1; i=0;
    while((c=getc(fin))!=EOF) {
      if(c=='\n') {
        j+=n1;
        s=1;
      } else {
        if(c!=' ') {
          info[j+s].nr=i++;
        }
        s++;
      }
    }
    fclose(fin);
  }
  anzf=i;
  s=0;
  for(j=1;j<n2-1;j++) {
    for(i=1;i<n1-1;i++) {
      if((info[j*n1+i-1].nr<0)&&(info[j*n1+i+1].nr>=0)&&(info[j*n1+i].nr>=0)) {
        if(s==MAX_ANF) {
          fprintf(stderr,"Too many word beginnings (%d)\n",s);
          exit(1);
        }
        anf[s++]=j*n1+i;
      }
    }
  }
  sanf0=s;
  for(j=1;j<n2-1;j++) {
    for(i=1;i<n1-1;i++) {
      if((info[(j-1)*n1+i].nr<0)&&(info[(j+1)*n1+i].nr>=0)&&(info[j*n1+i].nr>=0)) {
        if(s==MAX_ANF) {
          fprintf(stderr,"Too many word beginnings (%d)\n",s);
          exit(1);
        }
        anf[s++]=j*n1+i;
      }
    }
  }
  if(s==0) return(0);
  for(i=0;i<16;i++) lenneeded[i]=0;
  for(i=0;i<sanf0;i++) {
    for(j=anf[i];info[j].nr>=0;j++);
    info[anf[i]].wlen=j-=anf[i];
    if(j>15) {
      fprintf(stderr,"Too long a word\n");
      exit(1);
    }
    lenneeded[j]++;
    for(j=anf[i];info[j].nr>=0;info[j++].inwlen=info[anf[i]].wlen);
  }
  for(;i<s;i++) {
    for(j=anf[i];info[j].nr>=0;j+=n1);
    info[anf[i]].slen=j=(j-anf[i])/n1;
    if(j>15) {
      fprintf(stderr,"Too long a word\n");
      exit(1);
    }
    lenneeded[j]++;
    for(j=anf[i];info[j].nr>=0;j+=n1) info[j].inslen=info[anf[i]].slen;
  }
  printf("#include <stdio.h>\n");
  printf("#include \"MDawg.h\"\n");
  printf("#include \"MDawg.cpp\"\n\n");
  j=0;
  for(i=2;i<16;i++) {
    if(lenneeded[i]) {
      printf(j?",*rdawg%d":"unsigned char *rdawg%d",i);
      j++;
    }
  }
  printf(";\n\n");
  printf("typedef unsigned int uint32;\n\n");
  printf("typedef struct {\n");
  printf("  unsigned char *snode,*wnode;\n");
  printf("  uint32 smask,mask;\n");
  printf("} TFeld;\n\n");
  switch(CNTMETHOD) {
    case 2: printf("unsigned char logtab[256];\n\n"); break;
    case 3: printf("unsigned char logtab[32]={ 0,4,8,24,12,44,28,64,16,56,48,84,32,92,68,104,124,20,40,60,52,80,88,100,120,36,76,96,116,72,112,108};\n\n");
    default: break;
  }
  printf("TFeld afeld[%d];\n\n",anzf);
  printf("FILE *fout;\n\n");
  if(DIAGNOSIS) printf("unsigned int acc[%d];\n\n",anzf);
  printf("unsigned char partstr[] = { 128,129,130,131,0 };\n");
  printf("unsigned char fullstr[] = {\n  ");
  for(j=1;j<n2-1;j++) {
    nsp=0;
    for(i=1;i<n1-1;i++) {
      if(info[j*n1+i].nr>=0) {
        while(nsp) { printf("' ',"); nsp--; }
        printf("%d,",128+info[j*n1+i].nr);
      } else nsp++;
    }
    if(j<n2-2) {
      printf("'\\n',\n  ");
    } else {
      printf("0 };\n\n");
    }
  }
  printf("unsigned char letters[]=\"?ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ\";\n\n");
  
  printf("void ausgabe(TFeld *feld,unsigned char *ctrl)\n");
  printf("{ static unsigned char logs[16]={0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3};\n");
  printf("  int zp;\n");
  printf("  unsigned char zeile[%d];\n",(n1+3)*(n2-2)+1);
  printf("  unsigned int mask,log;\n");
  printf("  TFeld *fp;\n");
  printf("  unsigned char *octrl;\n\n");
  printf("  zp=0; octrl=ctrl;\n");
  printf("  while(*ctrl) {\n");
  printf("    if(*ctrl>=128) {\n");
  printf("      fp=&(feld[(*ctrl)-128]);\n");
  printf("      mask=fp->mask^((*((NODE *)(fp->wnode)))&(*((NODE *)(fp->snode))));\n");
  printf("      log=0;\n");
  printf("      if(mask&0xffff0000) { log=16; mask>>=16; }\n");
  printf("      if(mask&0xff00) { log+=8; mask>>=8; }\n");
  printf("      if(mask&0xf0) { log+=4; mask>>=4; }\n");
  printf("      log+=logs[mask];\n");
  printf("      zeile[zp++]=letters[log];\n");
  printf("    } else {\n");
  printf("      zeile[zp++]=*ctrl;\n");
  printf("    }\n");
  printf("    ctrl++;\n");
  printf("  }\n");
  printf("  zeile[zp++]='\\n';\n");
  printf("  zeile[zp]=0;\n");
  printf("  if(octrl==fullstr) {\n");
  printf("    fprintf(fout,\"%%s\\n\",zeile);\n");
  printf("  }\n");
  if(DIAGNOSIS) {
    printf("  for(zp=0;zp<%d;zp++) printf(\" %%d\",acc[zp]);\nputchar('\\n');\n",anzf);
//    printf("  printf(\"%%d %%d \",(acc+ctr/2)/ctr,ctr);\n");
  }
  printf("  printf((octrl==fullstr)?\"%%s\\n\":\"%%s\",zeile);\n");
  printf("}\n\n");

  printf("void doform()\n{ uint32 mask,maske; int log;");
  j=0;
  for(i=2;i<16;i++) {
    if(lenneeded[i]) {
      printf(j?",*dawg%d":" unsigned char *dawg%d",i);
      j++;
    }
  }
  printf(";\n");
  printf("  TFeld *feld;\n ");
  for(i=2;i<16;i++) {
    if(lenneeded[i]) {
      printf(" dawg%d=rdawg%d;",i,i);
    }
  }
  printf("\n  feld=afeld;\n");
  
  ctr=FREQ;
  mctr=0; lastp=0;
  for(j=1;j<n2-1;j++) {
    for(i=1;i<n1-1;i++) {
      if(info[j*n1+i].nr>=0) gibtext(i,j);
    }
  }
  printf("  ausgabe(feld,fullstr);\n  mask=feld[%d].mask; goto m%d;\n}\n\n",info[lastp].nr,mctr-1);
  
  printf("int main()\n{ int i;\n");
  for(i=2;i<16;i++) {
    if(lenneeded[i]) {
      printf("  MRDawg dawgobj%d(\"rdawg%d.pck2\");\n",i,i);
      printf("  rdawg%d=(unsigned char *)dawgobj%d.dawg;\n",i,i);
    }
  }
  for(i=0;i<sanf0;i++) {
    printf("  afeld[%d].wnode=(unsigned char *)dawgobj%d.firstnode;\n",info[anf[i]].nr,info[anf[i]].wlen);
  }
  for(;i<s;i++) {
    printf("  afeld[%d].smask=*(uint32 *)(afeld[%d].snode=(unsigned char *)dawgobj%d.firstnode);\n",info[anf[i]].nr,info[anf[i]].nr,info[anf[i]].slen);
  }
  if(CNTMETHOD==2) {
    printf("  for(i=0;i<8;i++) logtab[1<<i]=i<<2;\n");
  }
  if(DIAGNOSIS) {
    printf("  for(i=0;i<%d;i++) acc[i]=0;\n",anzf);
  }
  for(j=1;j<n2-1;j++) {
    for(i=1;i<n1-1;i++) {
      if((info[j*n1+i].nr>=0)&&(info[(j-1)*n1+i].nr<0)&&(info[j*n1+i].slen==0)) {
        printf("  afeld[%d].snode=(unsigned char *)dawgobj%d.firstnode;\n",info[j*n1+i].nr,info[j*n1+i].inwlen);
      }
    }
  }
  for(j=1;j<n2-1;j++) {
    for(i=1;i<n1-1;i++) {
      if((info[j*n1+i].nr>=0)&&(info[j*n1+i-1].nr<0)&&(info[j*n1+i].wlen==0)) {
        printf("  afeld[%d].wnode=(unsigned char *)dawgobj%d.firstnode;\n",info[j*n1+i].nr,info[j*n1+i].inslen);
      }
    }
  }
  printf("  if(fout=fopen(\"%s.res\",\"wb\")) {\n",argv[1]);
  printf("    doform();\n");
  printf("    fclose(fout);\n");
  printf("  }\n");
  printf("  return(0);\n}\n");
  return(0);
}

