// BSAE4.bcpl - BCPL Compiler -- SAE part 4 -- Structure reference handling
// Copyright Xerox Corporation 1980

//	LookatQual
//	TraceStructName
//	StructSize
//	CheckStruct

get "bsaex"

let LookatQual(x) = valof
[ let S = NULLQUALNODE
  if x!0 eq 0 resultis S
  let def = StructWithName(x!1)
  if def eq 0 do [ SAEreport(14, x!1); x!(-1) = S; resultis S ]
  def = DVec!(DvecLoc+1)	//the top-level node containing the name

  let u = vec QualMax * 4
  u!0 = 0
  let q = 1
  u!q = 0

  let p = 1
  for k = 1 to x!0 do
  [nextname
	let v = vec QualMax*2
	v!0 = 0
	v!1 = 0
	let d = TraceStructName(x!p, def, v)
	if d eq 0 do [ SAEreport(14, x!p); x!(-1) = S; resultis S ]

	let m = x!(p+1)
	let n = v!0
	test m gr n
	then [ SAEreport(15, x!p); x!(-1) = S; resultis S ]
	or if m ls n unless k eq x!0
	then [ SAEreport(16, x!p); x!(-1) = S; resultis S ]

	let r = 1
	for l = 1 to x!(p+1) do
	[nextsubscr
	    u!q = u!q + v!r
	    let subdef = v!(r+1)
	    let lvsub = Lookat(lv x!((p+1)+l))
	    test lvsub gr 0
	    then
	     [	let sub = rv lvsub
		unless sub ge H3!subdef do SAEreport(17, x!p)
		unless sub le H4!subdef do SAEreport(18, x!p)
		u!q = u!q + (sub - H3!subdef) * StructSize(H2!subdef)
	     ]
	    or
	     [	u!(q+1) = x!((p+1)+l)
		u!(q+2) = lv H3!subdef
		u!(q+3) = StructSize(H2!subdef)
		u!0 = u!0 + 1
		q = q + 4
		u!q = 0
	     ]
	    r = r + 2
	]nextsubscr

	u!q = u!q + v!r
	u!(q+1) = StructSize(v!(r+1))

	p = (p+1) + x!(p+1) +1
	def = d
  ]nextname

  S = Newvec(q+1)
  H1!S = u!q
  H2!S = u!(q+1)
  for i = 0 to q-1 do (H3+i)!S = u!i
  x!(-1) = S
  resultis S
]

and TraceStructName(name, def, v) = valof
[ if (H1!def & NameBit) ne 0 do
     [	test (H1!def & NameMask) eq (name & NameMask)
	then [ v!(v!0*2+2) = H2!def; resultis H2!def ]
	or   resultis 0
     ]

  switchon H1!def into
   [ case UPLUMP:
      [uplump
	let m = v!0
	let n = m*2+1
	v!(n+1) = def
	v!0 = v!0 + 1
	n = n + 2
	v!n = 0
	let s = TraceStructName(name, H2!def, v)
	if s eq 0 do v!0 = m
	resultis s
      ]uplump
     case FIELDLIST: case OVERLAYLIST:
      [list
	let m = v!0
	let n = m*2+1
	let l = v!n
	for i = 1 to H2!def do
	 [  let y = (H2+i)!def
	    let s = TraceStructName(name, y, v)
	    if s ne 0 resultis s
	    if H1!def eq FIELDLIST do v!n = v!n + StructSize(y)
	 ]
	v!n = l
      ]list
     case BLANK:
	resultis 0
     case BIT: case BYTE: case WORD:
	resultis 0
     default:
	SAEreport(-25)
  ]
]

and StructSize(def) = valof
[ if (H1!def & NameBit) ne 0 resultis StructSize(H2!def)
  switchon H1!def into
   [ case UPLUMP:
	resultis (H4!def - H3!def + 1) * StructSize(H2!def)
     case FIELDLIST:
      [	let s = 0
	for i = 1 to H2!def do
	    s = s + StructSize((H2+i)!def)
	resultis s
      ]
     case OVERLAYLIST:
      [	let s = 0
	for i = 1 to H2!def do
	 [  let t = StructSize((H2+i)!def)
	    if t gr s do s = t
	 ]
	resultis s
      ]
     case BLANK:
	resultis StructSize(H2!def)
     case BIT:
	resultis H2!def
     case BYTE:
	resultis H2!def * ByteSizeOb
     case WORD:
	resultis H2!def * WordSizeOb
     default:
	SAEreport(-26)
   ]
]

and CheckStruct(def, B) = valof
[ if def eq 0 resultis 0
  let err = 0
  test (H1!def & NameBit) ne 0
  then [ Curname = H1!def
	 err = CheckStruct(H2!def, B)
	]
  or switchon H1!def into
       [ case FIELDLIST:
	    for i = 1 to H2!def do
		[ err = CheckStruct((H2+i)!def, B)
		  unless err eq 0 resultis err
		  B = B + StructSize((H2+i)!def)
		]
	    endcase
	 case OVERLAYLIST:
	    for i = 1 to H2!def do
		[ err = CheckStruct((H2+i)!def, B)
		  unless err eq 0 resultis err
		]
	    endcase
	 case UPLUMP:
	    for i = H3!def to H4!def do
		[ err = CheckStruct(H2!def, B)
		  unless err eq 0 resultis err
		  B = B + StructSize(H2!def)
		]
	    endcase
	 case BLANK:
	    endcase
	 case WORD:
	    unless B rem WordSizeOb eq 0 do err = 19
	    endcase
	 case BYTE:
	    unless B rem ByteSizeOb eq 0 do err = 20
	    endcase
	 case BIT:
	    unless (B+StructSize(def)-1)/WordSizeOb eq B/WordSizeOb do err = 21
	    endcase
	 default:
	    SAEreport(-27)
       ]
  resultis err
]