/*  fd2lib  by Volker Barthelmann   */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXLEN 1000

#define check if(*p==0){printf("Parse error(0)\n");exit(EXIT_FAILURE);}

char *regnames[]={"a0","a1","a2","a3","a4","a5","a6","a7",
                  "d0","d1","d2","d3","d4","d5","d6","d7"};

#define SMALLCODE 1
#define SMALLDATA 2

char *varargs[]={
#include "vargs.h"
0,0
};

void ProcessFD(char *name,int mode)
{
    FILE *fd,*out,*lvos;
    int offset=0,public=0,i,j,count,savecount;
    char function[MAXLEN],ff[MAXLEN+8],base[MAXLEN],line[MAXLEN];
    char lvoname[MAXLEN],*p,*k,*functionp;
    int reg[16],loops;
    *function=*base=*line=0;
    fd=fopen(name,"r");
    if(!fd){printf("Could not open <%s>\n",name);exit(EXIT_FAILURE);}
    k=name;
    if(p=strrchr(k,'/')) k=p+1;
    if(p=strrchr(k,':')) k=p+1;
    sprintf(lvoname,"T:%s_LVO.s",k);
    lvos=fopen(lvoname,"w");
    if(!lvos){printf("Could not create <%s>\n",lvoname);exit(EXIT_FAILURE);}
    while(1){
        if(!fgets(line,MAXLEN-1,fd)){printf("File error\n");exit(EXIT_FAILURE);}
        if(*line=='*') continue;
        if(!strncmp(line,"##base",6)){
            p=line+6;while(isspace(*p)) p++;
            k=base;while(isgraph(*p)) *k++=*p++;
            *k=0;continue;
        }
        if(!strncmp(line,"##bias",6)){
            p=line+6;while(isspace(*p)) p++;
            sscanf(p,"%i",&offset);continue;
        }
        if(!strncmp(line,"##public",8)){
            public=1;continue;
        }
        if(!strncmp(line,"##private",9)){
            public=0;continue;
        }
        if(!strncmp(line,"##end",5)) return;
        if(!public) {offset+=6;continue;}
        functionp=function;
        for(loops=0;loops<=1;loops++){
            p=line;k=functionp;
            while(isspace(*p)) p++;
            if(loops==0){
                while(*p!='('&&*p!=0) *k++=*p++;
                check
                *k=0;
                fprintf(lvos,"_LVO%s\tequ\t-%d\n\txdef\t_LVO%s\n",functionp,offset,functionp);
            }else{
                while(*p!='('&&*p!=0) p++;
                check;
            }
/*            printf("function=%s, loops=%d\n",functionp,loops);*/
            count=savecount=0;
            strcpy(ff,"T:");
            strcat(ff,functionp);strcat(ff,".s");
            out=fopen(ff,"w");
            if(!out){printf("Could not create <%s>\n",functionp);exit(EXIT_FAILURE);}
            if(mode&SMALLDATA) fprintf(out,"\tnear\ta4,-2\n");
            if(mode&SMALLCODE) fprintf(out,"\tnear\tcode\n");
            if(*base) fprintf(out,"\txref\t%s\n",base);
            fprintf(out,"\txdef\t_%s\n",functionp);
            fprintf(out,"\tsection\t\"CODE\",code\n_%s\n",functionp);
            for(i=0;i<16;i++) reg[i]=0;
            while(*p!=')'&&*p!=0) p++;
            check
            p++;
            while(*p!='('&&*p!=0) p++;
            check
            p++;
            while(*p!=')'&&*p!=0){
                if((*p!='a'&&*p!='A'&&*p!='d'&&*p!='D')||p[1]<'0'||p[1]>'7')
                    {printf("Parse error(1)\n");exit(EXIT_FAILURE);}
                if(*p=='a') j=p[1]-'0';
                    else    j=p[1]-'0'+8;
                reg[j]=++count;if(j!=0&&j!=1&&j!=8&&j!=9&&j!=6) savecount++;
                p+=2;
                while(isspace(*p)&&*p!=0) p++;
                if(*p=='/'||*p==',') p++;
                else if(*p!=')'){printf("Parse error(2)\n");exit(EXIT_FAILURE);}
                while(isspace(*p)&&*p!=0) p++;
                check
            }
            if(savecount==0) fprintf(out,"\tmove.l\ta6,-(a7)\n");
            else{
                fprintf(out,"\tmovem.l\ta6");
                for(i=0;i<16;i++){
                    if(reg[i]&&i!=0&&i!=1&&i!=8&&i!=9&&i!=6) fprintf(out,"/%s",regnames[i]);
                    if(reg[i]&&(i==6/*||((mode&SMALLDATA)&&i==4)*/))
                        printf("WARNING: register conflict in %s!\n",functionp);
                }
                fprintf(out,",-(a7)\n");
            }
            for(j=1;j<=count;j++)
                for(i=0;i<16;i++)
                    if(reg[i]==j)
                        if(i>=15||reg[i+1]!=j+1||(loops==1&&j>=count-1)){
                            if(loops==0||j<count)
                                fprintf(out,"\tmove.l\t%d(a7),%s\n",4*(savecount+j+1),regnames[i]);
                            else
                                fprintf(out,"\tlea\t%d(a7),%s\n",4*(savecount+j+1),regnames[i]);
                        }else{
                            fprintf(out,"\tmovem.l\t%d(a7),%s",4*(savecount+j+1),regnames[i]);
                            while(i<15&&reg[i+1]==j+1&&(loops==0||j<count-1)){
                                i++;j++;
                                fprintf(out,"/%s",regnames[i]);
                            }
                            fprintf(out,"\n");
                        }

            if(*base){
                fprintf(out,"\tmove.l\t%s",base);
                if(mode&SMALLDATA) fprintf(out,"(a4)");
                fprintf(out,",a6\n");
            }
            fprintf(out,"\tjsr\t-%d(a6)\n",offset);
            if(savecount==0) fprintf(out,"\tmove.l\t(a7)+,a6");
                else     fprintf(out,"\tmovem.l\t(a7)+,a6");
            for(i=0;i<16;i++)
                if(reg[i]&&i!=0&&i!=1&&i!=8&&i!=9&&i!=6) fprintf(out,"/%s",regnames[i]);
            fprintf(out,"\n\trts\n");
            fclose(out);
            if(loops!=0) break;
            p=varargs[0];loops=3;i=0;
/*            printf("searching %s\n",functionp);*/
            while(p){
/*                printf("  %s\n",p);*/
                if(!strcmp(p,functionp)){
/*                    printf("found\n");*/
                    functionp=varargs[i+1];
                    loops=0;break;
                }
                i+=2;p=varargs[i];
            }
        }
        offset+=6;
    }
    fclose(fd);
    fclose(lvos);
}


int main(int argc,char **argv)
{
    int i,mode=0;
    for(i=1;i<argc;i++){
        if(!strcmp(argv[i],"-sc")) mode|=SMALLCODE;
        if(!strcmp(argv[i],"-sd")) mode|=SMALLDATA;
    }
    for(i=1;i<argc;i++)
        if(argv[i][0]!='-') ProcessFD(argv[i],mode);
}
