home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / pcmag / vol6n20.zip / INLINE.ZIP / INLINE.PAS < prev    next >
Pascal/Delphi Source File  |  1987-03-29  |  54KB  |  2,008 lines

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