home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / INLIN218.ZIP / INLINE.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-03-05  |  53.2 KB  |  2,020 lines

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