!PRIMGEN: Generate const arrays for IMP/PASCAL PRIM + PERM
!         using PRIM.OBJ and PRIM.LIS
include  "INC:UTIL.IMP"
@16_3F00-192 routine          closeinput
@16_3F00-198 routine          closeoutput
begin 
constinteger  compiler=1, obj=2, list=3;  !input streams
constinteger  ignore=17 {words to ignore at outset},
              rts=16_4E75,
              sign16=-32768
integer  i,max,first,count,procs=0,total=0

constinteger  CODEBOUND=2000
shortarray  CODE(1:codebound)
constinteger  CHARBOUND=2000
bytearray  CHAR(0:charbound)
integer  CHARBASE,CHARLIM1,CHARLIM=1

recordformat  OBJINFO C 
  (short  FLAGS,TYPE,
   (short  LINK or  short  XTYPE or  short  SIZE or  short  ACT),
   byte  REG,MODE,
   integer  VAL)
recordformat  IDENTINFO C 
  ((short  FLAGS,TYPE,
   (short  LINK or  short  XTYPE or  short  SIZE or  short  ACT),
   byte  REG,MODE,
   integer  VAL or  record (objinfo) DETAILS),
   (short    TEXT,HLINK or  short  X,Y))
!M68000 addressing modes:-
constinteger  DREGMODE=0, AREGMODE=2_001000,
              INDMODE=2_010000, POSTMODE=2_011000, PREMODE=2_100000,
              DISPMODE=2_101000, INDEXMODE=2_110000, ABSMODE=2_111000,
              PCMODE=2_111010, LITMODE=2_111100
constinteger  INDIR=indmode-aregmode, POST=postmode-aregmode,
              PRE=premode-aregmode
!Additional source-related modes:
constinteger  LABMODE=2_10000000+pcmode,
              PROCMODE=2_11000000+pcmode,
              CONSTMODE=2_01000000+pcmode,
              FRAMEMODE=2_10000000+dispmode

constinteger  DICTMIN=41
constinteger  DICTBOUND=300
record (identinfo)array  DICT(0:dictbound)
integer  DLIM=0
record (identinfo)name  DP
!
integer  CURID=0,IDMAX=0
constinteger  IDBOUND=100
! IMP or PASCAL required names:-
string (15)array  IDENTS(1:idbound+idbound)
ownbytearray  OK(1:idbound)=0(*)

routine  READ CODE FILE
integer  i,j,k
  on  event  9 start 
    write(max,1);  printstring(" words of code read")
    newline
    return 
  finish 
  max = -ignore
  cycle 
    read symbol(j)
    read symbol(k)
    max = max+1
    code(max) = j<<8+k if  max > 0
  repeat 
end 

routine  REPORT(string (255) s)
integer  j=outstream
  select output(0)
  print line(s)
  select output(j)
end 

routine  LOCATE(string (255) s)
integer  j,k
on  event  9 start 
  report("*Premature end of program") if  s # "%endofprogram"
  select input(j)
  return 
finish 
  j = instream
  select input(compiler)
  cycle 
    read symbol(k);  printsymbol(k)
    if  k = charno(s,1) start 
      i = 1
      cycle 
        i = i+1
        if  i > length(s) start ;  !all matched
          read symbol(k) until  k = nl and  nextsymbol = nl;  !skip to blank line
          select input(j)
          return 
        finish 
        read symbol(k);  printsymbol(k)
      repeat  until  charno(s,i) # k
    finish 
    while  k # nl cycle 
      read symbol(k);  printsymbol(k)
    repeat 
  repeat 
end 

integer  SYM
routine  SKIP REST
  read symbol(sym) while  sym # nl
end 

routine  READ MARK
  read symbol(sym) until  sym > ' '
end 

routine  READ SEPARATOR
  read symbol(sym) until  sym = '|'
end 

routine  READ TYPE(shortname  t)
  skip symbol while  next symbol = ' '
  read(t)
end 

routine  READ DICT INFO
! Read through listing file to obtain DICT dump
!Dict info format: "___ident ..."
!                   ident | flags | type | link | cat | mode | value

constbytearray  catsym(0:15) =
  'I', 'C', 'B', 'E', '@', 'X', '6', '7',
  'S', 'A', 'Z', ':', 'R', 'F', '!', '?'

constbytearray  flagsym(0:15) =
  'W','R','V','A','w','r','o','m','S','T','K','?','P','p','E','*'

integer  i,j,k
record (identinfo)name  dp

routine  READ IDENT
!First char in SYM
integer  cl
  charlim1 = charlim;  charlim = charlim+1
  cycle 
    char(charlim) = sym;  charlim = charlim+1
    read symbol(sym)
  repeat  until  not  ('a' <= sym!32 <= 'z' or  '0' <= sym <= '9')
  char(charlim1) = charlim-charlim1-1
  return  unless  sym = ':';  !alias
  read symbol(sym)
  cl = charlim;  charlim = charlim+1
  cycle 
    char(charlim) = sym;  charlim = charlim+1
    read symbol(sym)
  repeat  until  not  ('a' <= sym!32 <= 'z' or  '0' <= sym <= '9')
  char(cl) = charlim-cl-1+128
end 

on  event  9 start 
  report("*Unexpected end of listing file reading DICT info")
  return 
finish 
  cycle 
    read mark
    exit  if  sym = '_' = nextsymbol
    skip rest
  repeat 
  skip rest
  cycle 
    read symbol(sym) until  sym > ' ' and  not  '0' <= sym <= '9'
    exit  if  sym # '|'
    dp == dict(dlim);  dp = 0
    read mark
    if  sym > '9' and  sym # '|' start ;  !"*anon*"
      read ident
      dp_text = charlim1
    finish 
    read symbol(sym) while  sym # '|'
    read symbol(sym)
    if  sym # ' ' start ;  !category
      i = 16
      i = i-1 until  i < 0 or  catsym(i) = sym
      if  i < 0 then  report("*Unknown category ".tostring(sym)) c 
      else  dp_flags = i
    finish 
    read mark
    while  sym # '|' cycle 
      i = 16
      i = i-1 until  i < 0 or  flagsym(i) = sym
      if  i < 0 start 
report("*Unknown flag sym ".tostring(sym)." for ".string(addr(char(dp_text))))
      else 
        dp_flags = dp_flags!1<<i
      finish 
      read mark
    repeat 
    read type(dp_type);  read separator
    read type(dp_link);  read separator
    read(dp_reg);  read separator
    read(dp_mode);  read separator
    read(dp_val)
    skip rest
    dlim = dlim+1
  repeat 
end 

routine  READ LIST INFO
! Required names introduced by '{'
! Map info format:  "routname"     | Code: n  Entry: m
integer  size=0,entry=0,i,j,k,first,curid,lastid,closed
string (31) s,t
routine  READ IDENT(string (31)name  s)
  closed = 0
  cycle 
    read symbol(sym)
    closed = 1 if  sym = '}'
  repeat  until  'a' <= sym!32 <= 'z' or  sym = '@'
  s = ""
  if  sym = '@' then  read symbol(sym) else  start 
    cycle 
      s = s.tostring(sym)
      read symbol(sym)
    repeat  until  not  ('a' <= sym!32 <= 'z' or  '0' <= sym <= '9')
  finish 
end 
predicate  FOUND
string (255)name  d
integer  i,l
  i = dict(curid)_text
  unless  0 <= i < charlim start 
    j = outstream
    select output(0)
    printstring("Text (");  write(i,0)
    printstring(") unsound for ");  write(curid,0)
    newline
    select output(j)
    false 
  finish 
  d == string(charbase+i)
  l = length(d)
  false  unless  l = length(t)
  for  i = 1,1,l cycle 
    false  if  charno(d,i)!32 # charno(t,i)!32
  repeat 
  d = t;  !take case from T *NB*
  true 
end 
on  event  9 start 
  report("*Unexpected end of listing file reading LIST info")
  return 
finish 
  first = 1;  lastid = dictmin-1
  cycle 
    cycle 
      read mark
      exit  if  sym = '"'
      if  sym # '?' and  sym # '*' start 
        read symbol(sym) until  (sym = '{' and  nextsymbol = '|') c 
                         or  sym < ' '
      finish  else  skip rest
      exit  if  sym = '{'
    repeat 
    if  sym = '{' start 
      read ident(s)
      if  s # "" start 
        if  first # 0 start 
          printstring("%constinteger ")
          first = 0
        else 
          printsymbol(',');  newline;  spaces(14)
        finish 
        for  i = 1,1,length(s) cycle 
          k = charno(s,i);  k = k-32 if  k >= 'a'
          printsymbol(k)
        repeat 
        printstring("=")
      finish 
      t = s
      read ident(t) if  closed = 0
      curid = lastid
      curid = curid+1 until  curid >= dlim or  found
      if  curid >= dlim start 
        report("*Unknown name ".t)
      else 
        lastid = curid
      finish 
      if  s # "" start 
        write(curid,0)
        first = 0
      finish 
      skip rest
    else 
      read symbol(sym)
      exit  if  sym < 'a'
      read ident(t)
      read mark
      if  sym = '|' start 
        procs = procs+1
        skip symbol while  not  '0' <= nextsymbol <= '9'
        read(j)
        skip symbol while  not  '0' <= nextsymbol <= '9'
        read(entry);  skip symbol
        entry = size+entry>>1
        size = size+j>>1
        if  curid < dlim start 
          dict(curid)_mode = absmode
          dict(curid)_val = (16_8000+total+1)<<16 + entry<<8 + size
        finish 
        total = total+size
        entry = 0;  size = 0
      finish 
    finish 
  repeat 
  newline
end ;  !read list info

ownstring (127) oldfile="",
                objfile="PRIM.MOB", lisfile="PRIM.LIS",
                newfile=""
  define param("Old compiler",oldfile,pamnodefault+paminfile)
  define param("Object file",objfile,paminfile)
  define param("Listing file",lisfile,paminfile)
  define param("New compiler",newfile,pamnewgroup)
  process parameters(cliparam)
  newfile = oldfile if  newfile = ""
  open output(1,newfile)
  select output(0)

  char(0) = 0
  charbase = addr(char(0))
  select input(obj)
  read code file
  select input(list)
  select output(1)
  locate("!* PRIMGEN marker 1");  newline
  read dict info
  reset input
  read list info
!
  locate("!* PRIMGEN marker 2");  newline
  printstring("%const%integer CMAX=");  write(charlim,0);  newline
  printstring("%const%byte%array CHARINIT(0:CMAX) = ")
  i = 0
  cycle 
    if  char(i) <= 32 or  char(i) >= 128 start 
      newline and  space if  char(i) <= 32;  write(char(i),1)
    else 
      printsymbol('''');  printsymbol(char(i));  printsymbol('''')
    finish 
    printsymbol(',')
    i = i+1
  repeat  until  i = charlim
  newline;  printsymbol('0');  newline
  
!** To use record array when available: present approach requires
!   different PUT WORD and PUT LONGWORD for Vax
routine  PUT WORD(integer  v)
short  k<-v
l: write(k,0)
end 
routine  PUT LONGWORD(integer  v)
  put word(v>>16)
  printsymbol(',')
  put word(v)
end 

  printstring("%constinteger PREMAX=");  write(dlim-1,0);  newline
  printstring("%const%short%array DICTINIT(")
  write(dictmin,0)
  printstring("*6:PREMAX*6+5) = ")
  i = dictmin
  cycle 
    dp == dict(i)
    newline;  space
    put word(dp_flags);  printsymbol(',')
    if  dp_text = 0 then  put word(¬dp_type) c 
    else  put word(dp_type);  printsymbol(',')
    put word(dp_link);  printsymbol(',')
    put word(dp_reg<<8+dp_mode);  printsymbol(',')
    put longword(dp_val)
    i = i+1
    exit  if  i >= dlim
    printsymbol(',')
  repeat 
  newline

  locate("!* PRIMGEN marker 3");  newline
  printstring("%const%short%array PRIMCODE(1:")
  write(total,0);  printstring(") <- ");  newline
  first = 1;  count = 0
  i = 1
  cycle 
    newline and  count = 0 if  count >= 8
    count = count+1
    count = 8 if  code(i) = rts
    printstring("16_");  phex4(code(i))
    i = i+1
    exit  if  i > total
    printsymbol(',')
  repeat 
  newline

  locate("%endofprogram")
  newline

  select output(0)
  write(total,1);  printstring(" words in")
  write(procs,1);  printstring(" procedures")
  newline
endofprogram