home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
pcmag
/
vol6n20.arc
/
INLINE.ARC
/
UNINLINE.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1986-10-06
|
23KB
|
835 lines
{UNINLINE6}
(********* Source code Copyright 1986, by L. David Baldwin *********)
{Compiling with mAx=1000 will give sufficient heap for most applications
and prevent overwriting COMMAND.COM in most cases.}
{
{
From UNAS46
}
program Inline_disasm;
{$v-}{$k-}{$c+}
const
tab = 9;
signon1 : string[35] = ^M^J'Inline Disassembler, Vers 1.0'^m^j;
signon2 : string[40] = '(C) Copyright 1986 by L. David Baldwin'^m^j;
ulen=80;
symbolleng=28;
maxbyte=maxint;
tokenleng=7;
maxlabels=300;
PhraseOk=true;
firsttab=7;
secondtab=15;
type
byteptr=^byte;
word=integer;
ptrrec=record r,s :word; end;
string8=string[8];
string127=string[127];
regtype = record
ax,bx,cx,dx,bp,si,di,ds,es,flags : integer;
end;
string2=array[1..2] of char;
filestring=string[64];
regstrtype=array[0..15] of array[1..2] of char;
segregtype=array[0..3] of array[1..2] of char;
{Packet holds a displacement which may be either in phrase form (symbolic
expression) or numeric form. It may be of byte or word size}
packet =record
dispsize :(bytesize,wordsize);
case phrase : boolean of {either a numeric or symbollic phrase}
true :(s :string[symbolleng]);
false :(value : integer);
end;
line = record {Disassembled instruction is built up in a 'line'}
case boolean of
true: (s:string[ulen]);
false :(len : byte; PCsave : integer);
end;
var
ustring : line;
chi,PC,PCstart,PCfinish : integer;
nvalue :word;
token : string[tokenleng];
pair : string2;
lch : char absolute pair;
uch :char;
st :string127;
symname:string[symbolleng];
eofinf,bytepending,firsttime,wd,toreg,prefixfl,Wait_Found : boolean;
reg,mode,rm : word;
opcode,pendingbyte :byte;
usindex,tindex,labelindx,Errcount : integer;
TextArray : array[0..maxbyte] of char;
inf,outf : text;
labels : array[0..maxlabels] of record {Holds info on needed labels}
PCvalue : integer; found : boolean;
end;
Const opcodes : array[0..$ff] of byte = (
5,5,5,5,5,5,73,71,69,69,69,69,69,69,73,20,
4,4,4,4,4,4,73,71,86,86,86,86,86,86,73,71,
6,6,6,6,6,6,24,18,97,97,97,97,97,97,16,19,
102,102,102,102,102,102,91,0,13,13,13,13,13,13,23,3,
29,29,29,29,29,29,29,29,21,21,21,21,21,21,21,21,
73,73,73,73,73,73,73,73,71,71,71,71,71,71,71,71,
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
49,46,34,41,37,43,35,42,51,48,50,47,38,44,39,45,
20,20,20,20,98,98,100,100,62,62,62,62,62,54,62,71,
67,100,100,100,100,100,100,100,8,17,7,99,74,72,84,52,
62,62,62,62,63,64,14,15,98,98,95,96,57,58,87,88,
62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,
20,20,80,80,55,53,62,62,20,20,81,81,32,30,31,33,
20,20,20,20,2,1,20,101,20,20,20,20,20,20,20,20,
61,60,59,36,28,28,70,70,7,40,40,40,28,28,70,70,
56,20,79,78,25,12,20,20,9,92,11,94,10,93,20,20);
Const grp1_2names : array[0..15] of byte =
(98,75,68,66,65,27,22,26,29,21,7,7,40,40,73,75);
Const shiftnames : array[0..7] of byte =(82,83,76,77,89,90,75,85);
Const immednames : array[0..7] of byte = (5,69,4,86,6,97,102,13);
Const instrnames : array[0..102] of string[6] = (
'AAA', 'AAD', 'AAM', 'AAS', 'ADC', 'ADD', 'AND', 'CALL', 'CBW', 'CLC',
'CLD', 'CLI', 'CMC', 'CMP', 'CMPSB','CMPSW','CS:', 'CWD', 'DAA', 'DAS',
'DB', 'DEC', 'DIV', 'DS:', 'ES:', 'HLT', 'IDIV', 'IMUL', 'IN', 'INC',
'INT', 'INTO', 'INT 3','IRET', 'JB', 'JBE', 'JCXZ', 'JZ', 'JL', 'JLE',
'JMP', 'JNB', 'JA', 'JNZ', 'JGE', 'JG', 'JNO', 'JPO', 'JNS', 'JO',
'JPE', 'JS', 'LAHF', 'LDS', 'LEA', 'LES', 'LOCK', 'LODSB','LODSW','LOOP',
'LOOPE','LOOPNE','MOV', 'MOVSB','MOVSW','MUL', 'NEG', 'NOP', 'NOT', 'OR',
'OUT', 'POP', 'POPF', 'PUSH', 'PUSHF','???', 'RCL', 'RCR', 'REPE', 'REPNE',
'RET', 'RETF', 'ROL', 'ROR', 'SAHF' ,'SAR', 'SBB', 'SCASB','SCASW','SHL',
'SHR', 'SS:', 'STC', 'STD', 'STI', 'STOSB','STOSW','SUB', 'TEST', 'WAIT',
'XCHG', 'XLAT', 'XOR');
const regstr : regstrtype = (
'AX','CX','DX','BX','SP','BP','SI','DI',
'AL','CL','DL','BL','AH','CH','DH','BH');
segregstr : segregtype = ('ES','CS','SS','DS');
{-------------OutUstring}
PROCEDURE OutUstring;
var tmp : integer;
begin
(* WriteLn(ustring.s); *)
if tindex < maxbyte-ulen then
begin
tmp:=ustring.len+1;
move(ustring, TextArray[tindex], tmp);
tindex:=tindex+tmp;
end
else
begin
WriteLn('Output Array Overflow');
Halt(1);
end;
end;
{-------------Error}
procedure Error(ii :integer; s :string127);
var x,y : integer;
newS : string127;
begin
gotoxy(1,wherey);
writeln(st);
y:=wherey;
x:=ii-3; if x<1 then x:=1;
gotoxy(x, y);
write('^');
if S[0]>#0 then NewS:='Error, '+S else NewS:='Error';
if x+ord(NewS[0])>80 then x:=x-ord(NewS[0]) else x:=x+1;
gotoxy(x,y); WriteLn(News);
Errcount:=succ(Errcount);
if Errcount>6 then
begin
Writeln('Excessive Number of Errors');
Halt(1);
end;
end;
PROCEDURE byteerr; forward;
PROCEDURE Numbyteerr; forward;
{$I unpars.inc}
{-------------insrtchr}
procedure insrtchr(c :char);
begin
ustring.s[usindex]:=c;
if ustring.len<usindex then ustring.len:=usindex;
usindex:=usindex+1;
end;
{-------------comma}
procedure comma;
begin insrtchr(','); end;
{-------------insrtst}
procedure insrtst(s :string127);
var k :integer;
begin
for k:=1 to ord(s[0]) do
begin
insrtchr(s[k]);
end;
end;
type string4=string[4];
{-------------Hex2}
FUNCTION Hex2(b :byte): string4;
const HexDigs :array[0..15] of char = '0123456789ABCDEF';
var bz :byte;
begin
bz:=b and $f; b:=b shr 4;
Hex2:=HexDigs[b]+HexDigs[bz];
end;
{-------------Hex4}
FUNCTION Hex4(w :integer): string4;
begin Hex4:=Hex2(hi(w))+Hex2(lo(w)); end;
{-------------insrthx2}
procedure insrthx2(b :byte);
begin
insrtchr('$');
insrtst(Hex2(b));
end;
{-------------insrthx4}
procedure insrthx4(w :word);
begin
insrtchr('$');
insrtst(Hex4(w));
end;
{-------------insrtdisp}
procedure insrtdisp(disp : packet);
begin
with disp do
if not phrase then
begin
if (dispsize=bytesize) then
begin
if value and $80 <>0 then
begin
insrtchr('-'); {turn into negative number}
value:=-(value or $FF00);
end
else insrtchr('+');
insrthx2(lo(value));
end
else
insrthx4(value);
end
else insrtst(s);
end;
{-------------FormLabel}
FUNCTION FormLabel(N : integer): string8;
var S : string8;
begin
str(N,S);
FormLabel:='X'+S;
end;
{-------------outlabel}
PROCEDURE outlabel(n : integer);
PROCEDURE AddLabel(N : integer);
var I : Integer; fnd : boolean;
begin
fnd:=false; {only add label if it isn't already there}
I:=0;
while (I<labelindx) and not fnd do
begin fnd:=Labels[I].PCvalue=N; I:=succ(I); end;
if not fnd then
if labelindx<=maxlabels then
with Labels[labelindx] do
begin
PCvalue:=N;
found:=false; {will try to find it later}
labelindx:=succ(labelindx);
end;
end;
begin
AddLabel(N);
Insrtst(FormLabel(N));
end;
{-------------byteerr}
PROCEDURE byteerr;
begin
error(chi,'Byte Exp');
next; {pass it by}
PC:=succ(PC);
end;
{-------------NumByteErr}
PROCEDURE NumByteErr;
begin
error(chi,'Numerical Byte Exp');
next; {pass it by}
PC:=succ(PC);
end;
{-------------shortjump}
procedure shortjump;
{the short jump instructions}
var pk : packet;
vl : word;
begin
if not getbyte(pk,PhraseOk) then byteerr;
if (opcode=$eb) then insrtst('SHORT ');
with pk do
if not phrase then
begin
vl:=value;
if (vl and $80 <>0) then vl:=vl or $FF00; {sign extend}
vl:=vl+PC;
outlabel(vl);
end
else insrtdisp(pk);
end;
{-------------intraseg}
procedure intraseg;
{the intrasegment direct jumps and calls}
var pk : packet;
begin
getword(pk);
insrtst('NEAR ');
if not pk.phrase then outlabel(pk.value+PC)
else insrtdisp(pk);
end;
{-------------interseg}
procedure interseg;
{the intersegment direct jumps and calls}
var segm,ofst : packet;
begin
getword(ofst); getword(segm);
insrtst('FAR ');
insrtdisp(segm); insrtst(':'); insrtdisp(ofst);
end;
{-------------movimtoreg}
procedure movimtoreg;
{the move immediate to a reg such as mov bl,12 }
var disp : packet;
begin
reg:=(opcode and $f) xor 8;
insrtst(regstr[reg]); comma;
if (opcode and 8)<>0 {word} then
getword(disp)
else
if not getbyte(disp,PhraseOk) then byteerr;
insrtdisp(disp);
end;
{-------------domem}
procedure domem(disp : packet);
type rptype=array[0..7] of string[5];
const regphrase : rptype = (
'BX+SI','BX+DI','BP+SI','BP+DI','SI','DI','BP','BX');
begin
if mode=3 then
begin {its a reg}
if not wd then rm:=rm+8;
insrtst(regstr[rm]);
end
else
begin {its a memory}
insrtchr('[');
if (rm=6) and (mode=0) then
insrtdisp(disp)
else
begin {need a register phrase}
insrtst(regphrase[rm]);
if mode<>0 then
begin
if (disp.dispsize=wordsize) or disp.phrase then insrtchr('+');
insrtdisp(disp);
end;
end;
insrtchr(']');
end;
end;
{-------------doreg}
procedure doreg;
begin
if not wd then reg:=reg+8;
insrtst(regstr[reg]);
end;
{-------------readmodebyte}
procedure readmodebyte(var disp : packet);
{read the mode byte and sort out the various parts. read the
displacement byte or word if req'D}
var modebyte : byte;
pk : packet;
begin
if not getbyte(pk, not PhraseOk) then Numbyteerr;
modebyte:=lo(pk.value);
rm:=modebyte and 7;
mode:=(modebyte and $c0) div 64;
reg:=(modebyte and $38) div 8;
if (mode=0) and (rm=6) or (mode=2) then
getword(disp) {get address or 16 bit disp}
else if mode=1 then {its a 8 bit displ}
if not getbyte(disp, PhraseOk) then byteerr;
end;
{-------------memseg}
procedure memseg;
{move seg reg to/from mem/reg}
var disp : packet;
begin
toreg:=(opcode and 2)<>0;
wd:=true;
readmodebyte(disp);
reg:=reg and 3; {0..3}
if toreg then
begin insrtst(segregstr[reg]); comma; domem(disp); end
else
begin domem(disp); comma; insrtst(segregstr[reg]); end;
end;
{-------------imedtoac}
procedure imedtoac; {do the immediates to ac}
var disp : packet;
begin
wd:=(opcode and 1)<>0;
reg:=0; {ax or al}
if wd then
getword(disp)
else
if not getbyte(disp, PhraseOk) then byteerr;
doreg; comma;
if wd or disp.phrase then insrtdisp(disp)
else insrthx2(lo(disp.value)); {no sign}
end;
{-------------immed}
procedure immed; {add reg/mem,12 xor reg/mem,1234}
var signext :boolean;
d1,d2 : packet;
begin
wd:=(opcode and 1)<>0;
signext:=((opcode and 2)<>0) and (opcode<=$83);{mov does not have sign ext}
readmodebyte(d1);
if opcode<=$83 then {mov has name output already}
insrtst(instrnames[immednames[reg]]);
usindex:=secondtab;
if wd and not signext then
getword(d2)
else
if not getbyte(d2, PhraseOk) then byteerr;
if mode<>3 then
begin
if wd then insrtst('WORD PTR ')
else insrtst('BYTE PTR ');
end;
domem(d1); comma;
insrtdisp(d2);
end;
{$I flpt.inc}
{-------------doshift}
procedure doshift; {do the shift and rotate instr}
var pk : packet;
begin
wd:=(opcode and 1)<>0;
readmodebyte(pk);
insrtst(instrnames[shiftnames[reg]]);
usindex:=secondtab;
if mode<>3 then
begin
if wd then insrtst('WORD PTR ')
else insrtst('BYTE PTR ');
end;
domem(pk); comma;
if (opcode and 2)<>0 then
insrtst('CL') else insrtst('1');
end;
{-------------dogroup1_2}
procedure dogroup1_2; {f6,f7,fe,ff}
var pk : packet;
begin
wd:=(opcode and 1)<>0;
readmodebyte(pk);
if (opcode and 8)<>0 then reg:=reg+8; {reg is ptr to name in this case}
if (opcode=$fe) then if (reg>=$a) then
reg:=$f; {no call, jmp, push of bytes}
insrtst(instrnames[grp1_2names[reg]]);
usindex:=secondtab;
if (reg=$a) or (reg=$c) then insrtst('NEAR ')
else if (reg=$b) or (reg=$d) then insrtst('FAR ')
else if (mode<>3) then if (reg<>$e) {push} then
begin
if wd then insrtst('WORD PTR ')
else insrtst('BYTE PTR ');
end;
domem(pk);
if reg=0 then
begin {test}
comma;
if wd then begin getword(pk); insrtdisp(pk); end
else
begin
if not getbyte(pk, PhraseOk) then byteerr;
if pk.phrase then insrtdisp(pk)
else insrthx2(lo(pk.value)); {no sign}
end;
end;
end;
{-------------memtoreg}
procedure memtoreg;
{lds,les,lea}
var pk : packet;
begin
wd:=true; toreg:=true;
readmodebyte(pk);
doreg; comma;
domem(pk);
end;
{-------------memaccum}
procedure memaccum;
{handle mov ac,[1234] , cmp ac,[5678] etc}
var disp : packet;
begin
wd:=(opcode and 1)<>0;
toreg:=(opcode and 2)=0; {note the difference in sense}
reg:=0; {will be ax or al}
getword(disp);
rm:=6; mode:=0; {for displacement only}
if toreg then
begin doreg; comma; domem(disp); end
else
begin domem(disp); comma; doreg; end;
end;
{-------------mregmreg}
procedure mregmreg;
{do the mem/reg, mem/reg instructions, such as mov bx,[bp+1234]
or add [bx],dx }
var pk : packet;
begin
wd:=(opcode and 1)<>0;
toreg:=(opcode and 2)<>0;
readmodebyte(pk);
if toreg then
begin doreg; comma; domem(pk); end
else
begin domem(pk); comma; doreg; end;
end;
{-------------rep_lock}
procedure rep_lock; {do lock, repe, repne,wait, and seg overrides}
begin
prefixfl:=true;
OutUstring;
end;
{-------------unassem1}
procedure unassem1;
{unassemble one line of code (or two if preceeded by a seg instruction)
output the unassembled line in ustring.}
label 10;
const
dolater : set of byte = [$9B,$f6,$f7,$fe,$ff,$d0..$d3,$d8..$df,$80..$83];
var
pk : packet;
err : boolean;
PROCEDURE insbyte;
var pk1 : packet;
begin
if not getbyte(pk1, PhraseOk) then byteerr;
if pk1.phrase then insrtdisp(pk1) else insrthx2(lo(pk1.value));
end;
begin
Wait_Found:=false;
repeat
prefixfl:=false; {set true later if a segm overide instr found}
ustring.len:=0;
fillchar(ustring.s[1], ulen, ' '); {clear ustring}
ustring.PCsave:=PC;
repeat
err:=not getbyte(pk, not PhraseOk);
if err then begin Numbyteerr; Next; end;
opcode:=pk.value;
until not err;
usindex:=firsttab;
if not (opcode in dolater) then
begin {most items have opcode name output now}
insrtst(instrnames[opcodes[opcode]]);
usindex:=secondtab;
end;
case opcode of
$27,$2f,$37,$3f,
$90,$98,$99,$9c..$9f,$aa..$af,$a4..$a7,
$c3,$cb,$cc,$ce,$cf,$d7,$f4,$f5,
$f8..$fd :; {opcode only}
$26,$36,$2e,$3e, {seg overide inst}
$f0,$f2,$f3 :rep_lock; {lock, repe, repne}
$40..$5f,
$91..$97 :begin
insrtst(regstr[opcode and 7]); {push,pop,xchg
inc,dec}
if opcode>=$91 then
insrtst(',AX'); {xchg}
end;
0..3,8..$b,$10..$13,$18..$1b,
$20..$23,$28..$2b,$30..$33,$38..$3b,$84..$87,
$88..$8b :mregmreg;
$b0..$bf :movimtoreg; {mov cx,1234 etc.}
$70..$7f,$e0..$e3,
$eb :shortjump;
$e8,$e9 :intraseg;
$ea,$9a :interseg;
6,7,$e,$16,$17,$1e,$1f
:begin {seg, push-pop seg}
reg:=(opcode div 8) and 3;
insrtst(segregstr[reg]);
end;
$4,$5,$c,$d,$14,$15,$1c,$1d,$24,$25,$2c,$2d,$34,$35,$3c,$3d,
$a8,$a9 :imedtoac;
$a0..$a3 :memaccum; {mov ac,[1234] }
$c4,$c5,$8d :memtoreg; {les,lds,lea}
$cd :insbyte; {int n}
$ee,$ef :begin {out dx,ac}
wd:=true; reg:=2;
doreg;
10: comma;
wd:=(opcode and 1)<>0;
reg:=0; {ax or al}
doreg;
end;
$e4,$e5,$ec,$ed :begin {in ac, dx or port}
wd:=(opcode and 1)<>0;
reg:=0;
doreg;
comma;
if (opcode>=$ec) then
begin wd:=true; reg:=2; doreg; end
else insbyte;
end;
$e6,$e7 :begin {out port,ac}
insbyte;
goto 10;
end;
$8c,$8e :memseg; {segment, reg instr}
$f6,$f7,$fe,$ff :dogroup1_2;
$d0..$d3 :doshift;
$80..$83,$c6,$c7:immed;
$8f :begin
wd:=true; {pop reg/mem}
readmodebyte(pk);
domem(pk);
end;
$c2,$ca :begin getword(pk);insrtdisp(pk); end; {ret n}
$d4,$d5 :begin {aam,aad}
if not getbyte(pk,PhraseOk) then byteerr;
if not pk.phrase then
if pk.value<>$a then insrthx2(lo(pk.value));
end;
$9B :{WAIT - look to see if it preceeds a Fl Point instr}
if((sy=wordsy) or (sy=bytesy)) and (lo(nvalue)>=$d8)
and (lo(nvalue)<=$df) then
begin Wait_found:=true; Prefixfl:=true; end
else insrtst(instrnames[opcodes[$9B]]);
{plain wait}
$da,$de :da_de;
$d8,$dc :d8_dc;
$d9 :d9;
$db :db;
$dd :dd;
$df :df;
else insrthx2(opcode); {for db (databyte)}
end; {case}
until prefixfl=false;
OutUstring;
end;
{-------------chk_ioerror}
FUNCTION chk_ioerror(S : filestring): Integer;
var ioerr : Integer;
begin
ioerr := IOResult;
if ioerr = 1 then WriteLn('Can''t find ', S)
else if ioerr <> 0 then WriteLn('I/O Error ', Hex4(ioerr));
chk_ioerror := ioerr;
end;
{-------------PromptForInput}
PROCEDURE PromptForInput;
var
inname,name : filestring;
err : Integer;
begin
{$I-}
Repeat
Write('Inline Object Filename [.OBJ]: '); ReadLn(inname);
if inname='' then Halt;
DefaultExtension('OBJ', inname, name);
Assign(inf, inname); Reset(inf);
err:=chk_ioerror(inname);
if err>1 then Halt(1);
until err=0;
Write('Assembly Language Source Filename [', name, '.ASM]: '); ReadLn(inname);
if inname='' then inname:=name; {Use the same name}
DefaultExtension('ASM',inname,name);
Assign(outf, inname);
ReWrite(outf);
if chk_ioerror(inname)<>0 then Halt(1);
{$I+}
end;
{-------------CommandInput}
PROCEDURE CommandInput;
var
inname,name : filestring;
PROCEDURE DoHelp;
begin
Halt;
end;
begin
inname:=ParamStr(1);
if Pos('?', inname)<>0 then DoHelp;
DefaultExtension('OBJ', inname, name);
{$I-}
Assign(inf, inname);
ReSet(inf);
if chk_ioerror(inname)<>0 then Halt(1);
if ParamCount>=2 then inname:=ParamStr(2)
else inname:=name; {Use the old name}
DefaultExtension('ASM',inname,name);
Assign(outf, inname);
ReWrite(outf);
if chk_ioerror(inname)<>0 then Halt(1);
{$I+}
end;
{-------------ReportLabelErrors}
PROCEDURE ReportLabelErrors;
var I : integer;
begin
if labelindx>maxlabels then
WriteLn('Number of labels exceeds array capacity');
for I:=0 to labelindx-1 do
with labels[I] do
if not found then
if (PCvalue<PCstart) or (PCvalue>PCfinish) then
writeln('Label ',FormLabel(PCvalue),' is out of Inline code range')
else
writeln('Label ',FormLabel(PCvalue),' cannot be found');
end;
{-------------WriteToFile}
PROCEDURE WriteToFile;
var
P : ^line;
Px : ptrrec absolute P;
I,tmp : integer;
LB : string8;
FUNCTION FindLabel(N : integer): boolean;
var I : integer; fnd : boolean;
begin
fnd:=false; I:=0;
while (I<labelindx) and not fnd do
begin fnd:=labels[I].PCvalue=N; I:=succ(I); end;
if fnd then Labels[I-1].found:=true;
FindLabel:=fnd;
end;
begin
P:=addr(TextArray);
I:=0;
while I < tindex do {tindex now is index to last useful byte +1}
begin
with P^ do
begin
if findlabel(PCsave) then
begin {put it into textarray}
LB:=formlabel(PCsave)+':'; {in string form}
move(LB[1], S[1], ord(LB[0]));
end
else PCsave:=$2020; {replace integer by 2 spaces}
WriteLn(outf,S);
tmp:=len+1;
end;
I:=I+tmp;
Px.r:=Px.r+tmp;
end;
end;
{-------------MAIN}
begin
WriteLn(signon1,signon2);
Errcount:=0;
PC:=0; bytepending:=false; firsttime:=true;
if ParamCount >= 1 then CommandInput else PromptForInput;
eofinf:=false;
st[0]:=#0; chi:=1; {get the reading started}
getch;
gettoken;
while not eofinf do
if token='INLINE' then
begin
tindex:=0; {index into TextArray}
PCstart:=PC; labelindx:=0;
if not firsttime then
WriteLn(outf,'NEW');
next;
if sy=lparn then next;
while (sy<>rparn) and not eofinf do unassem1;
if sy=rparn then gettoken;
firsttime:=false;
PCfinish:=PC;
Ustring.S:=' '; {Provide for possible label at the end}
Ustring.PCsave:=PC;
OutUstring;
WriteToFile; {TextArray to outf, adding labels as req'd}
ReportLabelErrors;
end
else gettoken;
close(inf);
close(outf);
end.