home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 300-399 / ff339.lzh / PCQ / Source.lzh / Source / IO.p < prev    next >
Text File  |  1990-03-04  |  20KB  |  960 lines

  1. External;
  2.  
  3. {
  4.     IO.p (of PCQ Pascal)
  5.     Copyright (c) 1989 Patrick Quaid
  6.  
  7.     This module handles the IO of the compiler.  The actual
  8. compilation of the io statements is handled in stanprocs.p
  9. }
  10.  
  11. {$O-}
  12. {$I "Pascal.i"}
  13. {$I "Include/DOS.i" }
  14. {$I "Include/StringLib.i"}
  15. {$I "Include/Exec.i"}
  16.  
  17.  
  18. Function EndOfFile() : Boolean;
  19.  
  20. {
  21.     This just determines when the end of all input has occured.
  22. }
  23.  
  24. begin
  25.     EndOfFile := (InFile = nil) and (not CharBuffed);
  26. end;
  27.  
  28. Procedure AnnounceFile;
  29. begin
  30.     Write('\r\cK', LineNo:5, ' ', InFile^.Name, '\r');
  31. end;
  32.  
  33. Procedure WriteLineNo;
  34. begin
  35.     Write(Chr(13), LineNo:5);
  36. end;
  37.  
  38. Procedure CountLines;
  39.  
  40. { Does the bookkeeping for errors }
  41.  
  42. begin
  43.     if CurrentChar = Chr(10) then begin
  44.     LineNo := Succ(LineNo);
  45.     if Inform then
  46.         if (LineNo and 15) = 0 then
  47.         WriteLineNo;
  48.     end;
  49. end;
  50.  
  51. Procedure EndComment;
  52.     forward;    { It's in this module }
  53.  
  54. Procedure CloseInputFile;
  55.  
  56. { This closes the current input file and restores the saved stuff }
  57.  
  58. var
  59.     TempPtr : FileRecPtr;
  60. begin
  61.     if Inform then begin
  62.     WriteLineNo;
  63.     Writeln;
  64.     end;
  65.     Close(InFile^.PCQFile);
  66.     TempPtr := InFile^.Previous;
  67.     FreeString(InFile^.Name);
  68.     Dispose(InFile);
  69.     InFile := TempPtr;
  70.     if InFile <> nil then begin
  71.     LineNo := InFile^.SaveLine;
  72.     FNStart := InFile^.SaveStart;
  73.     CurrentChar := InFile^.SaveChar;
  74.     if Inform then
  75.         AnnounceFile;
  76.     EndComment;
  77.     end else
  78.     CurrentChar := Chr(0);
  79. end;
  80.  
  81. Procedure Abort;
  82.  
  83. {
  84.     This routine cuts out cleanly.  If you are debugging the
  85. compiler, this is a likely place to put post mortem dumps, like the
  86. one commented out.
  87. }
  88.  
  89. begin
  90.     While InFile <> nil do
  91.     CloseInputFile;
  92.     Close(OutFile);
  93.     Writeln('Compilation Aborted');
  94.     Exit(20);
  95. end;
  96.  
  97. Function OpenInputFile(name : String) : Boolean;
  98.  
  99. { This routine opens a new file record, and a new file.  It also
  100.   saves the state of the File-dependant variables, like LineNo. }
  101.  
  102. var
  103.     TempPtr : FileRecPtr;
  104.     OpenError : Integer;
  105. begin
  106.     New(TempPtr);
  107.     if not ReOpen(name, TempPtr^.PCQFile, 2048) then begin
  108.     Dispose(TempPtr);
  109.     OpenError := IOResult;
  110.     OpenInputFile := False;
  111.     end;
  112.     TempPtr^.Previous := InFile;
  113.     if InFile <> nil then begin
  114.     InFile^.SaveLine := LineNo;
  115.     InFile^.SaveStart := FNStart;
  116.     InFile^.SaveChar  := CurrentChar;
  117.     end;
  118.     LineNo := 1;
  119.     FNStart := 1;
  120.     TempPtr^.Name := AllocString(strlen(name));
  121.     strcpy(TempPtr^.Name, name);
  122.     InFile := TempPtr;
  123.     if EOF(InFile^.PCQFile) then
  124.     CloseInputFile
  125.     else
  126.     Read(Infile^.PCQFile, CurrentChar);
  127.     if Inform then
  128.     AnnounceFile;
  129.     OpenInputFile := True;
  130. end;
  131.  
  132. Function EQFix(x : integer): integer;
  133.  
  134. {
  135.     This helps implement a queue.  In this case it's for the
  136. error queue.
  137. }
  138.  
  139. begin
  140.     if x = -1 then
  141.     EQFix := EQSize
  142.     else
  143.     EQFix := x mod (Succ(EQSize));
  144. end;
  145.  
  146. Procedure Error(ptr : string);
  147.  
  148. {
  149.     This just writes out at most the previous 128 characters or
  150. two lines, then writes the error message passed to it.  If there
  151. are five errors, it aborts.
  152. }
  153.  
  154. var
  155.     index : integer;
  156.     newlines : integer;
  157. begin
  158.     index := EQEnd;
  159.     newlines := 0;
  160.     while (index <> EQStart) and (newlines < 2) do begin
  161.     index := EQFix(index - 1);
  162.     if ErrorQ[EQFix(index - 1)] = chr(10) then
  163.         newlines := newlines + 1;
  164.     end;
  165.  
  166.     if Inform then begin
  167.     write('\n\cK'); { newline, ClrEOL }
  168.     while index <> EQEnd do begin
  169.         if index = ErrorPtr then
  170.         write('\c0;33;40m');  { start highlight for ANSI }
  171.         write(ErrorQ[index]);
  172.         index := EQFix(index + 1);
  173.     end;
  174.     write('\c0;31;40m');  { end highlight }
  175.     writeln;
  176.     write('Line ', lineno, ' ');
  177.     if currfn <> nil then
  178.         write('(', CurrFn^.Name, ')');
  179.     writeln(': ', ptr, '\n');
  180.     end else
  181.     Writeln('Line ', LineNo, ' : ', ptr); { Quiet mode, no surprises }
  182.  
  183.     Inc(errorcount);
  184.     if errorcount > 4 then
  185.     Abort;
  186.     if CheckBreak() then
  187.     Abort;
  188.     if Inform then
  189.     AnnounceFile;
  190. end;
  191.  
  192. Procedure ReadChar;
  193.  
  194. { This is the main link between the lexical analysis stuff and the
  195.   IO stuff.  It sets up CurrentChar and keeps the line count. }
  196. var
  197.     IOError : Integer;
  198. begin
  199.     if CheckBreak() then
  200.     Abort;
  201.     if CharBuffed then begin
  202.     CurrentChar := BuffedChar;
  203.     CharBuffed := False;
  204.     return;
  205.     end;
  206.     if EOF(InFile^.PCQFile) then
  207.     CloseInputFile
  208.     else begin
  209.     Read(InFile^.PCQFile, CurrentChar);
  210.     IOError := IOResult;
  211.     CountLines;
  212.     end;
  213.     EQEnd := EQFix(Succ(EQEnd));
  214.     ErrorQ[EQEnd] := CurrentChar;
  215.     if EQStart = EQEnd then
  216.     EQStart := EQFix(Succ(EQStart));
  217. end;
  218.  
  219. Function NextChar() : Char;
  220. var
  221.     c : Char;
  222. begin
  223.     if not CharBuffed then begin
  224.     c := CurrentChar;
  225.     ReadChar;
  226.     BuffedChar := CurrentChar;
  227.     CurrentChar := c;
  228.     CharBuffed := True;
  229.     end;
  230.     NextChar := BuffedChar;
  231. end;
  232.  
  233. Procedure EndComment;
  234.  
  235. {
  236.     This just eats characters up to the end of a comment.  If
  237. you want nested comments, this is probably the place to do it.
  238. }
  239.  
  240. begin
  241.     while (Currentchar <> '}') and (not EndOfFile()) do
  242.     ReadChar;
  243.     if not EndOfFile() then
  244.     ReadChar;
  245. end;
  246.  
  247. Function GetLabel() : integer;
  248.  
  249. {
  250.     As in all compilers, this just returns a unique serial
  251. number.
  252. }
  253.  
  254. begin
  255.     Inc(NxtLab);
  256.     getlabel := nxtlab;
  257. end;
  258.  
  259. Procedure PrintLabel(lab : integer);
  260.  
  261. {
  262.     This routine prints a label based on a number from the
  263. above procedure.  The prefix for the label can be anything the
  264. assembler accepts - in this case I wanted it similar to the prefix
  265. of the run time library routines.  I didn't realize how ugly it
  266. would look.
  267. }
  268.  
  269. begin
  270.     write(OutFile, '_p%', lab);
  271. end;
  272.  
  273. Function JustFileName(S : String) : String;
  274.  
  275. { returns a string that is the file name part of a path.  It does
  276.   NOT allocate space. }
  277.  
  278. var
  279.     Ptr : String;
  280. begin
  281.     if S^ = Chr(0) then
  282.     JustFileName := S;
  283.     Ptr := String(Integer(S) + strlen(s) - 1);
  284.     while (Ptr^ <> ':') and (Ptr^ <> '/') do begin
  285.     if Ptr = S then
  286.         JustFileName := S;
  287.     Dec(Ptr);
  288.     end;
  289.     Inc(Ptr);
  290.     JustFileName := Ptr;
  291. end;
  292.  
  293. Procedure AddIncludeName(S : String);
  294.  
  295. { Adds the name of an include file to the list, so it won't be
  296.   included again. }
  297.  
  298. var
  299.     Ptr : IncludeRecPtr;
  300. begin
  301.     Ptr := IncludeRecPtr(AllocString(strlen(S) + 5));
  302.     if Ptr = nil then
  303.     Abort;
  304.     strcpy(Adr(Ptr^.Name), S);
  305.     Ptr^.Next := IncludeList;
  306.     IncludeList := Ptr;
  307. end;
  308.  
  309. Function AlreadyIncluded(S : String) : Boolean;
  310.  
  311. { Determines whether a file has been included already }
  312.  
  313. var
  314.     Ptr : IncludeRecPtr;
  315. begin
  316.     Ptr := IncludeList;
  317.     while Ptr <> nil do begin
  318.     if streq(Adr(Ptr^.Name), S) then
  319.         AlreadyIncluded := True;
  320.     Ptr := Ptr^.Next;
  321.     end;
  322.     AlreadyIncluded := False;
  323. end;
  324.  
  325. Procedure DoInclude;
  326.  
  327. {
  328.     The name says it all.  The mechanics of the include
  329. directive are all handled here.
  330. }
  331.  
  332. var
  333.     Ptr : String;
  334. begin
  335.     ReadChar;
  336.     While (CurrentChar <= ' ') and (not EndOfFile()) do
  337.     ReadChar;
  338.     if CurrentChar <> '"' then begin
  339.     Error("Missing Quote");
  340.     EndComment;
  341.     Return;
  342.     end;
  343.     ReadChar;
  344.     Ptr := SymText;
  345.     while CurrentChar <> '"' do begin
  346.     Ptr^ := CurrentChar;
  347.     Inc(Ptr);
  348.     if EndOfFile() then
  349.         Return;
  350.     ReadChar;
  351.     end;
  352.     Ptr^ := Chr(0); { mark then end of the file name }
  353.     ReadChar;        { read the end quote }
  354.     if not AlreadyIncluded(JustFileName(SymText)) then begin
  355.     if OpenInputFile(SymText) then
  356.         AddIncludeName(JustFileName(SymText))
  357.     else begin
  358.         Error("Could not open input file");
  359.         EndComment;
  360.     end;
  361.     end else
  362.     EndComment;
  363. end;
  364.  
  365. Procedure DoComment;
  366.  
  367. {
  368.     This routine implements compiler directives.
  369. }
  370.  
  371.     Procedure DoASM;
  372.     begin
  373.     ReadChar;
  374.     while CurrentChar <> '}' do begin
  375.         Write(OutFile, currentchar);
  376.         if EndOfFile() then begin
  377.         Error("File ended in a comment");
  378.         return;
  379.         end;
  380.         ReadChar;
  381.     end;
  382.     ReadChar;
  383.     Writeln(OutFile);
  384.     end;
  385.  
  386.     Procedure DoOnOff(var Flag : Boolean);
  387.     begin
  388.     ReadChar;
  389.     if CurrentChar = '+' then
  390.         Flag := True
  391.     else if CurrentChar = '-' then
  392.         Flag := False;
  393.     end;
  394.  
  395.     Procedure DoStorage;
  396.     var
  397.     KillChar : Boolean;
  398.     begin
  399.     ReadChar;
  400.     KillChar := True;
  401.     case CurrentChar of
  402.       'X' : StandardStorage := st_external;
  403.       'P' : StandardStorage := st_private;
  404.       'N' : StandardStorage := st_internal;
  405.     else begin
  406.         Error("Unknown storage class");
  407.         KillChar := False;
  408.          end;
  409.     end;
  410.     if KillChar then
  411.         ReadChar;
  412.     end;
  413.  
  414. begin
  415.     readchar;
  416.     if currentchar = '$' then begin
  417.     repeat
  418.         readchar; { either $ or , }
  419.         Case CurrentChar of
  420.           'I' : begin
  421.             DoInclude;
  422.             return;
  423.             end;
  424.           'A' : begin
  425.             DoASM;
  426.             return;
  427.             end;
  428.           'R' : DoOnOff(RangeCheck);
  429.           'O' : DoOnOff(IOCheck);
  430.           'S' : DoStorage;
  431.         else begin
  432.             Error("Unknown Directive");
  433.             EndComment;
  434.             return;
  435.          end;
  436.         end;
  437.         if (CurrentChar <> ',') or EndOfFile then begin
  438.         EndComment;
  439.         return;
  440.         end;
  441.     until false;
  442.     end else
  443.     EndComment;
  444. end;
  445.  
  446. Function Alpha(c : char): boolean;
  447.  
  448. {
  449.     This function answers the eternal question "is this
  450. character an alphabetic character?"  Note that _ is.
  451. }
  452.  
  453. begin
  454.     c := toupper(c);
  455.     Alpha := ((c >= 'A') and (c <= 'Z')) or (c = '_');
  456. end;
  457.  
  458. Function AlphaNumeric(c : char): boolean;
  459.  
  460. {
  461.     Is the character a letter or digit?
  462. }
  463.  
  464. begin
  465.     AlphaNumeric := Alpha(c) or isdigit(c);
  466. end;
  467.  
  468. Procedure Header;
  469.  
  470. {
  471.     This routine references all the run time library routines.
  472. One thing I like about A68k is that the only routines that are
  473. used in the assembly code end up in the object file.  Maybe all
  474. assemblers do it, but I don't know.
  475. }
  476.  
  477. begin
  478.     writeln(OutFile, "* Pascal compiler intermediate assembly program.\n\n");
  479.     writeln(OutFile, "\tSECTION\tPCQMain\n");
  480.     writeln(OutFile, "\tXREF\t_Input");
  481.     writeln(OutFile, "\tXREF\t_Output");
  482.     writeln(OutFile, "\tXREF\t_p%WriteInt");
  483.     writeln(OutFile, "\tXREF\t_p%WriteReal");
  484.     writeln(OutFile, "\tXREF\t_p%WriteChar");
  485.     writeln(OutFile, "\tXREF\t_p%WriteBool");
  486.     writeln(OutFile, "\tXREF\t_p%WriteCharray");
  487.     writeln(OutFile, "\tXREF\t_p%WriteString");
  488.     writeln(OutFile, "\tXREF\t_p%WriteLn");
  489.     writeln(OutFile, "\tXREF\t_p%ReadInt");
  490.     writeln(OutFile, "\tXREF\t_p%ReadReal");
  491.     writeln(OutFile, "\tXREF\t_p%ReadCharray");
  492.     writeln(OutFile, "\tXREF\t_p%ReadChar");
  493.     writeln(OutFile, "\tXREF\t_p%ReadString");
  494.     writeln(OutFile, "\tXREF\t_p%ReadLn");
  495.     writeln(OutFile, "\tXREF\t_p%ReadArb");
  496.     writeln(OutFile, '\tXREF\t_p%FilePtr');
  497.     writeln(OutFile, '\tXREF\t_p%Get');
  498.     writeln(OutFile, '\tXREF\t_p%Put');
  499.     writeln(OutFile, "\tXREF\t_p%dispose");
  500.     writeln(OutFile, "\tXREF\t_p%new");
  501.     writeln(OutFile, "\tXREF\t_p%Open");
  502.     writeln(OutFile, "\tXREF\t_p%WriteArb");
  503.     writeln(OutFile, "\tXREF\t_p%Close");
  504.     writeln(OutFile, "\tXREF\t_p%exit");
  505.     writeln(OutFile, "\tXREF\t_p%lmul");
  506.     writeln(OutFile, "\tXREF\t_p%ldiv");
  507.     writeln(OutFile, "\tXREF\t_p%lrem");
  508.     writeln(OutFile, "\tXREF\t_p%MathBase");
  509.     writeln(OutFile, '\tXREF\t_p%sin');
  510.     writeln(OutFile, '\tXREF\t_p%cos');
  511.     writeln(OutFile, '\tXREF\t_p%sqrt');
  512.     Writeln(OutFile, '\tXREF\t_p%tan');
  513.     Writeln(OutFile, '\tXREF\t_p%atn');
  514.     Writeln(OutFile, '\tXREF\t_p%CheckIO');
  515.     Writeln(OutFile, '\tXREF\t_p%CheckRange\n');
  516.     if mainmode then begin
  517.     writeln(OutFile, "\tXREF\t_p%initialize");
  518.     writeln(OutFile, "\tjsr\t_p%initialize");
  519.     writeln(OutFile, "\tjsr\t_MAIN");
  520.     writeln(OutFile, '\tmoveq.l\t#0,d0');
  521.     writeln(OutFile, "\tjsr\t_p%exit");
  522.     writeln(OutFile, "\trts");
  523.     end
  524. end;
  525.  
  526. Procedure Trailer;
  527.  
  528. {
  529.     This routine is the most important in the compiler
  530. }
  531.  
  532. begin
  533.     writeln(OutFile, "\tEND");
  534. end;
  535.  
  536. Procedure Blanks;
  537.  
  538. {
  539.     blanks() skips spaces, tabs and eoln's.  It handles
  540. comments if it comes across one.
  541. }
  542.  
  543. var
  544.     done : boolean;
  545. begin
  546.     while ((CurrentChar <= ' ') or (CurrentChar = '{')) and
  547.       (not EndOfFile()) do begin
  548.     if CurrentChar = '{' then
  549.         DoComment
  550.     else
  551.         ReadChar;
  552.     end;
  553. end;
  554.  
  555. Procedure DumpLitQ(k : Integer);
  556.  
  557. {
  558.     This procedure dumps the literal table at the end of the
  559. compilation.  Individual components are referenced as offsets to
  560. the literal label.
  561. }
  562.  
  563. var
  564.     j        : integer;
  565.     quotemode    : boolean;
  566. begin
  567.     while k < litptr do begin
  568.     write(OutFile, "\tdc.b\t");
  569.     j := 0;
  570.     quotemode := false;
  571.     while j < 40 do begin
  572.         if (ord(litq[k]) > 31) and (ord(litq[k]) <> 39) then begin
  573.         if quotemode then
  574.             write(OutFile, litq[k])
  575.         else begin
  576.             if j > 0 then
  577.             write(OutFile, ',');
  578.             write(OutFile, chr(39), litq[k]);
  579.             quotemode := true;
  580.         end;
  581.         end else begin
  582.         if quotemode then begin
  583.             write(OutFile, chr(39));
  584.             quotemode := false;
  585.         end;
  586.         if j > 0 then
  587.             write(OutFile, ',');
  588.         write(OutFile, ord(litq[k]));
  589.         if j > 32 then
  590.             j := 40
  591.         else
  592.             j := j + 3;
  593.         end;
  594.         j := j + 1;
  595.         k := k + 1;
  596.         if k >= litptr then
  597.         j := 40;
  598.     end;
  599.     if quotemode then
  600.         write(OutFile, chr(39));
  601.     writeln(OutFile);
  602.     end
  603. end;
  604.  
  605. Procedure DumpLits;
  606. begin
  607.     if LitPtr = 0 then
  608.     return;
  609.     writeln(OutFile, '\n\tSECTION\tLITS,DATA');
  610.     PrintLabel(LitLab);
  611.     DumpLitQ(0);
  612. end;
  613.  
  614. Procedure DumpIds;
  615.  
  616. {
  617.     This routine does whatever is appropriate with the various
  618. identifers.  If it's a global, it either references it or allocates
  619. space.  Similar stuff for the other ids.  When the modularity of
  620. PCQ is better defined, this routine will have to do more work.
  621. }
  622.  
  623. var
  624.     CB        : BlockPtr;
  625.     ID        : IDPtr;
  626.     TP        : TypePtr;
  627.     i        : Integer;
  628.     isodd    : boolean;
  629. begin
  630.     if mainmode then
  631.     writeln(OutFile, "\n\tSECTION\tTHREE,BSS\n");
  632.     isodd := false;
  633.     CB := CurrentBlock;
  634.     while CB <> nil do begin
  635.     for i := 0 to Hash_Size do begin
  636.         ID := CB^.Table[i];
  637.         while ID <> nil do begin
  638.         case ID^.Object of
  639.           global : case ID^.Storage of
  640.                 st_internal,
  641.                 st_private  : begin
  642.                         TP := ID^.VType;
  643.                         if isodd and (TP^.Size > 1) then begin
  644.                         Writeln(OutFile, "\tCNOP\t0,2");
  645.                         isodd := False;
  646.                         end;
  647.                         if ID^.Storage <> st_private then
  648.                         Writeln(OutFile,"\tXDEF\t_", ID^.Name);
  649.                         Write(OutFile, '_', ID^.Name);
  650.                         Writeln(OutFile, "\tds.b\t", TP^.Size);
  651.                         if odd(TP^.Size) then
  652.                         isodd := not isodd;
  653.                       end;
  654.                end;
  655.           proc,
  656.           func  : if ID^.Storage = st_forward then
  657.                 Writeln(ID^.Name, ' was never defined.');
  658.         end;
  659.         ID := ID^.Next;
  660.         end;
  661.     end;
  662.     CB := CB^.Previous;
  663.     end;
  664. end;
  665.  
  666. Procedure DumpRefs;
  667.  
  668. {
  669.     This routine makes all the external references necessary.
  670. }
  671.  
  672. var
  673.     CB        : BlockPtr;
  674.     ID        : IDPtr;
  675.     i        : Integer;
  676. begin
  677.     writeln(OutFile);
  678.     CB := CurrentBlock;
  679.     while CB <> nil do begin
  680.     for i := 0 to Hash_Size do begin
  681.         ID := CB^.Table[i];
  682.         while ID <> nil do begin
  683.         if ID^.Storage = st_external then
  684.             writeln(OutFile, "\tXREF\t_", ID^.Name);
  685.         ID := ID^.Next;
  686.         end;
  687.     end;
  688.     CB := CB^.Previous;
  689.     end
  690. end;
  691.  
  692. Procedure SearchReserved;
  693.  
  694. {
  695.     This just does a binary chop search of the list of reserved
  696. words.
  697. }
  698.  
  699. var
  700.     top,
  701.     middle,
  702.     bottom    : Symbols;
  703.     compare    : Short;
  704. begin
  705.     Bottom := And1;
  706.     Top := LastReserved;
  707.     while Bottom <= Top do begin
  708.     middle := Symbols((Short(bottom) + Short(top)) div 2);
  709.     Compare := stricmp(Reserved[Middle], SymText);
  710.     if Compare = 0 then begin
  711.         CurrSym := Middle;
  712.         Return;
  713.     end else if Compare < 0 then
  714.         Bottom := Succ(Middle)
  715.     else
  716.         Top := Pred(Middle);
  717.     end;
  718.     CurrSym := Ident1;
  719. end;
  720.  
  721. Procedure ReadWord;
  722.  
  723. {
  724.     This reads a Pascal identifier into symtext.
  725. }
  726.  
  727. var
  728.     ptr        : string;
  729. begin
  730.     ptr := symtext;
  731.     repeat
  732.     Ptr^ := CurrentChar;
  733.     Ptr := String(Integer(Ptr) + 1);
  734.     ReadChar;
  735.     until not AlphaNumeric(CurrentChar);
  736.     Ptr^ := chr(0);
  737.     SearchReserved;
  738. end;
  739.  
  740. Function DigVal(c : Char) : Integer;
  741. begin
  742.     DigVal := Ord(c) - Ord('0');
  743. end;
  744.  
  745. Procedure ReadNumber;
  746.  
  747. {
  748.     This routine reads a literal integer.  Note that _ can be used.
  749. }
  750.  
  751. var
  752.     Divider : Real;
  753.     Fraction : Real;
  754. begin
  755.     SymLoc := 0;
  756.     While isdigit(CurrentChar) do begin
  757.     SymLoc := (SymLoc * 10) + DigVal(CurrentChar);
  758.     ReadChar;
  759.     if CurrentChar = '_' then
  760.         ReadChar;
  761.     end;
  762.     CurrSym := Numeral1;
  763.     if (CurrentChar = '.') and isdigit(NextChar()) then begin { It's real! }
  764.     ReadChar; { skip the . }
  765.     RealValue := Float(SymLoc);
  766.     Divider := 1.0;
  767.     Fraction := 0.0;
  768.     while isdigit(CurrentChar) do begin
  769.         Fraction := Fraction * 10.0 + Float(DigVal(CurrentChar));
  770.         Divider := Divider * 10.0;
  771.         ReadChar;
  772.     end;
  773.     RealValue := RealValue + Fraction / Divider;
  774.     CurrSym := RealNumeral1;
  775.     end;
  776. end;
  777.  
  778. Procedure ReadHex;
  779.  
  780. {
  781.     readhex() reads a hexadecimal number.
  782. }
  783.  
  784. var
  785.    rc : integer;
  786. begin
  787.     ReadChar;
  788.     symloc := 0;
  789.     rc := ord(toupper(currentchar));
  790.     while isdigit(currentchar) or
  791.       ((rc >= ord('A')) and (rc <= ord('F'))) do begin
  792.     SymLoc := SymLoc shl 4;
  793.     if isdigit(currentchar) then
  794.         symloc := symloc + ord(currentchar) - ord('0')
  795.     else
  796.         symloc := symloc + rc - ord('A') + 10;
  797.     ReadChar;
  798.     rc := ord(toupper(currentchar));
  799.     end;
  800.     currsym := numeral1;
  801. end;
  802.  
  803. Procedure WriteHex(num : integer);
  804.  
  805. {
  806.     This writes full 32 bit hexadecimal numbers.
  807. }
  808.  
  809. var
  810.     numary  : array [1..8] of char;
  811.     pos     : integer;
  812.     ch      : Short;
  813. begin
  814.     pos := 8;
  815.     while (num <> 0) and (pos > 0) do begin
  816.     ch := num and 15;
  817.     if ch < 10 then
  818.         numary[pos] := chr(ch + ord('0'))
  819.     else
  820.         numary[pos] := chr(ch + ord('A') - 10);
  821.     pos := pos - 1;
  822.     num := num shr 4;
  823.     end;
  824.     if pos = 8 then begin
  825.     pos := 7;
  826.     numary[8] := '0';
  827.     end;
  828.     write(OutFile, '$');
  829.     for num := pos + 1 to 8 do
  830.     write(OutFile, numary[num]);
  831. end;
  832.  
  833. Procedure NextSymbol;
  834.  
  835. {
  836.     This is the workhorse lexical analysis routine.  It sets
  837. currsym to the appropriate symbol number, sets symtext equal to
  838. whatever identifier is read, and symloc to the value of a literal
  839. integer.
  840. }
  841.  
  842. begin
  843.     ErrorPtr := EQEnd;
  844.     Blanks;
  845.     if EndOfFile then begin
  846.     CurrentChar := Chr(0);
  847.     CurrSym := EndText1; { I don't think this routine is ever hit }
  848.     Return;
  849.     end;
  850.     if Alpha(CurrentChar) then
  851.     readword
  852.     else if isdigit(currentchar) then
  853.     readnumber
  854.     else begin
  855.     case CurrentChar of
  856.       '[' : begin
  857.             CurrSym:= leftbrack1;
  858.             ReadChar;
  859.         end;
  860.       ']' : begin
  861.             CurrSym:= rightbrack1;
  862.             ReadChar;
  863.         end;
  864.       '(' : begin
  865.             CurrSym:= leftparent1;
  866.             ReadChar;
  867.         end;
  868.       ')' : begin
  869.             CurrSym:= rightparent1;
  870.             ReadChar;
  871.         end;
  872.       '+' : begin
  873.             CurrSym := plus1;
  874.             ReadChar;
  875.         end;
  876.       '-' : begin
  877.             CurrSym := minus1;
  878.             ReadChar;
  879.         end;
  880.       '*' : begin
  881.             CurrSym:= asterisk1;
  882.             ReadChar;
  883.         end;
  884.       '/' : begin
  885.             CurrSym := RealDiv1;
  886.             ReadChar;
  887.         end;
  888.       '<' : begin
  889.             ReadChar;
  890.             if CurrentChar = '=' then begin
  891.             CurrSym := notgreater1;
  892.             ReadChar;
  893.             end else if currentchar = '>' then begin
  894.             CurrSym := notequal1;
  895.             ReadChar;
  896.             end else
  897.             CurrSym:= less1;
  898.         end;
  899.       '=' : begin
  900.             CurrSym:= equal1;
  901.             ReadChar;
  902.         end;
  903.       '>' : begin
  904.             ReadChar;
  905.             if CurrentChar = '=' then begin
  906.             CurrSym:= notless1;
  907.             ReadChar;
  908.             end else
  909.             CurrSym:= greater1;
  910.         end;
  911.       ':' : begin
  912.             ReadChar;
  913.             if CurrentChar = '=' then begin
  914.             CurrSym:= Becomes1;
  915.             ReadChar;
  916.             end else
  917.             CurrSym:= colon1;
  918.         end;
  919.       ',' : begin
  920.             CurrSym:= comma1;
  921.             ReadChar;    
  922.         end;
  923.       '.' : begin
  924.             ReadChar;
  925.             if CurrentChar = '.' then begin
  926.             CurrSym:= DotDot1;
  927.             ReadChar;
  928.             end else
  929.             CurrSym:= period1;
  930.         end;
  931.       ';' : begin
  932.             CurrSym:= semicolon1;
  933.             ReadChar;
  934.         end;
  935.       '\'': begin
  936.             CurrSym:= apostrophe1;
  937.             ReadChar;
  938.         end;
  939.       '"' : begin
  940.             CurrSym:= quote1;
  941.             ReadChar;
  942.         end;
  943.       '^' : begin
  944.             CurrSym:= carat1;
  945.             ReadChar;
  946.         end;
  947.       '@' : begin
  948.             CurrSym := At1;
  949.             ReadChar;
  950.         end;
  951.       '$' : ReadHex;
  952.      '\0' : CurrSym := EndText1;
  953.     else begin
  954.         Error("Unknown symbol.");
  955.         ReadChar;
  956.          end;
  957.     end; { Case }
  958.     end { Else }
  959. end;
  960.