// Routines for dynamic vectors and argument defaulting.
// Copyright Xerox Corporation 1979
// Last modified July 12, 1979  8:15 PM by Taft

external
[
// outgoing procedures
Dvec; 
DefaultArgs

// incoming procedures
CallersFrame; GotoFrame; Usc; SysErr
]

manifest
[
endCode = #335

ecDvecStackOverflow = 1002
ecTooFewArguments = 1003
]

structure F:	//BCPL frame
[
callersFrame word
savedPC word
temp word
extraArguments word
formals word
]
manifest formalsOffset = offset F.formals/16


//---------------------------------------------------------------------------
let Dvec(caller, newVecs, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
  nil, nil, nil, nil, nil, nil, nil, nil, nil,
 nil; numargs na) = valof
//---------------------------------------------------------------------------
[
let myArgs = lv caller
let cf = CallersFrame()
let cfs = CallersFrame(cf) - cf
let top = cf + cfs

let length = 0
let i = 0
while i ls na-1 do
   [
   i = i+1
   if myArgs!i eq 0 break
   length = length + rv myArgs!i+1
   rv myArgs!i = top - length
   ]

while i ls na-1 do
   [
   i = i+1
   let t = rv myArgs!i
   if t ge cf & t ls top then rv myArgs!i = t-length
   ]

let newCf = cf-length
if Usc(newCf, rv endCode) le 0 then SysErr(length, ecDvecStackOverflow)

// MoveBlock(newCf, cf, cfs)
// resultis newCf+cfs
let DoMove = table
   [
   #35003	// lda 3 extraArgs,2
   #131400	// inc 1 2
   #173000	// add 3 2
   #61005	// blt
   #121400	// inc 1 0	return address of first new word
   #35001	// lda 3 savedPC,2
   #1401	// jmp 1,3
   ]

resultis DoMove(cf-1, newCf+cfs-1, -cfs)
]


//---------------------------------------------------------------------------
and DefaultArgs(lvNa, base, defaultValue, nil, nil, nil, nil,
  nil, nil, nil, nil, nil; numargs na) be
//---------------------------------------------------------------------------
[
if na ls 2 then base = 0
let defaultOnZero = false
if base ls 0 then [ defaultOnZero = true; base = -base ]

let dvVec = lv defaultValue - base
let actualNumDVs = na-3 + base
let defaultDV = (na ls 3? 0, dvVec!actualNumDVs)
let callersFormals = CallersFrame() + formalsOffset

if @lvNa ls base then SysErr(nil, ecTooFewArguments)

for i = base to (lvNa-callersFormals-1) do
   if i ge @lvNa % (defaultOnZero & callersFormals!i eq 0) then
      callersFormals!i = (i le actualNumDVs ? dvVec!i, defaultDV)
]