// BLDRFINISH.BCPL
//  Taft, November 13, 1981  2:56 PM
//  Swinehart, May 23, 1977  5:53 PM
// Copyright Xerox Corporation 1979, 1981

get "BLDR.DECL"
 
let FinishBldr() be
 [
 ENDBINFILE()
 ENDSAVEFILE()

  if MAPSW do WriteSyms()

 //
FOO.RUN 45321b wds of code--24 undefs--56 warnings--34 errors
 BeginReport(false)
 PutTemplate(ESTREAM,"$S $6UOb wds of code",
	SFILENAME,SFILE>>BFile.maxCodeLoc-CODESTART)

  PRINTLISTINGS()

  if WARNINGSW & (WARNINGCOUNT ne 0) then
    PutTemplate(ESTREAM,"--$D warning$S",WARNINGCOUNT,
	 WARNINGCOUNT eq 1? "","s")
  if ERRORCOUNT then
    PutTemplate(ESTREAM,"--$D error$S",ERRORCOUNT,
	 ERRORCOUNT eq 1? "","s")
 Puts(ESTREAM,$*N)
 EndReport()
 if LSTREAM ne dsp do Closes(LSTREAM) // will truncate
 ]
	
and ENDSAVEFILE() be
   [ // write the common and static images
   
   let endFa = vec lFA
   GetCurrentFa(SSTREAM,endFa)
   
   // Write static links
   JumpToFa(SSTREAM,staticLinksFa)
   for i = 0 to KSTATICCOUNT-1 do Puts(SSTREAM,CODE!i>>SYm.staticAddress)
   
   if not BBINSAVESW then GetCurrentFa(SSTREAM, endFa)
	
   Zero(CODE,STATICMAX-STATICSTART) // MAKE SURE IT FITS!!!!
   for I = 1 to SYMTAB!0 do
	[
	let sym = SYMTAB!I
	if sym>>SYm.jOnly loop
	let ADDR = sym>>SYm.staticAddress
	if INITSWAPSW eq 2 & sym>>SYm.initSwappedOut then
		sym>>SYm.initialValue = SWAPPEDOUTSYM>>SYm.initialValue
	let VALUE = sym>>SYm.initialValue
	test sym>>SYm.z
		then test VALUE & not BETWEEN(ADDR,#50,#400)
			ifso OUTWARNING(sym)
			ifnot ZCODE!ADDR = VALUE
		or test VALUE & not BETWEEN(ADDR,STATICSTART,STATICMAX)
			ifso OUTWARNING(sym)
			ifnot CODE!(ADDR - STATICSTART) = VALUE
	]
   
   STATICLOC = Umax(STATICLOC, JSTATICMAX) // ****
   
   if Usc(STATICLOC , STATICMAX) ge 0 do
   	WARNING("Not enough static space was reserved")
   
   // Kludge to maintain compatibility with sifted format, which requires the
   //   statics to come first, hence requiring BLDR to assume the actual length
   //   of the statics before it can write out any code
   let realStaticLoc = STATICLOC
   STATICLOC=STATICMAX-1
   
   PARAMLIST>>BLV.startOfStatics = STATICSTART
   PARAMLIST>>BLV.endOfStatics = STATICLOC
   PARAMLIST>>BLV.startOfCode = SFILE>>BFile.codeLoc + 1
   PARAMLIST>>BLV.afterLastCodeWord = SFILE>>BFile.maxCodeLoc
   PARAMLIST>>BLV.endCode = SFILE>>BFile.rFileCodeLoc
   PARAMLIST>>BLV.relPairTable = SRELPAIRLOC
   
   
   if COMMONLOC ge COMMONMAX do WARNING("Not enough common space")
   Resets(SSTREAM) // back to word 0
   Puts(SSTREAM,PARAMLIST>>BLV.startOfCode) // initial value for PC
   Puts(SSTREAM,SFILE>>BFile.pageLength) // Length of .RUN File in pages (less BBs)
   Puts(SSTREAM,0) //  type
   Puts(SSTREAM,KSTATICCOUNT)
   Zero(BHEAD,#15-#4+1)
   WriteBlock(SSTREAM,BHEAD,#15-#4+1)
   WriteBlock(SSTREAM,PARAMLIST,#40)
   WriteBlock(SSTREAM,ZCODE,#300)
   WriteBlock(SSTREAM,CODE,STATICLOC-STATICSTART+1)
   JumpToFa(SSTREAM, endFa)
   
   Closes(SSTREAM)
   
   for I=#300 to #377 do if ZCODE!I ne 0 then
	[
	let xcNum = SFILENUM+1 // they are created contiguous
	let xcStream = Openfile(xcNum, ksTypeWriteOnly, wordItem)
	PutTemplate(LSTREAM,
	    "*NWriting locations #300-#377 on $S", fileNameVec!xcNum)
	WriteBlock(xcStream, ZCODE+#300, #100) // *****
	Closes(xcStream)
	break
	]
   
   PutTemplate(LSTREAM,"*NCOMMON *T$6UO*T$6UO*NSTATICS*T$6UO*T$6UO*N*N",
	COMMONSTART, COMMONLOC, STATICSTART, realStaticLoc)
   ]


and WriteSyms() be
[
  MHEAD!0 = verSyms

  let symStream = Openfile(MFILENUM,ksTypeWriteOnly,wordItem)
  WriteBlock(symStream,MHEAD,MHEADLENGTH)

  MHEAD!2 = MHEADLENGTH
  Puts(symStream,0)

  let SLENGTH = 1
  for i = 0 to DICTHEADLENGTH-1 do
   [ // not the same order as before!
   let d = DICT!i
   while d do
	[
	let name = lv d>>DIct.name
	let lN = name>>STRING.length/2+1
	d>>DIct.mFileOffset = SLENGTH
	WriteBlock(symStream,name,lN)
	SLENGTH = SLENGTH + lN
	d = @d
	]
   ]

  MHEAD!3 = CURBOPOS(symStream)
  Puts(symStream,SYMTAB!0)
  for i = 1 to SYMTAB!0 do
	[ let sym = SYMTAB!i
	if sym>>SYm.jOnly loop
	Puts(symStream,sym>>SYm.dictEntry>>DIct.mFileOffset)
	let T = sym>>SYm.type lshift 11
	if sym>>SYm.local then T = T + #2000
	if sym>>SYm.relocatable then T = T + #1000
	T = T + sym>>SYm.rFile>>RFile.rFileId
	Puts(symStream,T)
	Puts(symStream,sym>>SYm.staticAddress)
	Puts(symStream,sym>>SYm.initialValue)
	]

  for code = RFILECODE to BFILECODE do
	[ // record RFile, BFile information in symbol file
	MHEAD!(4+(code-RFILECODE)) = CURBOPOS(symStream)
	Puts(symStream, code eq RFILECODE? rFileCount, bFileCount)
	let nextFile = @eventList
	while nextFile do
		[ let file = nextFile; nextFile = @nextFile
		unless file>>RFile.useCode eq code loop
		let d = fileNameVec!(file>>RFile.fileNum) - offsetDIctName
		Puts(symStream,d>>DIct.mFileOffset)
		WriteBlock(symStream,lv file>>RFile.bFileId, 3)
		]
	]

  MHEAD!1 = CURBOPOS(symStream)
  let endFa = vec lFA; GetCurrentFa(symStream,endFa)
  Resets(symStream)
  WriteBlock(symStream,MHEAD,MHEADLENGTH)
  Puts(symStream,SLENGTH)

  JumpToFa(symStream,endFa)
  Closes(symStream)
]

and PRINTLISTINGS() be
	[
	FIRSTSYM = 1
	LASTSYM  = SYMTAB!0
	let UNDEFCOUNT = PRINTUNDEFINED()
	if UNDEFCOUNT then
	    PutTemplate(ESTREAM,"--$D undef$S",UNDEFCOUNT,UNDEFCOUNT eq 1?"","s")
	if LISTVARSW do [ Puts(LSTREAM,#14); PRINTVARS() ]
	if LISTNUMSW do [ Puts(LSTREAM,#14); PRINTNUMERIC() ]
	]

and PRINTUNDEFINED() = valof
  [ 
  let undefCt = 0
  let firstRefSym = -1
  for i = FIRSTSYM to LASTSYM do [
    let sym = SYMTAB!i
    if sym>>SYm.type eq 0 & sym>>SYm.jOnly eq 0 then [
	if undefCt eq 0 do  Wss(LSTREAM,"*NUndefined names*N")
	if sym ne firstRefSym then
	   PutTemplate(LSTREAM,"    first referenced in $S:*N",NameOfRfile(sym))
	firstRefSym = sym
	PRINTSYM(sym)
	undefCt = undefCt + 1
	]
    ]
  resultis undefCt
  ]

and PRINTVARS() be
[
let rFile = @eventList
while rFile do
    [
    if rFile>>RFile.useCode eq RFILECODE then
      [
      Wss(LSTREAM,fileNameVec!(rFile>>RFile.fileNum)); Puts(LSTREAM,$*N)
      for i = FIRSTSYM to LASTSYM do
	[
	let sym = SYMTAB!i
	unless sym>>SYm.jOnly %  sym>>SYm.rFile ne rFile % sym>>SYm.type ne 1 do
		PRINTSYM(sym)
	]
       ]
    rFile = @rFile
    ]
]

and PRINTNUMERIC() be
[
let sym = nil
for i = FIRSTSYM to LASTSYM do
   [ sym = SYMTAB!i 
   if (not sym>>SYm.jOnly) & sym>>SYm.z then PRINTSYM(sym)
   ]
for i = FIRSTSYM to LASTSYM do
   [ sym = SYMTAB!i 
   if (not sym>>SYm.jOnly) & (not sym>>SYm.z) then PRINTSYM(sym)
   ]
]