// BSAE0.bcpl - BCPL Compiler -- SAE Main Program.
// Copyright Xerox Corporation 1980
//  Last modified on 15 sept 74 by GMcD.

//	DeclareNames	Scan the tree and process all declarations
//	SAEreport
//	PrintName	Print a name for SAE errors

get "bsaex"
external InitToRead

static   //  Scalars used in CAE.
 [  Curname = -1

    DVec = nil 			//  Stack of identifiers currently declared.
    DvecS = DvecN+DvecN		//  Next free location in Dvec.
    DvecE = DvecN+DvecN		//  Last Dvec location currently declared.
    DvecP = DvecN+DvecN		//  Base in Dvec of current block body.
    DvecLoc = 0			//  Output of CellWithName

    Uvec = nil
    UvecP = 0
  ]

let DeclareNames() be
 [  if SWDebug do WriteS("SAE*n")

    ResetStream(DictStream, $d)
    InitToRead(DictStream)

    let v = vec DvecT; DVec = v
    DVec!0, DVec!1 = 0, 0   //  An unused entry, for error return from CellWithName.
    DVec!DvecN, DVec!(DvecN+1) = ERRORNAME, ERRORNODE	//  Declare "?".

    Uvec = Newvec(UvecT)
    Uvec!0, Uvec!1 = ERRORNAME + LABEL, 0

    OcodeStream = OpenTemp($c, false) // output only
    Decllabels(rv Tree); Declvars(rv Tree)
    Writech(OcodeStream, ENDSTATIC)

    TreeOffset = Newvec(0); rv TreeOffset =-1	//  The last tree location

    if UvecP eq 0 return

    Ostream = ErrorStream
    WW($*n)
    if UvecP ge UvecT do WriteS("MORE THAN ")
    WriteN(UvecP/UvecN); WriteS(" UNDEFINED NAME")
      unless UvecP/UvecN eq 1 do WW($S); WW($*n)
    for p = UvecN to UvecP by UvecN do
    [ PrintName(Uvec!p); WW($*t); WriteN(Uvec!(p+1)); WW($*n) ]
    Ostream = OutputStream
  ]


and SAEreport(n, name) be
 [  Ostream = ErrorStream
    WW($*n)
    WriteLine(Curline)
    let m = selecton n into
     [	default: 0
	case 1:	"MULTIPLE DEFINITION -- EXTERNAL+STATIC & STATIC"
	case 2:	"EXTERNAL NAME USED BEFORE STATIC DECLARATION"
	case 3:	"MULTIPLE DEFINITION -- EXTERNAL & EXTERNAL"
	case 4:	"MULTIPLE DEFINITION -- EXTERNAL+STATIC & EXTERNAL"
	case 5:	"MULTIPLE DEFINITION -- STATIC & EXTERNAL"
	case 6:	"TOO MANY NAMES DEFINED IN THE SAME SCOPE"
	case 7:	"MULTIPLE DEFINITION"
	case 8:	"DYNAMIC NAME REFERENCED OUTSIDE ITS DEFINING PROCEDURE"
	case 9:	"EXPRESSION MUST BE CONSTANT"
	case 10: "UNDEFINED NAME"
	case 11: "UNDEFINED NAME AFTER @ "
	case 12: "IMPROPER NAME AFTER @ "
	case 13: "MULTIPLE STRUCTURE NAME DEFINITION"
	case 14: "UNDEFINED STRUCTURE NAME"
	case 15: "TOO MANY SUBSCRIPTS AFTER NAME"
	case 16: "NOT ENOUGH SUBSCRIPTS ON NAME"
	case 17: "SUBSCRIPT LESS THEN LOWER LIMIT"
	case 18: "SUBSCRIPT GREATER THAN UPPER LIMIT"
	case 19: "WORD FIELD IS NOT ON A WORD BOUNDARY"
	case 20: "BYTE FIELD IS NOT ON A BYTE BOUNDARY"
	case 21: "BIT FIELD OVERLAPS A WORD BOUNDARY"
      ]
    BCPLreport(n, m)
    if n ls 0 do name = -1
    unless name eq -1 do
    [ WriteS("       *""); PrintName(name); WriteS("*"*n") ]
    unless Curname eq -1 do
    [ WriteS("       LAST NAME DECLARED WAS *"")
      PrintName(Curname); WriteS("*"*n")
      Curname = -1
    ]
    if SWHelp do Help("SAE REPORT")
    if n le 0 goto Abort
    Ostream = OutputStream
  ]

and PrintName(name) be
 [  name = name & NameMask
    if name eq 0 % name eq NameMask do [ WriteS("??"); return ]
    Reposition(DictStream, name*Bytesperword)
    let v = vec NAMELENGTH/Bytesperword
    Readword(DictStream, lv v!0)
    for i = 1 to Length(v)/Bytesperword do Readword(DictStream, lv v!i)
    WW($*s); WriteS(v); WW($*s)
  ]