home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / INLIN219.ZIP / INLINE.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-04-26  |  53.4 KB  |  2,024 lines

  1.                              {Inline27}
  2.  
  3. (*********  Source code Copyright 1986, by L. David Baldwin   *********)
  4.  
  5. {$R-,S-,I+,F-,V-,B-,N-}
  6. {$M 16384,0,655360 }
  7.  
  8. {
  9. 27 Vers 2.19 Fix CMP AX,-1, etc., incorrect in Vers 2.18.
  10. 26 Vers 2.18 Implement the sign extension bit for some instructions
  11. 25 Vers 2.17 Convert to Turbo 4.
  12. 24 Vers 2.16 Change byte size check in MemReg so the likes of
  13.              MOV [DI+$FE],AX will assemble right.
  14.    Allow ',' in DB pseudo op instruction.
  15. 23 Vers 2.15 Fix 'shl cl,1' which assembled as shl cl,cl
  16. 22 Vers 2.14 Change output format to better accomodate map file line numbers.
  17. 21 Vers 2.13 Allow JMP SHORT direct using symbols.
  18. 20 Vers 2.12 Allow CALL and JMP direct using symbols.
  19. 19 Vers 2.11
  20.    Fix bug in CallJmp and ShortJmp which didn't restrict short
  21.    jump range properly.
  22.    Fix bug which didn't allow CALL or JMP register. (CALL BX).
  23. 18 Vers 2.1
  24.    Fix bug in Accum which occasionally messed up IN and OUT instr.
  25.    Fix unintialized function in getnumber for quoted chars.
  26. 17 Vers 2.03
  27.     Change GetSymbol to accept about anything after '>' or '<'
  28.     Add 'NEW' pseudoinstruction.
  29.     Fix serious bug in defaultextension.
  30.     Add Wait_Already to prevent 2 'WAIT's from occuring.
  31.     Use 'tindex<maxbyte' comparison rather than <= which won't work
  32.     with integer comparison in this case.
  33. }
  34.  
  35. PROGRAM Inline_Asm;
  36.  
  37. Const
  38.   CommentColumn = 25;     {column where comments start in object file}
  39.   Symbolleng = 32;        {maximum of 32 char symbols}
  40.   CR = 13; Lf = 10; Tab = 9;
  41.   Maxbyte = MaxInt;
  42.   BigStringSize = 127;
  43.  
  44.   Signon1 : String[32] =
  45.  
  46.             ^M^J'Inline Assembler, Vers 2.19';
  47.  
  48.   Signon2 : String[43] =
  49.  
  50.             ^M^J'(C) Copyright 1986-7 by L. David Baldwin'^M^J;
  51.  
  52. Type
  53.   FileString = String[64];
  54.   SymString = String[Symbolleng];
  55.   IndxReg = (BX, SI, DI, BP, None);
  56.   IndxSet = set of IndxReg;
  57.   PtrType = (BPtr, WPtr, DwPtr, QwPtr, TbPtr, UnkPtr); {keep order}
  58.   String4 = String[4];
  59.   String5 = Array[1..5] of Char;
  60.   Symtype = (Address, Disp8, Disp16, Othersym, EOLsym, Identifier, JmpDist,
  61.     LfBrack, RtBrack, Plus, Comma, STsym);
  62.   Table = Array[0..20] of SymString; {fake}
  63.   BigString = String[BigStringSize]; {125 chars on a turbo line}
  64.   Label_Info_ptr = ^Label_Info;
  65.   Label_Info = Record
  66.                  Name : SymString;
  67.                  ByteCnt : Integer;
  68.                  Next : Label_Info_ptr;
  69.                end;
  70.   Fixup_Info_Ptr = ^Fixup_Info;
  71.   Fixup_Info = Record
  72.                  Name : SymString;
  73.                  Indx, Indx2, Fix_pt : Integer;
  74.                  Jmptype : (Short, Med);
  75.                  Prev, Next : Fixup_Info_Ptr;
  76.                end;
  77.  
  78. Var
  79.   NoAddrs, Aerr, Symbol, TheEnd, NewFnd, St_first,
  80.   Displace, WordSize, Wait_Already : Boolean;
  81.   Addr : Integer;
  82.   Sym : Symtype;
  83.   ModeByte, Reg1, Reg2, W1, W2, Sti_val : Integer;
  84.   SaveOfs, DataVal : Record
  85.                        Symb : Boolean;
  86.                        Sname : SymString;
  87.                        Value : Integer;
  88.                      end;
  89.   IRset : IndxSet;
  90.   Rmm, Md : Integer;
  91.   ByWord : PtrType;
  92.   Byt, SignExt : Byte;
  93.   Tindex, Tindex0, Column, I, ByteCount, LastSlash : Integer;
  94.   TextArray : Array[0..Maxbyte] of Char;
  95.  
  96.   Lsid : SymString;
  97.   Str8 : Array[1..9] of Char; {the following 4 are at the same location}
  98.   Str : String5 Absolute Str8;
  99.   ID2 : Array[1..2] of Char Absolute Str8;
  100.   ID3 : Array[1..3] of Char Absolute Str8;
  101.   UCh, LCh : Char;
  102.   Chi, OldChi : Integer;
  103.   Out, Inn : Text;
  104.  
  105.   Start_Col : Integer;
  106.   St : BigString;
  107.   Firstlabel, Pl : Label_Info_ptr;
  108.   Firstfix, Pf : Fixup_Info_Ptr;
  109.  
  110. {-------------DefaultExtension}
  111. PROCEDURE DefaultExtension(Extension:FileString;Var Infile,Name :FileString);
  112. {Given a filename, infile, add a default extension if none exists. Return
  113.  also the name without any extension.}
  114. Var
  115.  I,J : Integer;
  116.  Temp : FileString;
  117. begin
  118. I:=Pos('..',Infile);
  119. if I=0 then
  120.   Temp:=Infile
  121. else
  122.   begin   {a pathname starting with ..}
  123.   Temp:=Copy(Infile,I+2,64);
  124.   I:=I+1;
  125.   end;
  126. J:=Pos('.',Temp);
  127. if J=0 then
  128.   begin
  129.   Name := Infile;
  130.   Infile:=Infile+'.'+Extension;
  131.   end
  132. else Name:=Copy(Infile,1,I+J-1);
  133. end;
  134.  
  135. {-------------Space}
  136. PROCEDURE Space(N : Integer);
  137. Var I : Integer;
  138. begin for I := 1 to N do Write(' '); end;
  139.  
  140. {-------------Error}
  141. PROCEDURE Error(II : Integer; S : BigString);
  142. begin
  143. if not Aerr then
  144.   begin
  145.   WriteLn(St);
  146.   Space(Start_Col+II-4);
  147.   Write('^Error');
  148.   if Length(S) > 0 then
  149.     begin Write(', '); Write(S); end;
  150.   WriteLn;
  151.   Aerr := True;
  152.   end;
  153. end;
  154.  
  155. {the following are definitions and variables for the parser}
  156. Var
  157.   Segm, NValue : Integer;
  158.   Symname : SymString;
  159. {end of parser defs}
  160.  
  161. {-------------GetCh}
  162. PROCEDURE GetCh;
  163.   {return next char in uch and lch with uch in upper case.}
  164. begin
  165. if Chi <= Ord(St[0]) then LCh := St[Chi] else LCh := Chr(CR);
  166. UCh := UpCase(LCh);
  167. Chi := Chi+1;
  168. end;
  169.  
  170. {-------------SkipSpaces}
  171. PROCEDURE SkipSpaces;
  172. begin
  173. while (UCh = ' ') or (UCh = Chr(Tab)) do GetCh;
  174. end;
  175.  
  176. {-------------GetDec}
  177. FUNCTION GetDec(Var V : Integer) : Boolean;
  178. Const Ssize = 8;
  179. Var
  180.   S : String[Ssize];
  181.   Getd : Boolean;
  182.   Code : Integer;
  183. begin
  184. Getd := False;
  185. S := '';
  186. while (UCh >= '0') and (UCh <= '9') do
  187.   begin
  188.   Getd := True;
  189.   if Ord(S[0]) < Ssize then S := S+UCh;
  190.   GetCh;
  191.   end;
  192. if Getd then
  193.   begin
  194.   Val(S, V, Code);
  195.   if Code <> 0 then Error(Chi, 'Bad number format');
  196.   end;
  197. GetDec := Getd;
  198. end;
  199.  
  200. {-------------GetHex}
  201. FUNCTION GetHex(Var H : Integer) : Boolean;
  202. Var Digit : Integer;        {check for '$' before the call}
  203. begin
  204. H := 0; GetHex := False;
  205. while (UCh in ['A'..'F', '0'..'9']) do
  206.   begin
  207.   GetHex := True;
  208.   if (UCh >= 'A') then Digit := Ord(UCh)-Ord('A')+10
  209.     else Digit := Ord(UCh)-Ord('0');
  210.   if H and $F000 <>0 then Error(Chi, 'Overflow');
  211.   H := (H Shl 4)+Digit;
  212.   GetCh;
  213.   end;
  214. end;
  215.  
  216. {-------------GetNumber}
  217. FUNCTION GetNumber(Var N : Integer) : Boolean;
  218.   {get a number and return it in n}
  219. Var Term : Char;
  220.   Err : Boolean;
  221. begin
  222. N := 0;
  223. if UCh = '(' then GetCh;    {ignore ( }
  224. if (UCh = '''') or (UCh = '"') then
  225.   begin
  226.   GetNumber := True;
  227.   Term := UCh; GetCh; Err := False;
  228.   while (UCh <> Term) and not Err do
  229.     begin
  230.     Err := N and $FF00 <> 0;
  231.     N := (N Shl 8)+Ord(LCh);
  232.     GetCh;
  233.     if Err then Error(Chi, 'Overflow');
  234.     end;
  235.   GetCh;                    {use up termination char}
  236.   end
  237. else if UCh = '$' then
  238.   begin                     {a hex number}
  239.   GetCh;
  240.   if not GetHex(N) then Error(Chi, 'Hex number exp');
  241.   GetNumber := True;
  242.   end
  243. else
  244.   GetNumber := GetDec(N);   {maybe a decimal number}
  245. if UCh = ')' then GetCh;    {ignore an ending parenthesis}
  246. end;
  247.  
  248. {-------------GetExpr}
  249. FUNCTION GetExpr(Var Rslt : Integer) : Boolean;
  250. Var
  251.   Rs1, Rs2, SaveChi : Integer;
  252.   Pos, Neg : Boolean;
  253. begin
  254. SaveChi := Chi;
  255. GetExpr := False;
  256. SkipSpaces;
  257. Neg := UCh = '-';
  258. Pos := UCh = '+';
  259. if Pos or Neg then GetCh;
  260. if GetNumber(Rs1) then
  261.   begin
  262.   GetExpr := True;
  263.   if Neg then Rs1 := -Rs1;
  264.   if (UCh = '+') or (UCh = '-') then
  265.     if GetExpr(Rs2) then
  266.       Rs1 := Rs1+Rs2;       {getexpr will take care of sign}
  267.   Rslt := Rs1;
  268.   end
  269. else
  270.   begin
  271.   Chi := SaveChi-1; GetCh;
  272.   end;
  273. end;
  274.  
  275. {$v+}
  276. {-------------GetSymbol}
  277. FUNCTION GetSymbol(Var S : SymString) : Boolean;
  278. Const Symchars : set of Char = ['A'..'Z', '0'..'9', '_', '+', '-','$','*'];
  279. begin
  280. if UCh in Symchars then
  281.   begin
  282.   GetSymbol := True;
  283.   S[0] := Chr(0);
  284.   while UCh in Symchars do
  285.     begin
  286.     if Ord(S[0]) < Symbolleng then S := S+UCh;
  287.     GetCh;
  288.     end
  289.   end
  290. else GetSymbol := False;
  291. end;
  292. {$v-}
  293.  
  294. {-------------GetAddress}
  295. FUNCTION GetAddress : Boolean;
  296. Var Result : Boolean;
  297.   SaveChi : Integer;
  298. begin
  299. Result := False; SaveChi := Chi;
  300. if GetExpr(Segm) then
  301.   begin
  302.   SkipSpaces;
  303.   if UCh = ':' then
  304.     begin
  305.     GetCh; SkipSpaces;
  306.     Result := GetExpr(NValue);
  307.     end;
  308.   end;
  309. GetAddress := Result;
  310. if not Result then
  311.   begin Chi := SaveChi-1; GetCh; end;
  312. end;
  313.  
  314. {-------------ErrNull}
  315. PROCEDURE ErrNull;
  316. begin Error(Chi, ''); end;
  317.  
  318. {-------------ErrIncorrect}
  319. PROCEDURE ErrIncorrect;
  320. begin Error(Chi, 'Incorrect or No Operand'); end;
  321.  
  322. {-------------SegmErr}
  323. PROCEDURE SegmErr;
  324. begin Error(Chi, 'Segm Reg not Permitted'); end;
  325.  
  326. {-------------WordReg}
  327. PROCEDURE WordReg;
  328. begin Error(Chi, 'Word Reg Exp'); end;
  329.  
  330. {-------------DataLarge}
  331. PROCEDURE DataLarge;
  332. begin Error(Chi, 'Data Too Large'); end;
  333.  
  334. {-------------Chk_BwPtr}
  335. PROCEDURE Chk_BwPtr;
  336. begin
  337. if ByWord >= DwPtr then Error(Chi, 'BYTE or WORD Req''d');
  338. end;
  339.  
  340. {-------------ByteSize}
  341. FUNCTION ByteSize(Val : Integer) : Boolean;
  342.   {return true if val is a byte}
  343. begin
  344. ByteSize := (Hi(Val) = 0) or (Val and $FF80 = $FF80);
  345. end;
  346.  
  347. {-------------ShortSize}
  348. FUNCTION ShortSize(Val : Integer) : Boolean;
  349.     {return true if val is ShortInt size}
  350. begin
  351. ShortSize := (Val >= -128) and (Val <= 127);
  352. end;
  353.  
  354. {-------------ReadByte}
  355. FUNCTION ReadByte : Boolean;
  356. Var Rb : Boolean;
  357. begin
  358. Rb := GetExpr(NValue);
  359. if Rb then
  360.   if ByteSize(NValue) then
  361.     Byt := Lo(NValue)
  362.   else DataLarge;
  363. ReadByte := Rb;
  364. end;
  365.  
  366. {-------------MatchSt}
  367. FUNCTION MatchSt(Var Table; Size, Maxindx : Integer; Var Indx : Integer) :
  368.   Boolean;                  {see if str8 matches any string in a table}
  369. Var Ca : Array[0..MaxInt] of Char Absolute Table;
  370.   Rslt : Boolean;
  371.  
  372.   FUNCTION EqArray(Var A1; N : Integer) : Boolean;
  373.   Type Bigarray = Array[1..MaxInt] of Char;
  374.   Var
  375.     B1 : Bigarray Absolute A1;
  376.     I : Integer;
  377.   begin
  378.   for I := 1 to N do
  379.     if B1[I] <> Str8[I] then
  380.       begin EqArray := False; Exit; end;
  381.   EqArray := Str8[N+1] = ' '; {must have blank on end for complete match}
  382. end;
  383.  
  384. begin
  385. Indx := 0; Rslt := False;
  386. while (Indx <= Maxindx) and not Rslt do
  387.   if EqArray(Ca[Indx*Size], Size) then
  388.     Rslt := True
  389.   else
  390.     Indx := Indx+1;
  391. MatchSt := Rslt;
  392. end;
  393.  
  394. {-------------GetString}
  395. PROCEDURE GetString;
  396.   {Fill in lsid, str8, str, id2,id3.  They are, in fact, all in the
  397.    same locations}
  398. Var I : Integer;
  399. begin
  400. SkipSpaces;
  401. Lsid := '          ';
  402. I := 1;
  403. if (UCh >= 'A') and (UCh <= 'Z') then
  404.   begin
  405.   while (UCh >= 'A') and (UCh <= 'Z') or (UCh >= '0') and (UCh <= '9') do
  406.     begin
  407.     if I <= Symbolleng then
  408.       begin Lsid[I] := UCh; I := I+1; end;
  409.     GetCh;
  410.     end;
  411.   end;
  412. Lsid[0] := Chr(I-1);
  413. Move(Lsid[1], Str8, 9);     {Fill in str8,str,id2,id3}
  414. end;
  415.  
  416. {-------------InsertChr}
  417. PROCEDURE InsertChr(C : Char);
  418. begin
  419. if Tindex < Maxbyte then
  420.   begin
  421.   TextArray[Tindex] := C;
  422.   Tindex := Tindex+1; Column := Column+1;
  423.   end
  424. else
  425.   begin
  426.   WriteLn('Object Code Overflow!');
  427.   Halt(1);
  428.   end;
  429. end;
  430.  
  431. {-------------InsertStr}
  432. PROCEDURE InsertStr(S : BigString);
  433. Var I : Integer;
  434. begin
  435. for I := 1 to Ord(S[0]) do InsertChr(S[I]);
  436. end;
  437.  
  438. {-------------Hex2}
  439. FUNCTION Hex2(B : Byte) : String4;
  440. Const HexDigs : Array[0..15] of Char = '0123456789ABCDEF';
  441. Var Bz : Byte;
  442. begin
  443. Bz := B and $F; B := B Shr 4;
  444. Hex2 := HexDigs[B]+HexDigs[Bz];
  445. end;
  446.  
  447. {-------------Hex4}
  448. FUNCTION Hex4(W : Integer) : String4;
  449. begin Hex4 := Hex2(Lo(W))+Hex2(Hi(W)); end;
  450.  
  451. {-------------InsertByte}
  452. PROCEDURE InsertByte(B : Byte);
  453. begin
  454. InsertStr('$'+Hex2(B));
  455. ByteCount := ByteCount+1;
  456. LastSlash:=Tindex;
  457. InsertChr('/');
  458. Wait_Already:=False;  {any byte inserted cancels a WAIT}
  459. end;
  460.  
  461. {-------------InsertWord}
  462. PROCEDURE InsertWord(W : Integer);
  463. begin
  464. InsertByte(Lo(W)); InsertByte(Hi(W));
  465. end;
  466.  
  467. {-------------InsertHi_Low}
  468. PROCEDURE InsertHi_Low(W : Integer);
  469.   {insert a word in reverse order}
  470. begin
  471. InsertByte(Hi(W)); InsertByte(Lo(W));
  472. end;
  473.  
  474. {-------------InsertWait}
  475. PROCEDURE InsertWait;
  476. begin  {Insert a 'WAIT' for Fl Pt only if none already input}
  477. if not Wait_Already then InsertByte($9B);
  478. end;
  479.  
  480. {-------------Modify_Byte}
  481. PROCEDURE Modify_Byte(I : Integer; Modify : Byte);
  482.   {Modify an ascii byte string in textarray by adding modify to its value}
  483. Var
  484.   St : String4;
  485.   J : Integer;
  486.  
  487.   FUNCTION HexToByte(I : Integer; Var J : Integer) : Byte;
  488.     {Starting at tindex, i, convert hex to a byte. return j, the tindex where
  489.      byte started}
  490.   Var
  491.     Result, Tmp : Byte;
  492.     K : Integer;
  493.     C : Char;
  494.   Const Hex : set of Char = ['0'..'9', 'A'..'F'];
  495.   begin
  496.   Result := 0;
  497.   while not(TextArray[I] in Hex) do I := I+1; {skip '/' and '$'}
  498.   J := I;
  499.   for K:=I to I+1 do
  500.     begin
  501.     C := TextArray[K];
  502.     if C <= '9' then Tmp := Ord(C)-Ord('0') else Tmp := Ord(C)-Ord('A')+10;
  503.     Result := (Result Shl 4)+Tmp;
  504.     end;
  505.   HexToByte := Result;
  506.   end;
  507.  
  508. begin
  509. St := Hex2(HexToByte(I, J)+Modify);
  510. TextArray[J] := St[1];
  511. TextArray[J+1] := St[2];
  512. end;
  513.  
  514. {-------------DoNext}
  515. PROCEDURE DoNext;
  516. Var TmpCh : Char;
  517.  
  518. begin
  519. OldChi := Chi;
  520. Symbol := False;
  521. if Sym = EOLsym then Exit;  {do nothing}
  522. SkipSpaces;                 {note commas are significant}
  523. if (UCh = Chr(CR)) or (UCh = ';') then Sym := EOLsym
  524. else if UCh = ',' then begin Sym := Comma; GetCh; end
  525. else if (UCh = '>') or (UCh = '<') then
  526.   begin
  527.   TmpCh := UCh; GetCh;
  528.   if not GetSymbol(Symname) then Error(Chi, 'Symbol Name Exp');
  529.   if TmpCh = '<' then Sym := Disp8 else Sym := Disp16;
  530.   Symbol := True;           {disp8/16 is a symbol}
  531.   end
  532. else if GetAddress then
  533.   begin
  534.   if NoAddrs then ErrNull
  535.   else Sym := Address;
  536.   end
  537. else if GetExpr(NValue) then
  538.   begin
  539.   if ByteSize(NValue) then
  540.     Sym := Disp8 else Sym := Disp16;
  541.   end
  542. else if (UCh >= 'A') and (UCh <= 'Z') then
  543.   begin GetString; Symname := Lsid;
  544.   if (Lsid = 'FAR') or (Lsid = 'NEAR') or (Lsid = 'SHORT') then
  545.     Sym := JmpDist
  546.   else if Lsid = 'ST' then Sym := STsym
  547.   else Sym := Identifier;
  548.   end
  549. else if UCh = '+' then begin Sym := Plus; GetCh; end
  550. else if UCh = '[' then begin Sym := LfBrack; GetCh; end
  551. else if UCh = ']' then begin Sym := RtBrack; GetCh; end
  552. else begin Sym := Othersym; GetCh; end;
  553. end;
  554.  
  555. {-------------NextA}
  556. PROCEDURE NextA;            {Get the next item but also process any
  557.                             'WORD' 'BYTE', 'DWORD', 'QWORD',etc 'PTR'}
  558. Type Sizeary = Array[0..4] of String[2];
  559. Var Tmp : PtrType;
  560.   Indx : Integer;
  561. Const Ptrary : Sizeary = ('BY', 'WO', 'DW', 'QW', 'TB');
  562.       Ptrary1 : Array[0..4] of String[5] =
  563.                   ('BYTE','WORD','DWORD','QWORD','TBYTE');
  564.  
  565. begin
  566. DoNext;
  567. if Sym = Identifier then
  568.   begin
  569.   Tmp := BPtr; Indx := 0;
  570.   while (Tmp < UnkPtr) and (Lsid <> Ptrary[Indx]) and (Lsid <>Ptrary1[Indx]) do
  571.     begin
  572.     Tmp := Succ(Tmp); Indx := Indx+1;
  573.     end;
  574.   if Tmp < UnkPtr then
  575.     begin ByWord := Tmp; DoNext; end;
  576.   if Str = 'PTR  ' then DoNext; {ignore 'PTR'}
  577.   end;
  578. end;
  579.  
  580. {-------------Displace_Bytes}
  581. PROCEDURE Displace_Bytes(W : Integer);
  582. Var C : Char;
  583. begin
  584. if Displace then
  585.   with SaveOfs do
  586.     begin
  587.     if Symb then
  588.       begin                 {displacement is a symbol}
  589.       if W = 1 then C := '>' else C := '<';
  590.       InsertStr(C+Sname);
  591.       if Value <> 0 then    {Add it in too, don't reverse bytes}
  592.         InsertStr('+$'+Hex2(Hi(Value))+Hex2(Lo(Value)));
  593.       if W = 1 then ByteCount := ByteCount+2 else ByteCount := ByteCount+1;
  594.       LastSlash:=Tindex;
  595.       InsertChr('/');
  596.       end
  597.     else
  598.       if W = 1 then InsertWord(Value) else InsertByte(Lo(Value));
  599.     end;
  600. end;
  601.  
  602. {-------------Data_Bytes}
  603. PROCEDURE Data_Bytes(WordSize : Boolean);
  604. Var C : Char;
  605. begin
  606. with DataVal do
  607.   begin
  608.   if Symb then
  609.     begin                   {data is a symbol}
  610.     if WordSize then C := '>' else C := '<';
  611.     InsertStr(C+Sname);
  612.     if Value <> 0 then      {add it in too}
  613.       InsertStr('+$'+Hex2(Hi(Value))+Hex2(Lo(Value)));
  614.     if WordSize then ByteCount := ByteCount+2 else ByteCount := ByteCount+1;
  615.     LastSlash:=Tindex;
  616.     InsertChr('/');
  617.     end
  618.   else
  619.     if WordSize then InsertWord(Value) else InsertByte(Lo(Value));
  620.   end;
  621. end;
  622.  
  623. {-------------GetIR}
  624. FUNCTION GetIR : Boolean;
  625. Var Reg : IndxReg;
  626. begin
  627. GetIR := False; Reg := None;
  628. if (Sym = Identifier) and (Lsid[0] = Chr(2)) then
  629.   if ID2 = 'BX' then Reg := BX
  630.   else if ID2 = 'SI' then Reg := SI
  631.   else if ID2 = 'DI' then Reg := DI
  632.   else if ID2 = 'BP' then Reg := BP;
  633. if Reg <> None then
  634.   begin
  635.   IRset := IRset+[Reg];
  636.   GetIR := True;
  637.   NextA;
  638.   end;
  639. end;
  640.  
  641. {-------------MemReg}
  642. FUNCTION MemReg(Var W : Integer) : Boolean;
  643. Label 10;
  644.  
  645.   {Does not handle the 'reg' part of the mem/reg. Returns disp true if
  646.   a displacement is found with w=0 for byte disp and w=1 for word
  647.   disp.  Any displacement is output in saveofs.}
  648.  
  649. Var
  650.   SaveChi : Integer;
  651.   Dsp16, OldAddrs, Result_MemReg : Boolean;
  652. begin
  653. SaveChi := OldChi; Dsp16 := False;
  654. Result_MemReg := False;
  655. OldAddrs := NoAddrs; NoAddrs := True;
  656. SaveOfs.Value := 0; SaveOfs.Symb := False; IRset := [];
  657. while (Sym <> Comma) and (Sym <> EOLsym) do {',' or cr terminate a MemReg}
  658.   begin
  659.   if Sym = LfBrack then
  660.     begin Result_MemReg := True; NextA; end;
  661.   if Sym = Plus then NextA;
  662.   if (Sym = Disp8) or (Sym = Disp16) then
  663.     with SaveOfs do
  664.       begin
  665.       Dsp16 := Dsp16 or (Sym = Disp16);
  666.       if Symbol then
  667.         begin
  668.         Symb := True; Sname := Symname;
  669.         end
  670.       else Value := Value+NValue;
  671.       NextA;
  672.       end
  673.   else if not GetIR then
  674.     if Sym = RtBrack then NextA
  675.     else if Result_MemReg then
  676.       begin Error(Chi, 'Comma or Line End Exp'); NextA; end
  677.     else GOTO 10;           {abort}
  678.   end;
  679. if Result_MemReg then
  680.   begin                     {at least one '[' found}
  681.   if (IRset = []) or (IRset = [BP]) then Rmm := 6
  682.   else if IRset = [BX, SI] then Rmm := 0
  683.   else if IRset = [BX, DI] then Rmm := 1
  684.   else if IRset = [BP, SI] then Rmm := 2
  685.   else if IRset = [BP, DI] then Rmm := 3
  686.   else if IRset = [SI] then Rmm := 4
  687.   else if IRset = [DI] then Rmm := 5
  688.   else if IRset = [BX] then Rmm := 7
  689.   else Error(Chi, 'Bad Register Combination');
  690.  
  691.   NextA;                    {pass over any commas}
  692.   with SaveOfs do
  693.     Dsp16 := Dsp16 or (Symb and (Value <> 0)) or not ShortSize(Value);
  694.   if IRset = [] then
  695.     begin Displace := True; Md := 0; W := 1; end {direct address}
  696.   else if (IRset = [BP]) and not Dsp16 then
  697.     begin Displace := True; Md := 1; W := 0; end {bp must have displ}
  698.   else if (SaveOfs.Value = 0) and not SaveOfs.Symb then
  699.     begin Displace := False; Md := 0; W := 3; end
  700.   else if not Dsp16 then    {8 bit}
  701.     begin Displace := True; Md := 1; W := 0; end
  702.   else begin Displace := True; Md := 2; W := 1; end;
  703.   ModeByte := 64*Md+Rmm;
  704.   end
  705. else
  706. 10: begin                     {not a MemReg}
  707.   Chi := SaveChi-1; GetCh;  {restore as in beginning}
  708.   NextA;
  709.   end;
  710. NoAddrs := OldAddrs;
  711. MemReg := Result_MemReg;
  712. end;
  713.  
  714. {-------------St_St}
  715. FUNCTION St_St : Boolean;   {pick up st,st(i) or st(i),st or just st(i)}
  716. Var Err, Rslt : Boolean;
  717.  
  718.   FUNCTION GetSti_Val : Boolean;
  719.   Var Grslt : Boolean;
  720.   begin
  721.   NextA;
  722.   Grslt := Sym = Disp8;
  723.   if Grslt then
  724.     begin
  725.     Sti_val := NValue;
  726.     Err := ((Sti_val and $F8) <> 0); {check limit of 7}
  727.     NextA;
  728.     end;
  729.   GetSti_Val := Grslt;
  730.   end;
  731.  
  732. begin
  733. Err := False;
  734. Rslt := Sym = STsym;
  735. if Rslt then
  736.   begin
  737.   if GetSti_Val then
  738.     begin
  739.     St_first := False;      {st(i) is first}
  740.     while (Sym = Comma) or (Sym = STsym) do NextA;
  741.     end
  742.   else
  743.     begin
  744.     St_first := True;       {st preceeds st(i)}
  745.     if Sym = Comma then NextA;
  746.     if Sym = STsym then
  747.       begin
  748.       if not GetSti_Val then
  749.         Err := True;
  750.       end
  751.     else Err := True;
  752.     end;
  753.   if Err then ErrNull;
  754.   end;
  755. St_St := Rslt;
  756. end;
  757.  
  758. {-------------FstiOnly}
  759. FUNCTION FstiOnly : Boolean;
  760.   {Fl Pt instructions having only one form using st(i) operand}
  761.   {faddp,fmulp,fsubp,fsubrp,fdivp,fdivrp,ffree,fxch -- 0..7 }
  762. Type Arraytype = Array[0..7] of Word;
  763.   Table = Array[0..7, 0..5] of Char;
  764. Var Indx : Integer;
  765.   Rslt : Boolean;
  766. Const
  767.   Stiary : Arraytype =
  768.        ($DEC0, $DEC8, $DEE8, $DEE0, $DEF8, $DEF0, $DDC0, $D9C8);
  769.   StiOnlyTable : Table = ('FADDP ', 'FMULP ', 'FSUBP ',
  770.        'FSUBRP', 'FDIVP ', 'FDIVRP', 'FFREE ', 'FXCH  ');
  771.  
  772. begin
  773. Rslt := MatchSt(StiOnlyTable, 6, 7, Indx);
  774. if Rslt then
  775.   begin
  776.   NextA;
  777.   if not St_St then
  778.     begin
  779.     if Sym = EOLsym then Sti_val := 1
  780.     else ErrIncorrect;
  781.     end;
  782.   InsertWait;
  783.   InsertHi_Low(Stiary[Indx]+Sti_val);
  784.   end;
  785. FstiOnly := Rslt;
  786. end;
  787.  
  788. {-------------FmemOnly}
  789. FUNCTION FmemOnly : Boolean;
  790.   {Fl Pt instructions having only one form using a memory operand}
  791.   {fldenv,fldcw,fstenv,fstcw,fbstp,fbld,frstor,fsave,fstsw,
  792.   fnsave,fnstcw,fnstenv,fnstsw--0..12 }
  793. Type Arraytype = Array[0..12] of Word;
  794.   Table = Array[0..12, 0..6] of Char;
  795. Var Indx : Integer;
  796.   Rslt : Boolean;
  797. Const
  798.   Memary : Arraytype = (
  799.     $D920, $D928, $D930, $D938, $DF30, $DF20, $DD20, $DD30, $DD38,
  800.     $DD30, $D938, $D930, $DD38);
  801.   MemOnlyTable : Table =
  802.    ('FLDENV ', 'FLDCW  ', 'FSTENV ', 'FSTCW  ', 'FBSTP  ', 'FBLD   ',
  803.     'FRSTOR ', 'FSAVE  ', 'FSTSW  ',
  804.     'FNSAVE ', 'FNSTCW ', 'FNSTENV', 'FNSTSW ');
  805. begin
  806. Rslt := MatchSt(MemOnlyTable, 7, 12, Indx);
  807. if Rslt then
  808.   begin
  809.   NextA;
  810.   if Indx < 9 then InsertWait; {fwait}
  811.   if MemReg(W1) then
  812.     begin
  813.     InsertHi_Low(Memary[Indx]+ModeByte);
  814.     Displace_Bytes(W1);
  815.     end
  816.   else ErrIncorrect;
  817.   end;
  818. FmemOnly := Rslt;
  819. end;
  820.  
  821. {-------------FldType}
  822. FUNCTION FldType : Boolean;
  823.   {Do fld,fst,fstp-- 0..2}
  824. Type
  825.   Arraytype = Array[0..2, DwPtr..UnkPtr] of Word;
  826.   Table = Array[0..2, 0..3] of Char;
  827. Var Indx, Tmp : Integer;
  828.   Rslt : Boolean;
  829. Const
  830.   Fldarray : Arraytype = (
  831.     ($D900, $DD00, $DB28, $D9C0),
  832.     ($D910, $DD10, 0, $DDD0),
  833.     ($D918, $DD18, $DB38, $DDD8));
  834.   Fldtable : Table = ('FLD ', 'FST ', 'FSTP');
  835. begin
  836. Rslt := MatchSt(Fldtable, 4, 2, Indx);
  837. if Rslt then
  838.   begin
  839.   NextA;
  840.   InsertWait;           {fwait}
  841.   if ByWord >= DwPtr then
  842.     Tmp := Fldarray[Indx, ByWord];
  843.   if MemReg(W1) then
  844.     begin
  845.     if (ByWord >= DwPtr) and (ByWord <= TbPtr) then
  846.       begin
  847.       InsertHi_Low(Tmp+ModeByte);
  848.       Displace_Bytes(W1);
  849.       if Tmp = 0 then Error(Chi, 'TBYTE not Permitted');
  850.       end
  851.     else Error(Chi, 'DWORD, QWORD, or TBYTE Req''d');
  852.     end
  853.   else if St_St then
  854.     InsertHi_Low(Tmp+Sti_val)
  855.   else ErrIncorrect;
  856.   end;
  857. FldType := Rslt;
  858. end;
  859.  
  860. {-------------FildType}
  861. FUNCTION FildType : Boolean;
  862.   {do fild,fist,fistp-- 0..2}
  863. Type
  864.   Arraytype = Array[0..2, WPtr..QwPtr] of Word;
  865.   Table = Array[0..2, 0..4] of Char;
  866. Var Indx, Tmp : Integer;
  867.   Rslt : Boolean;
  868. Const
  869.   Fildarray : Arraytype = (
  870.     ($DF00, $DB00, $DF28),
  871.     ($DF10, $DB10, 0),
  872.     ($DF18, $DB18, $DF38));
  873.   Fildtable : Table = ('FILD ', 'FIST ', 'FISTP');
  874. begin
  875. Rslt := MatchSt(Fildtable, 5, 2, Indx);
  876. if Rslt then
  877.   begin
  878.   NextA;
  879.   if MemReg(W1) then
  880.     begin
  881.     if (ByWord >= WPtr) and (ByWord <= QwPtr) then
  882.       begin
  883.       InsertWait;       {fwait}
  884.       Tmp := Fildarray[Indx, ByWord];
  885.       InsertHi_Low(Tmp+ModeByte);
  886.       Displace_Bytes(W1);
  887.       if Tmp = 0 then Error(Chi, 'QWORD not Permitted');
  888.       end
  889.     else Error(Chi, 'WORD, DWORD, or QWORD Req''d');
  890.     end
  891.   else ErrIncorrect;
  892.   end;
  893. FildType := Rslt;
  894. end;
  895.  
  896. {-------------FaddType}
  897. FUNCTION FaddType : Boolean;
  898.   {The fadd,fmul,fcom,fcomp,fsub,fsubr,fdiv,fdivr instructions}
  899. Var Indx : Integer;
  900.   Rslt : Boolean;
  901. Type Table = Array[0..7, 0..4] of Char;
  902. Const Faddtable : Table = ('FADD ', 'FMUL ', 'FCOM ', 'FCOMP',
  903.   'FSUB ', 'FSUBR', 'FDIV ', 'FDIVR');
  904. begin
  905. Rslt := False;
  906. if MatchSt(Faddtable, 5, 7, Indx) then
  907.   begin
  908.   NoAddrs := True;
  909.   Rslt := True;
  910.   NextA;
  911.   InsertWait;           {fwait}
  912.   if MemReg(W1) then
  913.     begin
  914.     if ByWord = DwPtr then InsertByte($D8)
  915.     else if ByWord = QwPtr then InsertByte($DC)
  916.     else Error(Chi, 'DWORD or QWORD Req''d');
  917.     InsertByte(ModeByte+8*Indx);
  918.     Displace_Bytes(W1);
  919.     end
  920.   else if St_St then        {Must be st,st(i) or st(i),st }
  921.     begin
  922.     if St_first or (Indx = 2 {fcom} ) or (Indx = 3 {fcomp} ) then
  923.     InsertByte($D8) else InsertByte($DC);
  924.     ModeByte := $C0+8*Indx+Sti_val;
  925.     if not St_first and (Indx >= 6 {fdiv} ) then
  926.       ModeByte := ModeByte Xor 8; {reverse fdiv,fdivr for not st_first}
  927.     InsertByte(ModeByte);
  928.     end
  929.   else ErrIncorrect;
  930.   end;
  931. FaddType := Rslt;
  932. end;
  933.  
  934. {-------------FiaddType}
  935. FUNCTION FiaddType : Boolean;
  936.   {the fiadd,fimul,ficom,ficomp,fisub,fisubr,fidiv,fidivr instructions}
  937. Type Table = Array[0..7, 0..5] of Char;
  938. Var Indx : Integer;
  939.   Rslt : Boolean;
  940. Const Fiaddtable : Table = ('FIADD ', 'FIMUL ', 'FICOM ', 'FICOMP',
  941.   'FISUB ', 'FISUBR', 'FIDIV ', 'FIDIVR');
  942. begin
  943. Rslt := False;
  944. if MatchSt(Fiaddtable, 6, 7, Indx) then
  945.   begin
  946.   NoAddrs := True;
  947.   Rslt := True;
  948.   NextA;
  949.   if MemReg(W1) then
  950.     begin
  951.     InsertWait;         {fwait}
  952.     if ByWord = DwPtr then InsertByte($DA)
  953.     else if ByWord = WPtr then InsertByte($DE)
  954.     else Error(Chi, 'WORD or DWORD Req''d');
  955.     InsertByte(ModeByte+8*Indx);
  956.     Displace_Bytes(W1);
  957.     end
  958.   else ErrIncorrect;
  959.   end;
  960. FiaddType := Rslt;
  961. end;
  962.  
  963. {-------------Fnoperand}
  964. FUNCTION Fnoperand : Boolean;
  965.   {do the Fl Pt no operand instructions}
  966. Type Table = Array[0..32, 0..6] of Char;
  967. Var Indx : Integer;
  968.   Rslt : Boolean;
  969. Const
  970.   Fnoptable : Table =       {Ordered with fnopcode}
  971.    ('FNOP   ', 'FCHS   ', 'FABS   ', 'FTST   ', 'FXAM   ',
  972.     'FLD1   ', 'FLDL2T ', 'FLDL2E ', 'FLDPI  ', 'FLDLG2 ', 'FLDLN2 ',
  973.     'FLDZ   ', 'F2XM1  ', 'FYL2X  ', 'FPTAN  ', 'FPATAN ', 'FXTRACT',
  974.     'FDECSTP', 'FINCSTP', 'FPREM  ', 'FYL2XP1', 'FSQRT  ', 'FRNDINT',
  975.     'FSCALE ', 'FENI   ', 'FDISI  ', 'FCLEX  ', 'FINIT  ', 'FCOMPP ',
  976.     'FNCLEX ', 'FNDISI ', 'FNENI  ', 'FNINIT ');
  977.  
  978.   Fnopcode : Array[0..32] of Word=
  979.    ($D9D0, $D9E0, $D9E1, $D9E4, $D9E5, $D9E8,
  980.     $D9E9, $D9EA, $D9EB, $D9EC, $D9ED, $D9EE,
  981.     $D9F0, $D9F1, $D9F2, $D9F3, $D9F4, $D9F6,
  982.     $D9F7, $D9F8, $D9F9, $D9FA, $D9FC, $D9FD,
  983.     $DBE0, $DBE1, $DBE2, $DBE3, $DED9,
  984.     $DBE2, $DBE1, $DBE0, $DBE3);
  985.  
  986. begin
  987. Rslt := MatchSt(Fnoptable, 7, 32, Indx);
  988. if Rslt then
  989.   begin
  990.   NextA;
  991.   if Indx < 29 then InsertWait; {fwait}
  992.   InsertHi_Low(Fnopcode[Indx]);
  993.   end;
  994. Fnoperand := Rslt;
  995. end;
  996.  
  997. {-------------Register}
  998. FUNCTION Register(Var R, W : Integer) : Boolean;
  999. Type
  1000.   Regarytype = Array[0..15] of Array[1..2] of Char;
  1001. Const Regarray : Regarytype = (
  1002.   'AL', 'CL', 'DL', 'BL', 'AH', 'CH', 'DH', 'BH',
  1003.   'AX', 'CX', 'DX', 'BX', 'SP', 'BP', 'SI', 'DI');
  1004. Var Result_Reg : Boolean;
  1005. begin
  1006. Result_Reg := False;
  1007. if (Lsid[0] = Chr(2)) and (Sym = Identifier) then
  1008.   begin
  1009.   R := -1;
  1010.   repeat
  1011.     R := R+1;
  1012.   until (R > 15) or (ID2 = Regarray[R]);
  1013.   Result_Reg := R <= 15;
  1014.   if Result_Reg then
  1015.     begin
  1016.     NextA;
  1017.     if Sym = Comma then NextA;
  1018.     end;
  1019.   W := R div 8;             {w=1 for word type register}
  1020.   R := R and 7;
  1021.   end;
  1022. Register := Result_Reg;
  1023. end;
  1024.  
  1025. {-------------SegRegister}
  1026. FUNCTION SegRegister(Var R : Integer) : Boolean;
  1027. Var Result_Segr : Boolean;
  1028. begin
  1029. if (Sym = Identifier) and (Lsid[0] = Chr(2)) then
  1030.   begin
  1031.   Result_Segr := True;
  1032.   if ID2 = 'ES' then R := 0
  1033.   else if ID2 = 'CS' then R := 1
  1034.   else if ID2 = 'SS' then R := 2
  1035.   else if ID2 = 'DS' then R := 3
  1036.   else Result_Segr := False;
  1037.   if Result_Segr then
  1038.     begin
  1039.     NextA;
  1040.     if Sym = Comma then NextA;
  1041.     end;
  1042.   end
  1043. else Result_Segr := False;
  1044. SegRegister := Result_Segr;
  1045. end;
  1046.  
  1047. {-------------Data}
  1048. FUNCTION Data(Var Wd : Boolean) : Boolean;
  1049.   {See if immediate data is present.  Set wd if data found is word size}
  1050. Var SaveChi : Integer;
  1051.   Result : Boolean;
  1052. begin
  1053. Result := False; Wd := False;
  1054. SaveChi := OldChi;
  1055. with DataVal do
  1056.   begin
  1057.   Value := 0; Symb := False;
  1058.   while (Sym = Disp8) or (Sym = Disp16) do
  1059.     begin
  1060.     Result := True;
  1061.     if Symbol then
  1062.       begin
  1063.       Wd := Wd or (Sym = Disp16);
  1064.       Symb := True;
  1065.       Sname := Symname;
  1066.       end
  1067.     else Value := Value+NValue;
  1068.     NextA; if Sym = Plus then NextA;
  1069.     end;
  1070.   Result := (Sym = EOLsym) and Result;
  1071.   Wd := Wd or not ByteSize(Value);
  1072.   end;
  1073. Data := Result;
  1074. if not Result then
  1075.   begin
  1076.   Chi := SaveChi-1; GetCh; NextA;
  1077.   end;
  1078. end;
  1079.  
  1080. {-------------TwoOperands}
  1081. FUNCTION TwoOperands : Boolean;
  1082.   {Handles codes with two operands}
  1083. Label 2;
  1084. Type InsType = (Mov, Adc, Addx, Andx, Cmp, Orx, Sbb, Sub, Xorx, Test, Xchg,
  1085.   Lds, Les, Lea);
  1086.   Nametype = Array[Mov..Lea] of Array[1..5] of Char;
  1087.   Codetype = Array[Mov..Lea] of Byte;
  1088.   Shcodetype = Array[Mov..Test] of Byte;
  1089. Var Inst : InsType;
  1090.   Tmp : Byte;
  1091.  
  1092. Const Instname : Nametype = (
  1093.   'MOV  ', 'ADC  ', 'ADD  ', 'AND  ', 'CMP  ', 'OR   ',
  1094.   'SBB  ', 'SUB  ', 'XOR  ', 'TEST ', 'XCHG ', 'LDS  ',
  1095.   'LES  ', 'LEA  ');
  1096.  
  1097.   Immedop : Codetype = ($C6, $80, $80, $80, $80, $80, $80, $80, $80, $F6, 0,
  1098.     0, 0, 0);
  1099.   Immedreg : Codetype = (0, $10, 0, $20, $38, 8, $18, $28, $30, 0, 0,
  1100.     0, 0, 0);
  1101.   Memregop : Codetype = ($88, $10, 0, $20, $38, 8, $18, $28, $30, $84, $86,
  1102.     $C5, $C4, $8D);
  1103.   Shimmedop : Shcodetype = (0, $14, 4, $24, $3C, $C, $1C, $2C, $34, $A8);
  1104.  
  1105.   FUNCTION ChkSignExt (WordSize: Boolean): Byte; {Thanx to Jim LeMay}
  1106.   begin
  1107.     if (Immedop[Inst]=$80) and WordSize and ShortSize(DataVal.Value) then
  1108.          ChkSignExt:=2            { the sign extension bit }
  1109.     else ChkSignExt:=0;           { no  sign extension bit }
  1110.   end;
  1111.  
  1112. begin TwoOperands := False;
  1113. for Inst := Mov to Lea do
  1114.   if Str = Instname[Inst] then
  1115.     GOTO 2;
  1116. Exit;                         {not found}
  1117. 2:                            {found}
  1118. NoAddrs := True;            {full address not acceptable}
  1119. TwoOperands := True;
  1120. NextA;
  1121. if Register(Reg1, W1) then
  1122.   begin
  1123.   if Register(Reg2, W2) then
  1124.     begin                   {mov reg,reg}
  1125.     if Inst >= Lds then Error(Chi, 'Register not Permitted');
  1126.     if W1 <> W2 then Error(Chi, 'Registers Incompatible');
  1127.     if (Inst = Xchg) and ((W1 = 1) and ((Reg1 = 0) or (Reg2 = 0))) then
  1128.       InsertByte($90+Reg1+Reg2)
  1129.     else
  1130.       begin
  1131.       InsertByte(Memregop[Inst]+W1);
  1132.       InsertByte($C0+Reg1+8*Reg2);
  1133.       end;
  1134.     end
  1135.   else if SegRegister(Reg2) then
  1136.     begin                   {mov reg,segreg}
  1137.     if (W1 = 0) or (Inst <> Mov) then SegmErr;
  1138.     InsertByte($8C); InsertByte($C0+8*Reg2+Reg1);
  1139.     end
  1140.   else if Data(WordSize) then
  1141.     begin                   {mov reg,data}
  1142.     if Inst >= Xchg then Error(Chi, 'Immediate not Permitted');
  1143.     if (Ord(WordSize) > W1) then DataLarge;
  1144.     SignExt := ChkSignExt(W1=1);  {the sign extension bit}
  1145.     if (Inst = Mov) then
  1146.       begin
  1147.       InsertByte($B0+8*W1+Reg1);
  1148.       end
  1149.     else
  1150.       if (Reg1 = 0) {ax or al} then
  1151.         begin
  1152.         InsertByte(Shimmedop[Inst]+W1); {add ac,immed}
  1153.         SignExt := 0;                   {no sign extenstion for AL,AX}
  1154.         end
  1155.       else
  1156.         begin
  1157.         InsertByte(Immedop[Inst]+W1+SignExt);
  1158.         InsertByte($C0+Immedreg[Inst]+Reg1);
  1159.         end;
  1160.     Data_Bytes((SignExt = 0) and (W1 > 0));     {output the immediate data}
  1161.     end
  1162.   else if MemReg(W2) then
  1163.     begin                   {mov reg,mem/reg}
  1164.     if (Inst = Mov) and (Reg1 = 0) {ax or al} and (Rmm = 6) and (Md = 0) then
  1165.       begin                 {mov ac,mem}
  1166.       InsertByte($A0+W1);
  1167.       end
  1168.     else
  1169.       begin
  1170.       Tmp := Memregop[Inst];
  1171.       if Inst <= Xchg then
  1172.         begin
  1173.         Tmp := Tmp+W1;
  1174.         if Inst <> Test then Tmp := Tmp or 2; {to,from bit}
  1175.         end;
  1176.       InsertByte(Tmp);
  1177.       InsertByte(ModeByte+8*Reg1);
  1178.       end;
  1179.     Displace_Bytes(W2);     {add on any displacement bytes}
  1180.     end
  1181.   else ErrNull;
  1182.   end
  1183. else if SegRegister(Reg1) then
  1184.   begin
  1185.   if Inst <> Mov then SegmErr;
  1186.   InsertByte($8E);
  1187.   if Register(Reg2, W2) then
  1188.     begin                   {mov segreg,reg}
  1189.     if (W2 = 0) then WordReg;
  1190.     InsertByte($C0+8*Reg1+Reg2);
  1191.     end
  1192.   else if MemReg(W2) then
  1193.     begin                   {mov segreg,mem/reg}
  1194.     InsertByte(ModeByte+8*Reg1);
  1195.     Displace_Bytes(W2);     {add any displacement bytes}
  1196.     end
  1197.   else ErrNull;
  1198.   end
  1199. else if MemReg(W1) and (Inst <= Xchg) then
  1200.   begin
  1201.   if Register(Reg2, W2) then
  1202.     begin                   {mov mem/reg,reg}
  1203.     if (W2 > Ord(ByWord)) then Error(Chi, 'Byte Reg Exp');
  1204.     if (Inst = Mov) and (Reg2 = 0) {ax or al} and (Rmm = 6) and (Md = 0) then
  1205.       begin                 {mov ac, mem}
  1206.       InsertByte($A2+W2);
  1207.       end
  1208.     else
  1209.       begin
  1210.       InsertByte(Memregop[Inst]+W2);
  1211.       InsertByte(ModeByte+8*Reg2);
  1212.       end;
  1213.     Displace_Bytes(W1);
  1214.     end
  1215.   else if SegRegister(Reg2) then
  1216.     begin                   {mov mem/reg,segreg}
  1217.     if (Inst <> Mov) then SegmErr;
  1218.     InsertByte($8C); InsertByte(ModeByte+8*Reg2);
  1219.     Displace_Bytes(W1);
  1220.     end
  1221.   else if (Data(WordSize)) and (Inst < Xchg) then
  1222.     begin                   {mov mem/reg, data}
  1223.     Chk_BwPtr;
  1224.     if (Ord(WordSize) > Ord(ByWord)) then DataLarge;
  1225.     SignExt := ChkSignExt(ByWord=WPtr);   {the sign extension bit}
  1226.     InsertByte(Immedop[Inst]+Ord(ByWord)+SignExt);
  1227.     InsertByte(ModeByte+Immedreg[Inst]);
  1228.     Displace_Bytes(W1);     {add displacement bytes}
  1229.     Data_Bytes((SignExt=0) and (ByWord = WPtr)); {the immediate data}
  1230.     end
  1231.   else ErrNull;
  1232.   end
  1233. else if (Sym = Disp8) or (Sym = Disp16) then
  1234.   Error(Chi, 'Immediate not Permitted')
  1235. else ErrNull;
  1236. end;
  1237.  
  1238. {-------------OneOperand}
  1239. FUNCTION OneOperand : Boolean;
  1240.   {Handles codes with one operand}
  1241. Type InsType = (Dec, Inc, Push, Pop, Nott, Neg);
  1242.   Nametype = Array[Dec..Neg] of Array[1..5] of Char;
  1243.   Codetype = Array[Dec..Neg] of Byte;
  1244. Var Inst : InsType;
  1245.   Pushpop : Boolean;
  1246.  
  1247. Const
  1248.   Instname : Nametype = (
  1249.      'DEC  ', 'INC  ', 'PUSH ', 'POP  ', 'NOT  ', 'NEG  ');
  1250.  
  1251.   Regop : Codetype = ($48, $40, $50, $58, 0, 0);
  1252.   Segregop : Codetype = (0, 0, 6, 7, 0, 0);
  1253.   Memregop : Codetype = ($FE, $FE, $FF, $8F, $F6, $F6);
  1254.   Memregcode : Codetype = ($8, 0, $30, 0, $10, $18);
  1255.  
  1256. begin OneOperand := False;
  1257. for Inst := Dec to Neg do
  1258.   if Str = Instname[Inst] then
  1259.     begin
  1260.     Pushpop := (Inst = Push) or (Inst = Pop);
  1261.     NoAddrs := True;
  1262.     OneOperand := True;
  1263.     NextA;
  1264.     if Register(Reg1, W1) then
  1265.       begin
  1266.       if (W1 = 1) and (Inst < Nott) then
  1267.         begin               {16 bit register instructions}
  1268.         InsertByte(Regop[Inst]+Reg1);
  1269.         end
  1270.       else begin            {byte register or neg,not with any reg}
  1271.       InsertByte(Memregop[Inst]+W1);
  1272.       InsertByte($C0+Memregcode[Inst]+Reg1);
  1273.       if Pushpop then
  1274.         WordReg;
  1275.       end
  1276.       end                   {if reg}
  1277.     else if SegRegister(Reg1) then
  1278.       begin                 {segment reg--push,pop only}
  1279.       InsertByte(Segregop[Inst]+8*Reg1);
  1280.       if not Pushpop then SegmErr
  1281.       end
  1282.     else if MemReg(W1) then
  1283.       begin                 {memreg  (not register)}
  1284.       if not Pushpop then Chk_BwPtr;
  1285.       InsertByte(Memregop[Inst] or Ord(ByWord));
  1286.       InsertByte(ModeByte+Memregcode[Inst]);
  1287.       Displace_Bytes(W1);
  1288.       end
  1289.     else ErrIncorrect;
  1290.     end;                    {if st}
  1291. end;
  1292.  
  1293. {-------------NoOperand}
  1294. FUNCTION NoOperand : Boolean;
  1295.   {Those instructions consisting only of opcode}
  1296. Const Nmbsop = 31;
  1297. Type Sofield = Array[0..Nmbsop] of Array[1..5] of Char;
  1298.   Opfield = Array[0..Nmbsop] of Byte;
  1299. Var Index : Integer;
  1300. Const
  1301.   Sop : Sofield = (
  1302.     'DAA  ', 'AAA  ', 'NOP  ', 'MOVSB', 'MOVSW', 'CMPSB', 'CMPSW',
  1303.     'XLAT ', 'HLT  ',
  1304.     'CMC  ', 'DAS  ', 'AAS  ', 'CBW  ', 'CWD  ', 'PUSHF',
  1305.     'POPF ', 'SAHF ', 'LAHF ', 'STOSB', 'STOSW', 'LODSB', 'LODSW',
  1306.     'SCASB', 'SCASW', 'INTO ', 'IRET ', 'CLC  ', 'STC  ', 'CLI  ',
  1307.     'STI  ', 'CLD  ', 'STD  ');
  1308.   Opcode : Opfield = (
  1309.     $27, $37, $90, $A4, $A5, $A6, $A7, $D7, $F4,
  1310.     $F5, $2F, $3F, $98, $99, $9C, $9D, $9E, $9F, $AA, $AB, $AC, $AD,
  1311.     $AE, $AF, $CE, $CF, $F8, $F9, $FA, $FB, $FC, $FD);
  1312.  
  1313. begin NoOperand := False;
  1314. for Index := 0 to Nmbsop do
  1315.   if Str = Sop[Index] then
  1316.     begin
  1317.     InsertByte(Opcode[Index]);
  1318.     NoOperand := True;
  1319.     NextA;
  1320.     Exit;
  1321.     end;
  1322. end;
  1323.  
  1324. {-------------Prefix}
  1325. FUNCTION Prefix : Boolean;
  1326.   {process the prefix instructions}
  1327. Const Nmbsop = 11;
  1328. Type Field = Array[0..Nmbsop] of String5;
  1329.   Opfield = Array[0..Nmbsop] of Byte;
  1330. Var Index : Integer;
  1331.     SaveWait : Boolean;
  1332.     Opc : Byte;
  1333. Const
  1334.   Ops : Field = (
  1335.     'LOCK ', 'REP  ', 'REPZ ',
  1336.     'REPNZ', 'REPE ', 'REPNE', 'WAIT ', 'FWAIT',
  1337.     'ES   ', 'DS   ', 'CS   ', 'SS   ');
  1338.   Opcode : Opfield = (
  1339.     $F0, $F2, $F3, $F2, $F3, $F2, $9B, $9B, $26, $3E, $2E, $36);
  1340.  
  1341. begin Prefix := False;
  1342. for Index := 0 to Nmbsop do
  1343.   if Str = Ops[Index] then
  1344.     begin
  1345.     Opc:=Opcode[Index];
  1346.     SaveWait := Wait_Already;  {save any WAIT already programed}
  1347.     InsertByte(Opc);
  1348.     Wait_Already:=SaveWait or (Opc=$9B); {set for WAIT or FWAIT}
  1349.     Tindex0 := Tindex;      {for future fix ups}
  1350.     if UCh = ':' then GetCh; {es: etc permitted with a colon}
  1351.     Prefix := True;
  1352.     Exit;
  1353.     end;
  1354. end;
  1355.  
  1356. {-------------FindLabel}
  1357. FUNCTION FindLabel(Var B : Integer) : Boolean;
  1358.   {Find a label if it exists in the label chain}
  1359. Var Found : Boolean;
  1360. begin
  1361. Pl := Firstlabel; Found := False;
  1362. while (Pl <> Nil) and not Found do
  1363.   with Pl^ do
  1364.     if Symname = Name then
  1365.       begin
  1366.       Found := True;
  1367.       B := ByteCnt;
  1368.       end
  1369.     else Pl := Next;
  1370. FindLabel := Found;
  1371. end;
  1372.  
  1373. {-------------ShortJmp}
  1374. FUNCTION ShortJmp : Boolean;
  1375.   {short jump instructions}
  1376. Const Numjmp = 34;
  1377. Type
  1378.   Sjfield = Array[0..Numjmp] of Array[1..5] of Char;
  1379.   Opfield = Array[0..Numjmp] of Byte;
  1380. Var I, B : Integer;
  1381. Const
  1382.   Jumps : Sjfield = (
  1383.     'JO   ', 'JNO  ', 'JB   ', 'JNAE ', 'JNB  ', 'JAE  ',
  1384.     'JE   ', 'JZ   ', 'JNE  ', 'JNZ  ', 'JBE  ', 'JNA  ',
  1385.     'JNBE ', 'JA   ', 'LOOPN', 'LOOPZ', 'LOOPE', 'LOOP ',
  1386.     'JCXZ ', 'JS   ', 'JNS  ', 'JP   ', 'JPE  ', 'JNP  ',
  1387.     'JPO  ', 'JL   ', 'JNGE ', 'JNL  ', 'JGE  ', 'JLE  ',
  1388.     'JNG  ', 'JNLE ', 'JG   ', 'JC   ', 'JNC  ');
  1389.  
  1390.   Opcode : Opfield = (
  1391.     $70, $71, $72, $72, $73, $73, $74, $74, $75, $75, $76, $76,
  1392.     $77, $77, $E0, $E1, $E1, $E2, $E3, $78, $79, $7A, $7A, $7B,
  1393.     $7B, $7C, $7C, $7D, $7D, $7E, $7E, $7F, $7F, $72, $73);
  1394.  
  1395. begin ShortJmp := False;
  1396. for I := 0 to Numjmp do
  1397.   if Str = Jumps[I] then
  1398.     begin
  1399.     InsertByte(Opcode[I]);
  1400.     ShortJmp := True;
  1401.     NoAddrs := True;
  1402.     NextA;
  1403.     if Sym = Identifier then
  1404.       begin
  1405.       if FindLabel(B) then
  1406.         begin
  1407.         Addr := B-(ByteCount+1);
  1408.         if (Addr <= $7F) and (Addr >= -128) then InsertByte(Lo(Addr))
  1409.         else Error(Chi, 'Too Far');
  1410.         end
  1411.       else
  1412.         begin               {enter jump into fixups}
  1413.         New(Pf);
  1414.         with Pf^ do
  1415.           begin
  1416.           Next := Firstfix;
  1417.           if Firstfix <> Nil then
  1418.             Firstfix^.Prev := Pf;
  1419.           Firstfix := Pf;
  1420.           Prev := Nil;
  1421.           Jmptype := Short;
  1422.           Name := Symname;
  1423.           Fix_pt := ByteCount; Indx := Tindex;
  1424.           InsertByte(0);     {dummy insertion}
  1425.           end;
  1426.         end;
  1427.       NextA;
  1428.       end
  1429.     else Error(Chi, 'Label Exp');
  1430.     end;
  1431. end;
  1432.  
  1433. {-------------ShfRot}
  1434. FUNCTION ShfRot : Boolean;
  1435. Type
  1436.   InsType = (Rclx, Rcrx, Rolx, Rorx, Salx, Sarx, Shlx, Shrx);
  1437.   Nametype = Array[Rclx..Shrx] of Array[1..3] of Char;
  1438.   Codetype = Array[Rclx..Shrx] of Byte;
  1439. Var
  1440.   Inst : InsType;
  1441.   CL : Byte;
  1442.  
  1443. Const
  1444.   Instname : Nametype = (
  1445.     'RCL', 'RCR', 'ROL', 'ROR', 'SAL', 'SAR',
  1446.     'SHL', 'SHR');
  1447.  
  1448.   Regcode : Codetype = ($10, $18, 0, 8, $20, $38, $20, $28);
  1449.  
  1450. begin ShfRot := False;
  1451. if Lsid[0] = Chr(3) then
  1452.   for Inst := Rclx to Shrx do
  1453.     if ID3 = Instname[Inst] then
  1454.       begin
  1455.       NoAddrs := True; ShfRot := True;
  1456.       NextA;
  1457.       InsertByte($D0);       {may get modified later}
  1458.       if Register(Reg1, W1) then
  1459.         InsertByte($C0+Regcode[Inst]+Reg1)
  1460.       else if MemReg(W2) then
  1461.         begin
  1462.         Chk_BwPtr;
  1463.         W1 := Ord(ByWord);
  1464.         InsertByte(ModeByte+Regcode[Inst]);
  1465.         Displace_Bytes(W2);
  1466.         end
  1467.       else Error(Chi, 'Reg or Mem Exp');
  1468.       if Sym = Comma then NextA;
  1469.       CL := 0;
  1470.       if (Sym=Identifier) and (ID3 = 'CL ') then CL := 2
  1471.       else if NValue <> 1 then Error(Chi, 'CL or 1 Exp');
  1472.       NextA;
  1473.       Modify_Byte(Tindex0, CL+W1); {modify the opcode}
  1474.       end;
  1475. end;
  1476.  
  1477. {-------------CallJmp}
  1478. FUNCTION CallJmp : Boolean;
  1479. Type InsType = (CALL, JMP);
  1480.   Codetype = Array[CALL..JMP] of Byte;
  1481. Var
  1482.   Inst : InsType;
  1483.   Dist : (Nodist, Long, Shrt, Near);
  1484.   Tmp : Byte;
  1485.   Dwtmp : PtrType;
  1486.   B : Integer;
  1487.   WordSize : Boolean;
  1488.  
  1489. Const
  1490.   Shortop : Codetype = ($E8, $E9);
  1491.   Longop : Codetype = ($9A, $EA);
  1492.   Longcode : Codetype = ($18, $28);
  1493.   Shortcode : Codetype = ($10, $20);
  1494.  
  1495. begin CallJmp := False;
  1496. if Str = 'CALL ' then Inst := CALL
  1497. else if Str = 'JMP  ' then Inst := JMP
  1498. else Exit;
  1499.  
  1500. CallJmp := True;
  1501. NextA;
  1502. Dist := Nodist;
  1503. Dwtmp := ByWord;            {could have passed a 'DWORD PTR' here}
  1504. if Sym = JmpDist then
  1505.   begin
  1506.   if ID2 = 'FA' then Dist := Long
  1507.   else if ID2 = 'NE' then Dist := Near
  1508.   else if ID2 = 'SH' then Dist := Shrt;
  1509.   NextA;
  1510.   end;
  1511. if (Sym = Address) then
  1512.   begin
  1513.   InsertByte(Longop[Inst]);
  1514.   InsertWord(NValue);
  1515.   InsertWord(Segm);
  1516.   end
  1517. else if Register(Reg1, W1) then
  1518.   begin
  1519.   if W1 = 0 then WordReg;
  1520.   if Dist = Long then Error(Chi, 'FAR not Permitted');
  1521.   InsertByte($FF);
  1522.   InsertByte($C0+Shortcode[Inst]+Reg1);
  1523.   end
  1524. else if Sym = Identifier then
  1525.   begin
  1526.   if Dist = Long then Error(Chi, 'Far not Permitted with Label');
  1527.   if FindLabel(B) then
  1528.     begin
  1529.     Addr := B-(ByteCount+2);
  1530.     if Inst = CALL then
  1531.       begin
  1532.       InsertByte($E8);
  1533.       InsertWord(Addr-1);
  1534.       end
  1535.     else
  1536.       if (Addr <= $7F) and (Addr >= -128) and (Dist <> Near) then   {inst=jmp}
  1537.         begin               {short jump}
  1538.         InsertByte($EB); InsertByte(Lo(Addr));
  1539.         end
  1540.       else
  1541.         begin
  1542.         InsertByte($E9); InsertWord(Addr-1);
  1543.         end;
  1544.     end                     {findlabel}
  1545.   else
  1546.     begin                   {enter it into fixup chain}
  1547.     New(Pf);
  1548.     with Pf^ do
  1549.       begin
  1550.       Next := Firstfix;
  1551.       if Firstfix <> Nil then
  1552.         Firstfix^.Prev := Pf;
  1553.       Firstfix := Pf;
  1554.       Prev := Nil;
  1555.       Name := Symname;
  1556.       if Dist = Shrt then
  1557.         begin
  1558.         Jmptype := Short;
  1559.         InsertByte($EB);
  1560.         Fix_pt := ByteCount; Indx := Tindex;
  1561.         InsertByte(0);       {dummy insertion}
  1562.         end
  1563.       else
  1564.         begin
  1565.         Jmptype := Med;
  1566.         if Inst = CALL then InsertByte($E8) else InsertByte($E9);
  1567.         Fix_pt := ByteCount; Indx := Tindex;
  1568.         InsertByte(0);       {dummy insertion}
  1569.         Indx2 := Tindex;
  1570.         InsertByte(0);       {another dummy byte}
  1571.         end;
  1572.       end;
  1573.     end;
  1574.   end                       {identifier}
  1575. else if Data(WordSize) then
  1576.   begin  {Direct CALL or JMP}
  1577.   if (Inst=JMP) and (Dist=Shrt) then
  1578.     begin
  1579.     if WordSize then Error(Chi,'Must be byte size');
  1580.     InsertByte($EB);
  1581.     Data_Bytes(False);
  1582.     end
  1583.   else
  1584.     begin
  1585.     if not ((Dist=Nodist) or (Dist=Near)) or (Dwtmp<>UnkPtr) then
  1586.       Error(Chi, 'Only NEAR permitted');
  1587.     if not WordSize then Error(Chi, 'Must be word size');
  1588.     InsertByte(Shortop[Inst]);
  1589.     Data_Bytes(True);
  1590.     end;
  1591.   end
  1592. else if MemReg(W1) then
  1593.   begin
  1594.   if (Dist = Long) or (Dwtmp = DwPtr) then Tmp := Longcode[Inst]
  1595.   else Tmp := Shortcode[Inst];
  1596.   InsertByte($FF);
  1597.   InsertByte(ModeByte+Tmp);
  1598.   Displace_Bytes(W1);
  1599.   end
  1600. else ErrNull;
  1601. NextA;
  1602. end;
  1603.  
  1604. {-------------Retrn}
  1605. PROCEDURE Retrn(Far : Boolean);
  1606. begin
  1607. if (Sym = Disp16) or (Sym = Disp8) then
  1608.   begin
  1609.   if Far then InsertByte($CA) else InsertByte($C2);
  1610.   InsertWord(NValue);
  1611.   NextA;
  1612.   end
  1613. else
  1614.   if Far then InsertByte($CB) else InsertByte($C3);
  1615. end;
  1616.  
  1617. {-------------OtherInst}
  1618. FUNCTION OtherInst : Boolean;
  1619. Label 2, 10, 20, 30;
  1620. Type
  1621.   Instsym = (Ret, Retf, Aam, Aad, Inn, Out, Mul, Imul, Divd, Idiv, Int);
  1622.   Nametype = Array[Ret..Int] of Array[1..5] of Char;
  1623. Var Index : Instsym;
  1624.   Tmp : Byte;
  1625. Const Instname : Nametype = (
  1626.   'RET  ', 'RETF ', 'AAM  ', 'AAD  ', 'IN   ', 'OUT  ', 'MUL  ',
  1627.   'IMUL ', 'DIV  ', 'IDIV ', 'INT  ');
  1628.  
  1629.   PROCEDURE MulDiv(B : Byte);
  1630.   Var Wordbit : Integer;
  1631.   begin
  1632.   InsertByte($F6);
  1633.   if Register(Reg2, W2) then
  1634.     begin
  1635.     InsertByte($C0+B+Reg2);
  1636.     Wordbit := W2;
  1637.     end
  1638.   else if MemReg(W2) then
  1639.     begin
  1640.     Chk_BwPtr;
  1641.     Wordbit := Ord(ByWord);
  1642.     InsertByte(ModeByte+B);
  1643.     Displace_Bytes(W2);
  1644.     end
  1645.   else Error(Chi, 'Reg or Mem Exp');
  1646.   Modify_Byte(Tindex0, Wordbit);
  1647.   end;
  1648.  
  1649.   FUNCTION DXreg : Boolean;
  1650.   begin
  1651.   DXreg := False;
  1652.   if Sym = Identifier then
  1653.     if ID2 = 'DX' then
  1654.       begin DXreg := True; NextA; end;
  1655.   end;
  1656.  
  1657.   FUNCTION Accum(Var W : Integer) : Boolean;
  1658.   Var Result_acc : Boolean;
  1659.     {See if next is AL or AX}
  1660.   begin
  1661.   Result_acc := False;
  1662.   if (Sym = Identifier) then
  1663.     begin
  1664.     Result_acc := (ID3 = 'AX ') or (ID3 = 'AL ');
  1665.     if Result_acc then
  1666.       begin
  1667.       if Str[2] = 'X' then W := 1 else W := 0; {word vs byte register}
  1668.       NextA;
  1669.       end;
  1670.     end;
  1671.   Accum := Result_acc;
  1672.   end;
  1673.  
  1674. begin
  1675. OtherInst := False;
  1676. for Index := Ret to Int do
  1677.   if Str = Instname[Index] then GOTO 2;
  1678. Exit;
  1679.  
  1680. 2: OtherInst := True; NextA;
  1681. case Index of
  1682.   Ret : Retrn(False);
  1683.   Retf : Retrn(True);
  1684.   Out : begin
  1685.         if DXreg then InsertByte($EE) {out dx,ac}
  1686.         else if Sym = Disp8 then
  1687.           begin             {out port,ac}
  1688.           InsertByte($E6);
  1689.           InsertByte(Lo(NValue));
  1690.           NextA;
  1691.           end
  1692.         else GOTO 10;
  1693.         if Sym = Comma then NextA;
  1694.         if Accum(W1) then
  1695.           Modify_Byte(Tindex0, W1) {al or ax}
  1696.         else GOTO 20;
  1697.         end;
  1698.   Inn : begin
  1699.         if Accum(W1) then
  1700.           begin
  1701.           if Sym = Comma then NextA;
  1702.           if DXreg then InsertByte($EC+W1) {in ac,dx}
  1703.           else
  1704.             begin
  1705.             if Sym = Disp8 then
  1706.               begin         {in ac,port}
  1707.               InsertByte($E4+W1);
  1708.               InsertByte(Lo(NValue));
  1709.               NextA;
  1710.               end
  1711.             else
  1712. 10:            Error(Chi, 'DX or Port Exp');
  1713.             end
  1714.           end
  1715.         else
  1716. 20:         Error(Chi, 'AX or AL Exp');
  1717.         end;
  1718.   Aam : begin
  1719.         Tmp := $D4;
  1720.         GOTO 30;
  1721.         end;
  1722.   Aad : begin
  1723.         Tmp := $D5;
  1724. 30:     InsertByte(Tmp);
  1725.         InsertByte($A);
  1726.         end;
  1727.   Mul : MulDiv($20);
  1728.   Imul : MulDiv($28);
  1729.   Divd : MulDiv($30);
  1730.   Idiv : MulDiv($38);
  1731.   Int : begin
  1732.         if Sym = Disp8 then
  1733.           begin
  1734.           if NValue = 3 then InsertByte($CC)
  1735.           else
  1736.             begin
  1737.             InsertByte($CD);
  1738.             InsertByte(Lo(NValue));
  1739.             end;
  1740.           NextA;
  1741.           end
  1742.         else ErrNull;
  1743.         end;
  1744.  end;
  1745. end;
  1746.  
  1747. {-------------GetQuoted}
  1748. FUNCTION GetQuoted(Var Ls : BigString) : Boolean;
  1749. Var SaveChi, K : Integer;
  1750.   Term : Char;
  1751.   Gq : Boolean;
  1752. begin
  1753. SkipSpaces;
  1754. SaveChi := Chi; K := 1;
  1755. Gq := False;
  1756. if (UCh = '''') or (UCh = '"') then
  1757.   begin
  1758.   Term := UCh; GetCh;
  1759.   while (UCh <> Term) and (UCh <> Chr(CR)) do
  1760.     if (UCh <> Chr(CR)) and (K <= BigStringSize) then
  1761.       begin
  1762.       Ls[K] := LCh; K := K+1; GetCh;
  1763.       end;
  1764.   GetCh;                    {pass by term}
  1765.   Gq := not(UCh in ['+', '-', '*', '/']); {else was meant to be expr}
  1766.   end;
  1767. Ls[0] := Chr(K-1);
  1768. if not Gq then
  1769.   begin Chi := SaveChi-1; GetCh; end;
  1770. GetQuoted := Gq;
  1771. end;
  1772.  
  1773. {-------------DataByte}
  1774. PROCEDURE DataByte;
  1775. Var I : Integer;
  1776.   Lst : BigString;
  1777. begin
  1778. repeat
  1779.   if GetQuoted(Lst) then
  1780.     begin
  1781.     for I := 1 to Ord(Lst[0]) do
  1782.       InsertByte(Lo(Ord(Lst[I])));
  1783.     end
  1784.   else
  1785.     if ReadByte then InsertByte(Byt)
  1786.     else begin ErrNull; end;
  1787.   while (UCh = ' ') or (UCh = Chr(Tab)) or (UCh = ',') do GetCh;
  1788. until (UCh = Chr(CR)) or (UCh = ';') or Aerr;
  1789. NextA;
  1790. end;
  1791.  
  1792. {-------------Chk_For_Label}
  1793. PROCEDURE Chk_For_Label;
  1794. Var Dum1,Dum2 : Integer;
  1795. begin
  1796. if not Prefix then          {could be prefix here}
  1797.   begin
  1798.   SkipSpaces;
  1799.   if (Lsid[0] > Chr(0)) and (UCh = ':') then
  1800.     begin                 {label found}
  1801.     Sym := Identifier;
  1802.     if Register(Dum1,Dum2) then Error(Chi, 'Register name used as label')
  1803.     else
  1804.       begin
  1805.       GetCh; Symname := Lsid;
  1806.       Pl := Firstlabel;       {check for duplication of label}
  1807.       while Pl <> Nil do
  1808.         with Pl^ do
  1809.           begin
  1810.           if Symname = Name then Error(Chi, 'Duplicate Label');
  1811.           Pl := Next;
  1812.           end;
  1813.       New(Pl);                {add the label to the label chain}
  1814.       with Pl^ do
  1815.         begin
  1816.         Next := Firstlabel;
  1817.         Firstlabel := Pl;
  1818.         ByteCnt := ByteCount;
  1819.         Name := Symname;
  1820.         end;
  1821.       Pf := Firstfix;         {see if any fixups are required}
  1822.       while Pf <> Nil do
  1823.         with Pf^ do
  1824.           begin
  1825.           if Name = Symname then
  1826.             begin             {remove this fixup from chain}
  1827.             if Pf = Firstfix then
  1828.               Firstfix := Next
  1829.             else Prev^.Next := Next;
  1830.             if Next <> Nil then Next^.Prev := Prev;
  1831.             Dispose(Pf);
  1832.             Addr := ByteCount-(Fix_pt+1);
  1833.             if Jmptype = Short then
  1834.               begin
  1835.               if Addr+$80 <= $FF then Modify_Byte(Indx, Lo(Addr))
  1836.               else Error(Chi, 'Too Far');
  1837.               end
  1838.             else
  1839.               begin           {jmptype=med}
  1840.               Addr := Addr-1;
  1841.               Modify_Byte(Indx, Lo(Addr));
  1842.               Modify_Byte(Indx2, Hi(Addr));
  1843.               end;
  1844.             end;
  1845.           Pf := Next;
  1846.           end;
  1847.       end;                    {label found}
  1848.     GetString;              {for next item to use}
  1849.     end;
  1850.   end                       {neither a label or a prefix}
  1851. else GetString;             {it was a prefix}
  1852. end;
  1853.  
  1854. {-------------Interpret}
  1855. PROCEDURE Interpret;
  1856. begin
  1857. Tindex0 := Tindex;          {opcode position}
  1858. GetString;
  1859. Chk_For_Label;
  1860. while Prefix do             {process any prefix instructions}
  1861.   GetString;
  1862. if Lsid[0] > Chr(0) then
  1863.   begin
  1864.   if not NoOperand then
  1865.   if not OneOperand then
  1866.   if not TwoOperands then
  1867.   if not ShortJmp then
  1868.   if not CallJmp then
  1869.   if not ShfRot then
  1870.   if not OtherInst then
  1871.   if not FaddType then
  1872.   if not Fnoperand then
  1873.   if not FiaddType then
  1874.   if not FldType then
  1875.   if not FmemOnly then
  1876.   if not FildType then
  1877.   if not FstiOnly then
  1878.   if ID3 = 'DB ' then DataByte
  1879.   else if Lsid = 'NEW' then begin NewFnd:=True; NextA; end
  1880.   else if Lsid = 'END' then
  1881.     begin
  1882.     TheEnd := True;
  1883.     NextA;
  1884.     end
  1885.   else Error(Chi, 'Unknown Instruction');
  1886.   end
  1887. else
  1888.   NextA;                 {if not a string find out what}
  1889. if Sym <> EOLsym then Error(Chi, 'End of Line Exp');
  1890. end;
  1891.  
  1892. {-------------Chk_IOerror}
  1893. FUNCTION Chk_IOerror(S : FileString): Integer;
  1894. Var IOerr : Integer;
  1895. begin
  1896. IOerr := IOResult;
  1897. if (IOerr = 2) or (IOerr = 3) then WriteLn('Can''t find ', S)
  1898. else if IOerr <> 0 then WriteLn('I/O Error ', Hex4(IOerr));
  1899. Chk_IOerror := IOerr;
  1900. end;
  1901.  
  1902. {-------------PromptForInput}
  1903. PROCEDURE PromptForInput;
  1904. Var
  1905.   InName,Name : FileString;
  1906.   Err : Integer;
  1907. begin
  1908. {$I-}
  1909. repeat
  1910.   Write('Source Filename [.ASM]: '); ReadLn(InName);
  1911.   if InName='' then Halt;
  1912.   DefaultExtension('ASM', InName, Name);
  1913.   Assign(Inn, InName); Reset(Inn);
  1914.   Err:=Chk_IOerror(InName);
  1915.   if Err>1 then Halt(1);
  1916. until Err=0;
  1917. Write('Object Filename [', Name, '.OBJ]: '); ReadLn(InName);
  1918. if InName='' then InName:=Name;   {Use the same name}
  1919. DefaultExtension('OBJ',InName,Name);
  1920. Assign(Out, InName);
  1921. Rewrite(Out);
  1922. if Chk_IOerror(InName)<>0 then Halt(1);
  1923. {$I+}
  1924. end;
  1925.  
  1926. {-------------CommandInput}
  1927. PROCEDURE CommandInput;
  1928. Var
  1929.   InName,Name : FileString;
  1930. begin
  1931. InName:=ParamStr(1);
  1932. DefaultExtension('ASM', InName, Name);
  1933. {$I-}
  1934. Assign(Inn, InName);
  1935. Reset(Inn);
  1936. if Chk_IOerror(InName)<>0 then Halt(1);
  1937. if ParamCount>=2 then InName:=ParamStr(2)
  1938.   else InName:=Name;             {Use the old name}
  1939. DefaultExtension('OBJ',InName,Name);
  1940. Assign(Out, InName);
  1941. Rewrite(Out);
  1942. if Chk_IOerror(InName)<>0 then Halt(1);
  1943. {$I+}
  1944. end;
  1945.  
  1946. {-------------LabelReport}
  1947. PROCEDURE LabelReport;  {Report any fixups not made and restore heap}
  1948. Var
  1949.   Pftmp : Fixup_Info_Ptr;
  1950.   Pltmp : Label_Info_ptr;
  1951. begin
  1952. Pf := Firstfix;
  1953. while Pf <> Nil do
  1954.   with Pf^ do
  1955.     begin
  1956.     WriteLn('Label not Found-- ', Name);
  1957.     Pftmp := Next;
  1958.     Dispose(Pf);
  1959.     Pf:=Pftmp;
  1960.     end;
  1961. Pl := Firstlabel;
  1962. while Pl <> Nil do
  1963.   begin
  1964.   Pltmp := Pl^.Next;
  1965.   Dispose(Pl);
  1966.   Pl:=Pltmp;
  1967.   end;
  1968. end;
  1969.  
  1970. {-------------Main}
  1971. begin
  1972. Write(Signon1); WriteLn(Signon2);
  1973. if ParamCount >= 1 then CommandInput else PromptForInput;
  1974.  
  1975. Wait_Already:=False;
  1976. NewFnd:=True;
  1977. while NewFnd and not EOF(Inn) do
  1978.   begin
  1979.   NewFnd:=False;
  1980.   Start_Col := 1; TheEnd := False;
  1981.   Tindex := 0;
  1982.   ByteCount := 0;
  1983.   Firstlabel := Nil; Firstfix := Nil;
  1984.   InsertStr('Inline('+^M^J);
  1985.  
  1986.   while not EOF(Inn) and not TheEnd and not NewFnd do
  1987.     begin
  1988.     Aerr := False; NoAddrs := False;
  1989.     ByWord := UnkPtr;
  1990.     Column := 0;
  1991.     ReadLn(Inn, St); Chi := 1; GetCh; Sym := Othersym;
  1992.     SkipSpaces;
  1993.     if UCh<>Chr(CR) then   {skip blank lines}
  1994.       begin
  1995.       InsertStr('  ');
  1996.       Interpret;
  1997.       InsertChr(' ');   {Space for possible ');' fixup}
  1998.       if not NewFnd and not TheEnd then
  1999.         begin
  2000.         while Column < CommentColumn do InsertChr(' ');
  2001.         InsertChr('{');
  2002.         I := 1;
  2003.         while (Column < 124) and (I <= Length(St)) do
  2004.           begin
  2005.           InsertChr(St[I]);
  2006.           I := I+1;
  2007.           end;
  2008.         InsertStr('}'^M^J);
  2009.         end;
  2010.       end;
  2011.     if EOF(Inn) or TheEnd or NewFnd then
  2012.       begin   {Fix up the last '/' inserted}
  2013.       TextArray[LastSlash]:=')';
  2014.       TextArray[Succ(LastSlash)]:=';';
  2015.       InsertStr(^M^J);
  2016.       end;
  2017.     end;
  2018.   LabelReport;       {report any fixups not made and dispose all heap items}
  2019.   for I := 0 to Tindex-1 do Write(Out, TextArray[I]);
  2020.   end;
  2021. Close(Out);
  2022. Close(Inn);
  2023. end.
  2024.