(******************************************************************) (* *) (* Copyright (c) 1978 Regents of the University of California. *) (* Permission to copy or distribute this software or documen- *) (* tation in hard or soft copy granted only by written license *) (* obtained from the Institute for Information Systems. *) (* *) (******************************************************************) { * Phase 1 opens host and library files and * reads in seg tables. All fields are verified * and the hostfile/libfiles file list is built. * The prototype final seg table is set up in * seginfo[*] from the host file and the sep seg * list is set up for searching in later phases. } procedure phase1; { * Build file list opens input code files and reads segtbls. * The var hostfile is set up as head of linked list of file * info recs. The order of these files determines how id's * will be searched for. Note that libfiles points at the * list just past the host file front entry. } procedure buildfilelist; label 1; var f: 0..MAXFILE; i: integer; p, q: finfop; fname: string[40]; { * Setupfile opens file and enters new finfo rec in * hostfile list. Segtbl is read in and validated. } procedure setupfile(num: integer; kind: filekind; title: string); var errs: integer; s: segindex; cp: filep; fp: finfop; alllinked: boolean; goodkinds: set of segkinds; { * Getfilep returns a pointer to a file using unspeakable * methods, but the ends justify the means. } function getfilep(var f: codefile): filep; var a: array [0..0] of filep; begin {$R-} getfilep := a[-1]; {$R+} end { getfilep } ; begin { setupfile } case num of 0: cp := getfilep(f0); 1: cp := getfilep(f1); 2: cp := getfilep(f2); 3: cp := getfilep(f3); 4: cp := getfilep(f4); 5: cp := getfilep(f5); 6: cp := getfilep(f6); 7: cp := getfilep(f7) end { cases } ; reset(cp^, title); if IORESULT <> 0 then if title <> 'in workspace' then begin insert('.CODE', title, length(title)+1); reset(cp^, title) end; if IORESULT <> 0 then begin insert('No file ', title, 1); error(title); if kind <> USERHOST then errcount := errcount-1 end else begin { file open ok } if talkative then writeln('Opening ', title); new(fp); fp^.next := hostfile; fp^.code := cp; fp^.fkind := kind; if blockread(cp^, fp^.segtbl, 1, 0) <> 1 then error('segtbl read err') else begin { now check segtbl values } s := 0; alllinked := TRUE; errs := errcount; if kind = USERHOST then goodkinds := [LINKED,SEGPROC,SEPRTSEG,HOSTSEG,UNITSEG] else goodkinds := [LINKED,UNITSEG,SEPRTSEG]; with fp^.segtbl do repeat alllinked := alllinked and (segkind[s] = LINKED); if (diskinfo[s].codeleng = 0) and (segkind[s] <> LINKED) then if (kind <> USERHOST) or (segkind[s] <> UNITSEG) then error('funny code seg'); if (diskinfo[s].codeleng < 0) or (diskinfo[s].codeaddr < 0) or (diskinfo[s].codeaddr > 300) then error('bad diskinfo'); if not (segkind[s] in goodkinds) then error('bad seg kind'); if not alphabetic(segname[s]) then error('bad seg name'); if errcount > errs then s := MAXSEG; s := s+1 until s > MAXSEG; if alllinked and (kind = USERHOST) then begin write('All segs linked'); exit(linker) end; if errcount = errs then hostfile := fp { ok file...link in } end end end { setupfile } ; begin { buildfilelist } if talkative then begin for i := 1 to 7 do writeln; writeln('Linker [I.5]') end; useworkfile := cmdstate <> SYSPROG; with userinfo do if useworkfile then begin if gotcode then fname := concat(codevid, ':', codetid) else fname := 'in workspace'; setupfile(0, USERHOST, fname); setupfile(1, SYSTEMLIB, '*SYSTEM.LIBRARY') end else begin write('Host file? '); readln(fname); if fname = '' then if gotcode then fname := concat(codevid, ':', codetid) else fname := 'in workspace'; setupfile(0, USERHOST, fname); if errcount > 0 then exit(linker); { no host! } for f := 1 to MAXFILE do begin write('Lib file? '); readln(fname); if fname = '' then goto 1; if fname = '*' then setupfile(f, SYSTEMLIB, '*SYSTEM.LIBRARY') else setupfile(f, USERLIB, fname) end; 1: write('Map name? '); readln(mapname); if mapname <> '' then if mapname[length(mapname)] = '.' then delete(mapname, length(mapname), 1) else insert('.TEXT', mapname, length(mapname)+1) end; { now reverse list so host is } { first and syslib is last } p := hostfile; hostfile := NIL; repeat q := p^.next; p^.next := hostfile; hostfile := p; p := q until p = NIL; libfiles := hostfile^.next; end { buildfilelist } ; { * Buildseginfo initializes the seginfo table from * the host prototype seg table. All legal states * are checked, and imported units found. This * leaves a list of all segs to finally appear in * the output code file. } procedure buildseginfo; label 1; var s: segindex; errs: integer; sp: segp; begin with hostfile^.segtbl do for s := 0 to MAXSEG do if (segkind[s] = LINKED) and (diskinfo[s].codeleng = 0) then seginfo[s] := NIL { not in use } else begin { do something with seg } errs := errcount; new(sp); sp^.srcfile := hostfile; sp^.srcseg := s; sp^.symtab := NIL; sp^.segkind := segkind[s]; case sp^.segkind of SEGPROC, LINKED: ; { nothing to check! } HOSTSEG: if s <> MASTERSEG then error('bad host seg') else if hostsp <> NIL then error('dup host seg') else hostsp := sp; SEPRTSEG: if s = MASTERSEG then sp^.next := NIL else begin { put into seplist } sp^.next := seplist; seplist := sp; sp := NIL end; UNITSEG: if diskinfo[s].codeleng = 0 then sp^.srcfile := unitsrch(libfiles, segname[s], sp^.srcseg) end { cases } ; if errs = errcount then seginfo[s] := sp else seginfo[s] := NIL end; { now find first assignable seg } for s := FIRSTSEG to MAXSEG do if seginfo[s] = NIL then goto 1; s := MAXSEG1; 1: nextseg := s; if seginfo[MASTERSEG] = NIL then error('wierd host') end { buildseginfo } ; { * Buildseplist searches through libraries and adds onto * a global list of sep segs that are to be searched * for procs and globals. They are initially build in * the reverse order, then reversed again so searches * will go in the order the files were specified. } procedure buildseplist; var sp, p, q: segp; fp: finfop; s: segindex; begin fp := libfiles; while fp <> NIL do begin for s := 0 to MAXSEG do if fp^.segtbl.segkind[s] = SEPRTSEG then begin new(sp); sp^.next := seplist; sp^.srcfile := fp; sp^.srcseg := s; sp^.symtab := NIL; sp^.segkind := SEPRTSEG; sp^.next := seplist; seplist := sp end; fp := fp^.next end; { now reverse the list to maintain original order } p := seplist; seplist := NIL; while p <> NIL do begin q := p^.next; p^.next := seplist; seplist := p; p := q end end { buildseplist } ; begin { phase1 } { initialize globals } hostfile := NIL; libfiles := NIL; hostsp := NIL; seplist := NIL; reflitypes := [UNITREF, GLOBREF, PUBLREF, PRIVREF, CONSTREF, SEPPREF, SEPFREF]; errcount := 0; nextbaselc := 3; mapname := ''; talkative := not userinfo.slowterm; mark(heapbase); unitwrite(3, heapbase^, 35); { build list of input files } buildfilelist; if errcount > 0 then exit(linker); { init basic seg info table } buildseginfo; if errcount > 0 then exit(linker); { finally build sep seg list } buildseplist; if errcount > 0 then exit(linker) end { phase1 } ;