
/*    Dougs macro assembler pre processor   */

#define  VERSION	"2.22"

#include "stdio.h"
#include "string.h"
#include "ctype.h"

   FILE *in, *out;
   char work[132], *wk, *wkend;
   char work1[132], *wk10, *wk11, *wk12, *wk13;
   char work2[10];
   char text[132];
   int labcnt, linecnt, errcnt;

main(argc,argv)
int argc;
char *argv[];

{

/*******************************/
/*  Give the logo to the user  */
/*******************************/

   printf("\nDoug's Programming Language -- DPL, Version %s\n",VERSION);
   printf("Copyright (c) 1988 Douglas S. Cody, All rights reserved.\n");

/********************************/
/* fetch the file name from     */
/* the command line/operator    */
/********************************/

   if(argc!=2) {
     /* prompt the operator for a file name */
     printf ("\nENTER THE FILE NAME [.D]  ");
     gets (work);
    }
   else {
      strcpy (work,argv[1]);
    }
   if(strstr(work,".") == NULL) {
      strcpy (work1,work);
      strcat (work1,".asm");
      strcat (work,".d");
   }
   else {
      strcpy(work1,work);
      strcpy(work1,(strtok(work1,".")));
      strcat(work1,".asm");
    }

/********************************/
/*      open the text file      */
/********************************/

   if ((in = fopen (work,"rt"))==NULL) {
      printf("\nCAN'T OPEN INPUT FILE\n");
      exit (1);
    }
    if ((out = fopen (work1,"w"))==NULL) {
      printf("\nCAN'T OPEN OUTPUT FILE\n");
      exit (1);
     }

   printf("\nCOMPILING %s\n",work);
   fputs ("\tINCLUDE\tDPL.MAC\n",out);

/************************************/
/* process the contents of the file */
/************************************/

   labcnt  = 0;    /* clear the label count          */
   linecnt = 0;    /* clear the input line count     */
   errcnt  = 0;    /* clear the DOS ERRORLEVEL count */

   get_string();

   while (!feof(in)) {
      compile();
      get_string();
    }
    fclose(in);
    exit (errcnt);

}

/****************************************************************************/
/*                         1st level routines                               */
/****************************************************************************/


/*******************************/
/*    compile the code         */
/*******************************/

compile() {

   strcpy (work1,work);
   strtok (work1,"\n");
   wk10 = strtok(work1,"\t ");             /* point to the first token */

   if (strcmp(wk10,"CALL") == 0) {
      perform_call();
      return(255);
    }

   if (strcmp(wk10,"IF") == 0) {
      perform_if();
      return(255);
    }

   if (strcmp(wk10,"RECORD") == 0) {
      perform_rec();
      return(255);
    }

   wk11 = strtok('\0',"\t ");

   if (strcmp(wk11,"=") == 0) {
      perform_arith();
      return(255);
    }

   if (strcmp(wk11,"$=") == 0) {
      perform_scat();
      return(255);
    }

   fputs (work,out);
   return(0);
}

/****************************/
/*   fetch a string from    */
/*   the input file         */
/****************************/

get_string() {
      fgets (text, 132, in);
      linecnt++;
      strcpy (work,text);
}

/****************************************************************************/
/*                         2nd level routines                               */
/****************************************************************************/

/********************************/
/*    parse the MATH statment   */
/********************************/

perform_arith() {

    fputs ("\t@LOAD\t",out);
    fputs (strtok('\0',"\t "),out);
    fputs ("\n",out);

    wk11 = strtok('\0',"\t ");

    while (wk11 && (wk11 != (strchr(wk11,59)))) {
       if (strcmp(wk11,"+") == 0) strcpy (work2,"\t@ADD\t");
       else if (strcmp(wk11,"-") == 0) strcpy (work2, "\t@SUB\t");
       else if (strcmp(wk11,"*") == 0) strcpy (work2, "\t@MULT\t");
       else if (strcmp(wk11,"/") == 0) strcpy (work2, "\t@DIV\t");
       else if (strcmp(wk11,">>") == 0) strcpy (work2,"\t@SHR\t");
       else if (strcmp(wk11,"<<") == 0) strcpy (work2,"\t@SHL\t");
       else if (strcmp(wk11,"AND") == 0) strcpy (work2,"\t@AND\t");
       else if (strcmp(wk11,"OR") == 0) strcpy (work2,"\t@OR\t");
       else if (strcmp(wk11,"XOR") == 0) strcpy (work2,"\t@XOR\t");
       else if (strcmp(wk11,"MOD") == 0) strcpy (work2,"\t@MOD\t");
       else give_err ("ERROR -- incorrect math operator");

       fputs(work2,out);
       fputs(strtok('\0',"\t "),out);
       fputs ("\n",out);

       wk11 = strtok('\0',"\t ");
     }

    fputs("\t@STOR\t",out);
    fputs(wk10,out);
    fputs ("\n",out);

}

/*******************************/
/*   parse the CALL statement  */
/*******************************/

perform_call() {
   wk11 =  strtok('\0',"\t ");

   if (strcmp(wk11,"DWORD") && strcmp(wk11,"WORD")
      && strcmp(wk11,"FAR") && strcmp(wk11,"NEAR"))
   {
      wk12 = strtok('\0',"\t ");
      if (wk12 && *wk12!=';') {
         fputs ("\tMOV\tAX,",out);
         if (!isdigit(*wk12)) fputs ("OFFSET ",out);
         fputs (wk12,out);
         fputs ("\n",out);

         wk12 = strtok('\0',"\t ");
         if (wk12 && *wk12!=';') {
            fputs ("\tMOV\tBX,",out);
            if (!isdigit(*wk12)) fputs ("OFFSET ",out);
            fputs (wk12,out);
            fputs ("\n",out);

            wk12 = strtok('\0',"\t ");
            if (wk12 && *wk12!=';') {
               fputs ("\tMOV\tCX,",out);
               if (!isdigit(*wk12)) fputs ("OFFSET ",out);
               fputs (wk12,out);
               fputs ("\n",out);

               wk12 = strtok('\0',"\t ");
               if (wk12 && *wk12!=';') {
                  fputs ("\tMOV\tDX,",out);
                  if (!isdigit(*wk12)) fputs ("OFFSET ",out);
                  fputs (wk12,out);
                  fputs ("\n",out);
               }
            }
         }
      }
      fputs ("\tCALL\t",out);
      fputs (wk11,out);
      fputs ("\n",out);
   }

   else {
      fputs ("\tCALL\t",out);
      do {
	 fputs (wk11,out);
         fputs (" ",out);
	 wk11 = strtok('\0',"\t ");
      } while (wk11);
      fputs ("\n",out);
   }

}

/*******************************/
/*    parse the IF statement   */
/*******************************/

perform_if() {
   wk11 = strtok('\0',"\t ");
   if (strcmp(wk11,"BYTE") == 0) do_ifn ("AL","BYTE");
   else if (strcmp(wk11,"CHAR") == 0) do_ifn ("AL","BYTE");
   else if (strcmp(wk11,"INT")  == 0) do_ifn ("AX","WORD");
   else if (strcmp(wk11,"WORD") == 0) do_ifn ("AX","WORD");
   else if (strcmp(wk11,"STRING") == 0) do_ifs();
   else give_err ("ERROR -- No BYTE/WORD/STRING operator given");

}

/***********************************/
/*    parse the RECORD statement   */
/***********************************/

perform_rec() {
   fputs ("REC\t",out);
   fputs ((strtok('\0',",")),out);
   fputs (",",out);
   fputs ((strtok('\0'," ")),out);
   fputs ("\n",out);
}

/***************************************/
/*    parse the string concatenation   */
/***************************************/

perform_scat() {
   wk11 = strtok('\0',"\t ");
   if (strcmp(wk10,wk11) == 0) {
      fputs ("\t@SCATSME\t",out);
      fputs (wk11,out);
      fputs ("\n",out);
    }
   else {
      fputs ("\t@SMOV\t",out);
      fputs (wk10,out);
      fputs ("\n",out);
      fputs ("\t@SCNCT\t",out);
      fputs (wk11,out);
      fputs ("\n",out);
    }

   do {
     wk11 = strtok('\0',"\t ");
      if (wk11 && (strcmp(wk11,"+") == 0)) {
         wk11 = strtok('\0',"\t ");
         fputs ("\t@SCNCT\t",out);
         fputs (wk11,out);
         fputs ("\n",out);
       }
    } while (wk11 && (wk11 != (strchr(wk11,59))));

}

/****************************************************************************/
/*                         3rd level routines                               */
/****************************************************************************/

/************************************/
/*     parse the IF xxx statement   */
/************************************/

do_ifs() {
   fputs ("\t@IFSTR\n",out);

   fputs ("\tMOV\tSI,OFFSET ",out);
   fputs (strtok('\0',"\t "),out);
   fputs ("\n",out);

   wk12 = strtok('\0',"\t ");

   fputs ("\tMOV\tDI,OFFSET ",out);
   fputs (strtok('\0',"\t "),out);
   fputs ("\n",out);

   if (strcmp(wk12,"EQ") == 0) fputs ("\tCALL\t_IFSEQ\n",out);
      else if (strcmp(wk12,"NE") == 0) fputs ("\tCALL\t_IFSNE\n",out);
         else fputs ("\tCALL\n",out);

   itoa(labcnt++,work2,10);
   fputs ("\tJNC\t@@@XXX",out);
   fputs (work2,out);
   fputs ("\n",out);

   do_true();

   fputs ("@@@XXX",out);
   fputs (work2,out);
   fputs (":\n",out);

}

/************************************/
/*   parse the IF xxxxx statement   */
/************************************/

do_ifn(reg,siz)
  char *reg, *siz;

{
   fputs ("\tMOV\t",out);
   fputs (reg,out);
   fputs (",",out);
   fputs (siz,out);
   fputs (" PTR ",out);
   fputs (strtok('\0',"\t "),out);
   fputs ("\n",out);

   wk12 = strtok('\0',"\t ");

   fputs ("\tCMP\t",out);
   fputs (reg,out);
   fputs (",",out);
   fputs (siz,out);
   fputs (" PTR ",out);
   fputs (strtok('\0',"\t "),out);
   fputs ("\n",out);

   if (strcmp(wk12,"LT") == 0) strcpy(work2,"\tJGE\t");
   else if (strcmp(wk12,"LE") == 0) strcpy (work2,"\tJG\t");
   else if (strcmp(wk12,"EQ") == 0) strcpy (work2,"\tJNE\t");
   else if (strcmp(wk12,"GE") == 0) strcpy (work2,"\tJL\t");
   else if (strcmp(wk12,"GT") == 0) strcpy (work2,"\tJLE\t");
   else if (strcmp(wk12,"NE") == 0) strcpy (work2,"\tJE\t");
   else give_err ("ERROR -- incorrect comparison operator");

   fputs (work2,out);

   itoa(labcnt++,work2,10);
   fputs ("@@@XXX",out);
   fputs (work2,out);
   fputs ("\n",out);

   do_true();

   fputs ("@@@XXX",out);
   fputs (work2,out);
   fputs (":\n",out);

}

/****************************************************************************/
/*                         4th level routines                               */
/****************************************************************************/

/*********************************/
/* do_true PARSE of if statement */
/*********************************/

do_true() {
    wk13 = strtok('\0',"\t ");
    if (strcmp(wk13,"GOTO") == 0) {
       fputs ("\tGOTO\t",out);
       fputs (strtok('\0',"\t "),out);
       fputs ("\n",out);
     }
    else if (strcmp(wk13,"RETURN") == 0) fputs("\tRETURN\n",out);
    else if (strcmp(wk13,"CALL") == 0) perform_call();
    else give_err ("ERROR -- Missing GOTO/CALL/RETURN in 'IF' statement");

}

/****************************************************************************/
/*                       Bottom level routines                              */
/****************************************************************************/

give_err(str)
char *str;
{
    printf ("%s\n",str);
    printf ("\tline #%d: %s\n",linecnt,text);
    errcnt++;

}
