// BSAE1.bcpl - BCPL Compiler -- SAE part 1 - Declaration handling
// Copyright Xerox Corporation 1980
//  Last modified on Sun 29 Oct 72 0345.20 by  jec.
//  Swinehart, 5-10-77: docase exp, merge Declvars activities

//  last modified by Butterfield, January 31, 1979  12:59 PM
//  - Scanlabels and Declvars, ThinDVec on END - 1/25/79

//      Decllabels	Declare all the labels at the top level in a block.
//     *ScanLabels	Do the work for Decllabels.
//      Declvars	Declare all the rest of the names in a block.
//     *ThinDVec	Squeeze out names with excessive Dictionary indexes.
//  * local to this file.


get "bsaex"
//  This routine is called for all blocks to declare all labels reachable at the top level
//  in the block.  It uses ScanLabels to do the work.

let Decllabels(x) be
 [  let DS = DvecS
    let L = Curline
    ScanLabels(x)
    CheckDistinct(DS, DvecS)
    Curline = L
    DvecE = DvecS
  ]


//  This routine does the work for Decllabels just above.  All labels are declared.

and ScanLabels(x) be
 [  if x eq 0 return
    switchon H1!x into
     [  default:
	    return

	case COLON:
	 [  H5!x = Nextentry()
	    H2!(H2!x) = H5!x
	    let d = DeclStatic(H2!x, LENTRY)
	    H4!x = d!1
	    ScanLabels(H3!x)
	    return
	  ]

	case IF: case UNLESS:
	case UNTIL: case WHILE:
	    ScanLabels(H3!x)
	    return

	case REPEAT:
	case REPEATWHILE: case REPEATUNTIL:
	    ScanLabels(H2!x)
	    return

	case TEST:
	    ScanLabels(H3!x)
	    ScanLabels(H4!x)
	    return

	case LINE:
	    Curline = H2!x
	    if SWList do WriteLine(Curline)
	    ScanLabels(H3!x)
	    return

	case END:
	    ThinDVec(H2!x)
	    ScanLabels(H3!x)
	    return

	case SWITCHON: case CASE:
	    ScanLabels(H3!x)
	    return

	case CASETO:
	    ScanLabels(H4!x)
	    return

	case DEFAULT:
	    ScanLabels(H2!x)
	    return

	case SEQ:
	    ScanLabels(H2!x)
	    ScanLabels(H3!x)
	    return

///*DCS* conditional compilation, choose one
	case COMPILEIF:
	    [
	    H1!x = COMPILETEST
	    let B = EvalConst(H3+x)
	    /// 0 => want ifnot (no code if COMPILEIF)
	    let res = B? H4!x, H5!x
	    if res then
	      [
        let rest = H2!x
        H2!x = res
        Compileifsplice(x,H2+x,rest)
        ]
	    ScanLabels(H2!x) // rest of block body
	    return
	    ]
   ]
  ]


and Declvars(x) be
 [  if x eq 0 return
    switchon H1!x into
     [  case LET:
	    DeclareLet(x)
	    return

  	case EXT:
  	case MANIFEST:
	case STATIC:
	case STRUCTURE:
	 [  let DE, DS = DvecE, DvecS

	 L:  test H1!x eq STRUCTURE
	    then
	    [struct
		DeclStruct(lv H3!x, H3!x, true)
		let err = CheckStruct(H3!x, 0)
		unless err eq 0 do SAEreport(err, -1)
	    ]struct
	    or
	    [var
	    let p = lv H4!x
	    until p ge lv H4!x + H3!x do
	     [scan
		Curname = p!0
		switchon H1!x into
		 [  case EXT:
			DeclExt(p)
			endcase

		    case STATIC:
			p!1 = EvalConst(lv p!1)
			DeclStatic(p, STATIC)
			endcase

		    case MANIFEST:
			p!1 = EvalConst(lv p!1)
			NewName(p)
			endcase

	          ]
		 DvecE = DvecS
		 p = p + 2
	      ]scan
	    ]var

	    Curname = -1
	    let t = x
	    x = H2!x
	M:  switchon H1!x into
		[ case LINE:	Curline = H2!x
				if SWList do WriteLine(Curline)
				x = H3!x
				goto M
		  case END:	ThinDVec(H2!x)
				x = H3!x
				goto M
		  case EXT:
		  case MANIFEST:
		  case STATIC:
		  case STRUCTURE:
				goto L

		  default:	endcase
		]
	    x = t

	    CheckDistinct(DS, DvecS)
	    DvecE = DvecS
	    Decllabels(H2!x)
	    Declvars(H2!x)
	    DvecE, DvecS = DE, DS
	    return
	  ]

	case LINE:
	    Curline = H2!x
	    if SWList do WriteLine(Curline)
	    Declvars(H3!x)
	    return

	case END:
	    ThinDVec(H2!x)
	    Declvars(H3!x)
	    return

	case ASS: case RTAP:
	    Lookat(H2+x); Lookat(H3+x)
	    return

	case GOTO: case RESULTIS: case DOCASE:
 	    Lookat(H2+x)
	    return

	case IF:
	case UNLESS:
	case WHILE:
	case UNTIL:
	case CASE:
	case SWITCHON:
	    Lookat(H2+x)
	case COLON:
	    Declvars(H3!x)
	    return

	case TEST:
	    Lookat(H2+x)
	    Declvars(H3!x)
	    Declvars(H4!x)
	    return

	case REPEATWHILE:
	case REPEATUNTIL:
	    Lookat(H3+x)
	case REPEAT:
	case DEFAULT:
	case COMPILETEST:
	    Declvars(H2!x)
	    return

	case CASETO:   //  Case label with limits.
	    Lookat(H2+x); Lookat(H3+x)
	    Declvars(H4!x)
	    return

	case FOR:
	 [  Lookat(H3+x)
	    Lookat(H4+x)   
	    unless H5!x eq 0 do Lookat(H5+x)
	    let DE, DS = DvecE, DvecS
	    DeclLocal(H2!x)
	    DvecE = DvecS   
	    Decllabels(H6!x)   
	    Declvars(H6!x)		
	    DvecE, DvecS = DE, DS
	    return
	  ]

	case SEQ:
	    Declvars(H2!x)
	    Declvars(H3!x)
	    return

 case COMPILEIF:
      SAEreport(-20)    // Conditional compilation out of place

	case BREAK:
	case LOOP:
	case RETURN:
	case FINISH:
	case ABORT:
	case ENDCASE:
	    return

	default:
	    SAEreport(-1)   //  Error report.
      ]
  ]

and Compileifsplice(x,lvsome,rest) be
   [
   let some = @lvsome
   unless some do
      [
      @lvsome = rest
      return
      ]
   let idx = selecton H1!some into
      [
      case MANIFEST:
      case EXT:
      case STATIC:
      case COMPILEIF:
      case STRUCTURE: H2
      case LINE:
      case AND:
      case LET:
      case SEQ: H3
      default: -1
      ]
   test idx < 0
      ifso
         [
         H3!x = SEQ
         H4!x = some
         H5!x = rest
         @lvsome = H3+x
         ]
      ifnot
         Compileifsplice(x,idx+some,rest)
   ]
         
//----------------------------------------------------------------------------
and ThinDVec(newEnd) be
//----------------------------------------------------------------------------
[
manifest [ signBit = #100000; goodSign = signBit; badSign = 0; ]
let NextName(index, sign, newEnd) = valof
   [
   if index ge DvecS resultis DvecS  //don't let index go beyond DvecS
   let nameword = DVec!index;
   let name = NameMask & (((nameword & NameBit) ne 0)? nameword, @nameword)
   if (name - newEnd & signBit) eq sign resultis index;
   index = index + DvecN;
   ] repeat;
let new = NextName(DvecN + DvecN, badSign, newEnd); let bad = new;
//(skip CellWithName's unused error entry and ERRORNAME entry; cf. BSAE0) 
while bad ls DvecS do
   [
   let good = NextName(bad + DvecN, goodSign, newEnd);
   bad = NextName(good + DvecN, badSign, newEnd);
   for i = 0 to bad - good - 1 do DVec!(new+i) = DVec!(good+i);
   new = new + bad - good;
   ]
DvecS = new;
]