# masm-expd exand macros with gawk ( you need this program )
# optional: build inputfile for BBC-Basic-inline-assembler
# external variables: 
# 1. out=file  name of outputfile of masm-expd
# 2. basic     if =1 build outputfile for BBC-Basic-inline-assembler
# 3. bin=file  name of outputfile of BBC-Basic-inline-assembler 
# example for expand macros only:
# gawk -f <masm-expd$dir>.masm-expd1 -v out=outputfile inputfile 
# example for expand macros and build a basicfile 
# gawk -f <masm-expd$dir>.masm-expd1 -v out=basicfile -v basic=1 -v bin=binaryfile outputfile 

integer stackpointer;
integer true;
integer false;
integer labelcount;
integer maxlabelcount;
integer macrocount;
integer linenumber;

function init()
{
linenumber=5001;
asmlength="64*1024";
if (out=="") out="vdu:";
if (start=="") start="&8000";
true=1;
false=0;
labelcount=0;
maxlabelcount=0;
macrocount=0;
stackpointer=0;
if (basic==1)
   {
   if (bin=="") 
      {
      print "ERROR: if basic is selected, name of binaryfile must be specified";
      print "include -v bin=binaryfile in the commandline with call of gawk";
      exit;
      } 
   printf("%d REM begin of output-file of !masm-expd\n",linenumber++) > out;
   printf("%d ON ERROR  PRINT REPORT$,\" on line \",ERL,",linenumber++) >out;
   printf("\" of file %s\":OSCLI \"set asm$err true\":END \n",out) > out; 
   printf("%d REM LIBRARY \"<masm-expd$function>\"\n",linenumber++) > out;
   printf("%d codelen%  = %s \n",linenumber++,asmlength) > out;
   printf("%d DIM code% codelen%\n",linenumber++) > out;
   printf("%d FOR opt%=12 TO 15 STEP 3\n",linenumber++) > out;
   printf("%d P%=%s\n",linenumber++,start) > out;
   printf("%d O%=code%\n",linenumber++) > out;
   printf("%d L%=code%+codelen%\n",linenumber++) > out;
   printf("%d [ opt opt%\n",linenumber++) > out;
   }
} 

function lastfunk()
{
system("unset masm-expd$error");
system("set masm-expd$error false");
if (basic==1)
   {
   printf("%d  ]\n",linenumber++) > out;
   printf("%d NEXT opt%\n",linenumber++)  > out;
   printf("%d PRINT \"length of assemblerfile \"",linenumber++) > out;
   print (",O%-code%,\" Bytes\"") >out;
   printf("%d OSCLI \"Save %s \"+STR$~code%+",linenumber++,bin) > out;
   print "\" \"+STR$~O%" > out;
   printf("%d OSCLI \"*Settype %s absolute\"\n",linenumber++,bin)  > out;
   printf("%d END\n",linenumber++) > out;
   printf("%d REM end of output-file of !masm-expd \n",linenumber++) >out;
   }
}

function push(tostack)
    {
    stack[++stackpointer]=tostack;
    }

function pop()
    {
       return(stack[stackpointer--]);
    }

function macrodefine(file,macroname1,rest)
{
 integer tempk;
 integer templ;
 integer tempm;

    macrocount++;
    localcount[macroname1]=0;
    macrolist[macrocount]=macroname1;
    gsub(" ","",rest);
    argcount[macroname1]=split(rest,tempparts,",");
    for (tempk=1;tempk<=argcount[macroname1];tempk++)
       macroarguments[macroname1,tempk]=tempparts[tempk];
    macrolength[macroname1]=0;       
    do 
      {
      eofflag[file]=getline < file;
      if (toupper($1)=="LOCAL")
         {
         templ=split(substr($0,index($0,$2)),tempparts,",");
         for (tempk=1;tempk<=templ;tempk++)        
            localargs[macroname1,tempk+localcount[macroname1]]=tempparts[tempk];
         localcount[macroname1] += templ;
         }
      else if (toupper($1)!="ENDM")
         {
         macrolength[macroname1] +=1;       
         macrotext[macroname1,macrolength[macroname1]]=$0; 
         }
      if (eofflag[file]==0)
         {
         printf(" unexpected end of file in macro %s ",macroname1);
         printf(" where is ENDM ? ");
         exit;
         }
      } while (toupper($1)!="ENDM");
}

function checkline(macroname,string)
{
   integer printlineflag;
   integer tempi;

      argcount[""]=0;  
      printlineflag=true;
      for (tempi=1;tempi<=argcount[macroname];tempi++)
         gsub(macroarguments[macroname,tempi],target[tempi],string);
      for (tempi=1;tempi<=localcount[macroname];tempi++)
         {
         newlabel=sprintf("%s_%d",localargs[macroname,tempi],labelcount);
         gsub(localargs[macroname,tempi],newlabel,string);     
         }
      part[1]="";
      split(string,part);
      for (tempi=1;tempi<=macrocount;tempi++)
         {
         if ((part[1]==macrolist[tempi]) && (part[1]!=""))
            {
            macroexpand(part[1],substr(string,index(string,part[2])));
            printlineflag=false;
            break;
            }
         }
      if (printlineflag==true)
         {
         for (tempi=1;tempi<=macrocount;tempi++)
            {
            if ((part[2]==macrolist[tempi]) && (part[2]!=""))
               {
               if (basic==1)
                  {
                  printf("%d ",linenumber) > out;
                  linenumber++;
                  }
               printf("%s \n",part[1]) >out;
               macroexpand(part[2],substr(string,index(string,part[3])));
               printlineflag=false;
               break;
               }
            }
         }
      if (printlineflag==true)
         {
         if (basic==1)
            {
            if (toupper(part[1])=="IF")
               {
               printf("%d ]\n",linenumber  ) > out;
               printf("%d IF ",linenumber+1) > out;
               printf("%s THEN\n",substr(string,index(string,part[2]))) > out;
               printf("%d [ opt opt%\n",linenumber+2) > out;
               linenumber +=3;
               printlineflag=false;
               }
            else if (toupper(part[1])=="ELSE")
               {
               printf("%d ]\n",linenumber  ) > out;
               printf("%d ELSE\n",linenumber+1) > out;
               printf("%d [ opt opt%\n",linenumber+2) > out;
               linenumber +=3;
               printlineflag=false;
               }
            else if (toupper(part[1])=="ENDIF")
               {
               printf("%d ]\n",linenumber  ) > out;
               printf("%d ENDIF\n",linenumber+1) > out;
               printf("%d [ opt opt%\n",linenumber+2) > out;
               linenumber += 3;
               printlineflag=false;
               }
            printf("%d ",linenumber) > out;
            linenumber++;
            }
         if (printlineflag==true)
            printf("%s",string) > out ;
         printf("\n") >out ;
         }            
}

function macroexpand(macroname2,reststring)
{
   integer tempj;

    maxlabelcount++;
    labelcount=maxlabelcount;
    for (tempj=1;tempj<=macrolength[macroname2];tempj++)
       {
       push(labelcount);
       push(tempj);
       symbolcount=split(reststring,target,",");
       checkline(macroname2,macrotext[macroname2,tempj]);
       tempj=pop();
       labelcount=pop();
       }
}   

function readfile(file)
   {      
   do
      {
      eofflag[file]=getline < file;
      if (toupper($2)=="MACRO")
         macrodefine(file,$1,substr($0,index($0,$3)));
      else if (toupper($1)=="INCLUDE")
         readfile($2);
      else        
         checkline("",$0);
      } while (eofflag[file]!=0);
   }

BEGIN {init();readfile(ARGV[1]);lastfunk();exit;}

