program AUTOCODER

  use ERROR_M, only: DO_ERROR, N_ERRORS
  use INPUT_M, only: INUNIT
  use IO_UNITS, only: INPUT, LIST, MACROS, OBJ, TAPE, U_ERROR, U_INPUT, &
    & U_LIST, U_MACROS, U_OBJ, U_SCRATCH, U_SCR2, U_TAPE
  use LITERALS_M, only: DUMP_LIT_TABLE, LONG_LITS
  use MACHINE, only: IO_ERROR, HP
  use PASS_1_M, only: PASS_1
  use PASS_2_M, only: PASS_2
  use PASS_3_M, only: BOOTLOADER, CORESIZE, INTERLEAVE, MAXLINE, NOTIN_1_80, &
    & PASS_3
  use SYMTAB_M, only: DUMP_SYMTAB
  use TRACES_M, only: TRACES

  implicit NONE

  character(127) :: ARG       ! Command line argument

  logical :: Do_List = .false.     ! Make a listing (turned on by -l)
  logical :: Do_Macros = .false.   ! Run a macro-processing pass
  logical :: Do_Object = .false.   ! Make an object "deck" (turned on by -o)
  logical :: Do_Tape = .false.     ! Make an object "tape" (turned on by -t)
  integer :: I                ! Subscript, loop inductor
  integer :: IOSTAT           ! I/O status
  logical :: NeedPass2        ! There are undefined ORG's or EQU's after pass 1
  integer :: PGLEN            ! Page Length (from -p option)
  logical :: SYMTAB           ! Dump the symbol table
  character(len=*), parameter :: &
    & Version = &
    & '1401 Autocoder (c) Van Snyder <van.snyder@jpl.nasa.gov> 2004 version 1.1'

  interleave = .false.
  inunit = -1
  notIn_1_80 = .true.
  symtab = .false.
  traces = ''

  i = hp
  do
    i = i + 1
    call getarg ( i, arg )
    if ( arg(1:1) /= '-' ) exit
    if ( arg(2:3) == 'a ' ) then
      notIn_1_80 = .false.
    else if ( arg(2:2) == 'b' ) then
      if (arg(3:) == '' ) then
        i = i + 1
        call getarg ( i, arg(3:) )
      end if
      bootLoader = adjustl(arg(3:))
      if ( bootLoader >= 'a' .and. bootLoader <= 'z' ) &
        & bootLoader = achar(iachar(bootLoader) + iachar('A') - iachar('a'))
      if ( bootLoader /= 'B' .and.  bootLoader /= 'I' .and. bootLoader /= 'N' .and. &
        & bootLoader /= 'V' ) then
        print *, 'Boot Loader (-b option) must be I or N or B or V; IX used'
        bootLoader = 'I'
        arg(4:4) = ' '
      end if
      if ( bootLoader == 'I' ) then
        select case ( arg(4:4) ) ! Core size flag
        case ( '1' )
          coreSize = 1400
        case ( '2' )
          coreSize = 2000
        case ( '4' )
          coreSize = 4000
        case ( '8' )
          coreSize = 8000
        case ( 'V', 'v' )
          coreSize = 12000
        case ( 'X', 'x' )
          coreSize = 16000
        case ( ' ' )
        case default
          print *, 'Invalid core size flag.  ', coreSize, ' used.'
        end select
      end if
    else if ( arg(2:3) == 'i ' ) then
      interleave = .true.
    else if ( arg(2:2) == 'l' ) then
      if ( arg(3:3) == ' ' ) then
        i = i + 1
        call getarg ( i, arg(3:) )
      end if
      do_list = .true.
      list = arg(3:)
      open ( u_list, file=list, form='formatted', access='sequential', &
        & iostat=iostat )
      if ( iostat /= 0 ) then
        call io_error ( 'While opening "listing" file', iostat, list )
        stop
      end if
    else if ( arg(2:3) == 'L ' ) then
      long_lits = .true.
    else if ( arg(2:2) == 'm' ) then
      if ( arg(3:3) == ' ' ) then
        i = i + 1
        call getarg ( i, arg(3:) )
      end if
      do_macros = .true.
      macros = arg(3:)
      open ( u_macros, file=macros, form='formatted', access='sequential', &
        & status='old', iostat=iostat )
      if ( iostat /= 0 ) then
        call io_error ( 'While opening "macro library" file', iostat, arg(3:) )
        stop
      end if
    else if ( arg(2:2) == 'o' ) then
      if ( arg(3:3) == ' ' ) then
        i = i + 1
        call getarg ( i, arg(3:) )
      end if
      do_object = .true.
      obj = arg(3:)
      open ( u_obj, file=obj, form='formatted', access='sequential', &
        & iostat=iostat )
      if ( iostat /= 0 ) then
        call io_error ( 'While opening "object deck" file', iostat, obj )
        stop
      end if
    else if ( arg(2:2) == 'p' ) then
      if ( arg(3:3) == ' ' ) then
        i = i + 1
        call getarg ( i, arg(3:) )
      end if
      read ( arg(3:), *, iostat=iostat ) pgLen
      if ( iostat == 0 ) then
        maxLine = pglen
      else
        call io_error ( 'While converting -p option', iostat )
        stop
      end if
    else if ( arg(2:3) == 's' ) then
      symtab = .true.
    else if ( arg(2:2) == 't' ) then
      if ( arg(3:3) == ' ' ) then
        i = i + 1
        call getarg ( i, arg(3:) )
      end if
      do_tape = .true.
      tape = arg(3:)
      open ( u_tape, file=tape, form='formatted', access='sequential', &
        & iostat=iostat )
      if ( iostat /= 0 ) then
        call io_error ( 'While opening "loadable tape" file', iostat, tape )
        stop
      end if
    else if ( arg(2:2) == 'T' ) then
      if ( arg(3:) == '' ) then
        i = i + 1
        call getarg ( i, arg(3:) )
      end if
      traces = arg(3:)
    else if ( arg(2:3) == 'V ' ) then
      print *, version
      stop
    else if ( arg(2:) == '' ) then
      exit
    else
      call getarg ( 0, arg )
      print *, 'Usage: ', trim(arg), ' [options] input-file'
      print *, ' Options: -h => Print this information'
      print *, '          -a => Code in 1..80 is OK'
      print *, '          -b[ ]X[#] => Select boot loader; X = I => IBM,'
      print *, '             X = N => None,'
      print *, '             X = B => Van''s favorite 1-card boot/no clear,'
      print *, '             X = V => Van''s favorite 2-card boot/clear,'
      print *, '             If X = i, # is the core size selector: 1 => 1400,'
      print *, '               2 => 2000, 4 => 4000, 8 => 8000, v => 12000,'
      print *, '               x => 16000.  Default ', coreSize
      print *, '          -i => Interleave object deck into listing ', &
        &                       '(needs -o and -l)'
      print *, '          -l[ ]file => Listing file'
      print *, '          -L => Store long literals once (unlike "real" Autocoder)'
      print *, '          -m[ ]file => Macro library file'
      print *, '          -o[ ]file => Object "deck" file'
      print *, '          -p[ ]# => Page length in lines'
      print *, '          -s => Dump the symbol and literal tables (debug)'
      print *, '          -t[ ]file => Loadable "tape" file'
      print *, '          -T[ ]letters => Trace, depending on letters'
      print *, '               l => Lexer, p => Parser, P => PROCESS_LTORG'
      print *, '          -V => Print version info and stop'
      print *, version
      stop
    end if
  end do

  if ( arg(1:1) /= '-' .and. arg /= '' ) then
    inunit = u_input
    input = arg
    open ( u_input, file=input, form='formatted', access='sequential', &
      & status='old', iostat=iostat )
    if ( iostat /= 0 ) then
      call io_error ( 'While opening input file', iostat, input )
      stop
    end if
  end if

! open ( u_scratch, form='unformatted', access='sequential', &
!   & status='scratch' )
  open ( u_scratch, form='formatted', access='sequential', &
    & file='scratch' )

  do
    n_errors = 0
    if ( do_macros ) then
      u_error = u_scr2
    ! call macro_pass
      inunit = u_scr2
    end if
    u_error = u_scratch
    call pass_1 ( iostat, needPass2 )
    u_error = -1
    if ( do_list ) u_error = u_list
    if ( symtab ) then
      call dump_symtab ( heading='After pass 1:' )
      call dump_lit_table ( -1 )
    end if
    if ( iostat /= 0 ) exit
    call pass_2 ! Resolve forward EQU, ORG and LTORG references
    if ( symtab ) then
      call dump_symtab ( heading='After pass 2:' )
      call dump_lit_table ( -1 )
    end if
    call pass_3 ( do_list, do_object, do_tape )
    if ( n_errors > 0 ) then
      write ( arg(1:5), '(i5)' ) n_errors
      call do_error ( arg(1:5) // ' Errors' )
    end if
  end do

end program AUTOCODER
