$title ('ASM86 MAIN PROGRAM')
mainp:
do;
/*

        This is the main program of the CP/M 8086
        assembler. This module activates the i/o
        modules and goes through the source text
        in 3 passes. The module then for each source
        line calls the external subroutine DECODELINE
        to perform assembly of each line;
*/

/*

   modified  3/25/81  R. Silberstein
   modified  3/28/81  R. Silberstein
   modified  3/30/81  R. Silberstein
   modified  4/7/81   R. Silberstein
   modified  4/20/81  R. Silberstein
   modified  6/16/81  R. Silberstein
   modified  7/24/81  R. Silberstein
   modified  7/27/81  R. Silberstein
   modified  8/21/81  R. Silberstein

*/

$include (:f1:macro.lit)
$include (:f1:struc.lit)
$include (:f1:equals.lit)
$include (:f1:dev.lit)
$include (:f1:ermod.lit)
$include (:f1:subr2.ext)
$include (:f1:io.ext)
$include (:f1:files.ext)
$include (:f1:outp.ext)
$include (:f1:scan.ext)
$include (:f1:print.ext)
$include (:f1:symb.ext)
$include (:f1:ermod.ext)
$include (:f1:mglob.ext)
$include (:f1:text.ext)
$include (:f1:dline.ext)

DECLARE ASM86 LABEL PUBLIC;

closefiles: procedure;
  call close$source;
  call close$print;
  call close$symbol;
  call close$hex;
end closefiles;

open$output$files: procedure;
  CALL OPENPRINT;
  CALL OPENHEX;
  CALL OPENSYMBOL;
end open$output$files;

userbreak: proc byte;  /* test if keyboard break from user */
  if not constat then return false; /* test console status */
  if readconsole then;  /* skip first break key */
  do forever;
    call outtext(.usbreaktext); /* USER BREAK. OK (Y/N)? */
    i=upper(readconsole);
    call crlf;
    if i = yes then return true;
    if i = no then return false;
  end$forever;
end userbreak;

varinit: proc;
  CALL FILL (0, .PRINT$ON-.CIP, .CIP);
  errors=0;
  printswitchoff,includeon=false;
  IFLEVEL = 0;
  IFLIST = TRUE;
  csegtype=rcs;
end varinit;

pass0init: proc;  /* initialize pass 0 */
  simform=false;
  maxcol=119;
  if printdevice=console then maxcol=79;
  call symbinit;  /* initialize symbol table */
  print$on=false;
  call varinit;
end pass0init;

pass1init: proc;  /* initialize for pass 1 */
  call varinit;
end pass1init;

pass2init: proc;  /* initialize for pass 2 (last pass) */
  print$on=true;
  call varinit;
  call emitinit;
end pass2init;

pass0terminate: proc;  /* terminate pass 0 */
  call outtext(.pass0text);  /* End of pass 0 */
end pass0terminate;

pass1terminate: proc;  /* terminate pass 1 */
  print$on=false;      /* dummy */
  call outtext(.pass1text);  /* End of pass 1 */
end pass1terminate;

pass2terminate: proc;  /* terminate pass 2 (last pass) */
  DECLARE USEFACT BYTE;
  USEFACT = (FREEPT-.MEMORY) / ((ENDOFSYMBTAB-.MEMORY) / 100 + 1);
  errorprinted=false;
  call emitterminate;    /* terminate hex output module */
  call symbterminate;    /* print symbols */
  if printdevice <> console then call printterminate (USEFACT);
  CALL CLOSEFILES;
  call outtext(.endtext);  /* END OF ASSEMBLY... */
  call decout(errors,.help(0));  /* print no of errors */
  call outtext(.help(2));
  CALL OUTTEXT (.USEFACTOR);
  CALL DECOUT (USEFACT, .HELP(0));
  CALL OUTTEXT (.HELP(3));
  CALL WRITECONSOLE (25H);   /* % */
  CALL CRLF;
end pass2terminate;

include$close: proc (flag);
  declare flag byte;
  if eofset and include$on then$do
    call close$include;
    include$on,eofset=false;
    if flag then$do
      call scan;       /* skip EOF */
      call scan;       /* prepare for next source line */
    end$if;
  end$if;
end include$close;

ASM86:

call globalinit;      /* initialize some globals */

call outtext(.asm86text); /* CP/M 8086 ASSEMBLER.... */

if not filesetup then$do
  call outtext(.parerrtext);  /* PARAMETER ERROR */
  CALL SYSTEMRESET;
end$if;

CALL OPENSOURCE;

CALL OPENOUTPUTFILES;

pass=0ffh;
do while (pass:=pass+1) < 3;
  do case pass;
    call pass0init;    /* pass 0 */
    call pass1init;    /* pass 1 */
    call pass2init;    /* pass 2 */
  end$case;
  call scaninit;
  call scan;
  do while not eofset;
    if userbreak then$do
      eofset=true;
      pass=3;
    else$do
      errorprinted=false;
      call decodeline;
      call includeclose(false);  /* close include file if necessary */
      call scan;
      call includeclose(true);  /* close include file if necessary */
    end$if;
  end$while;
  do case pass;
    call pass0terminate;  /* pass 0 */
    call pass1terminate;  /* pass 1 */
    call pass2terminate;  /* pass 2 */
    do; end;              /* do nothing if userbreak */
  end$case;
end$while;

call system$reset;

end$module mainp;
