home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / TURBOPAS / TPF.ZIP / TPFSCN.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1985-05-20  |  19.8 KB  |  708 lines

  1. {[B+]}
  2. {*--------------------------*
  3.  | Lexical Scanner, Utility |
  4.  *--------------------------*}
  5.  
  6.  
  7. procedure Symbol_Put(This_Char: Char); {ch to symbol}
  8.     begin
  9.     Sym_Len := Sym_Len + 1;
  10.     Symbol[Sym_Len] := This_Char;
  11.     Get_Char;
  12.     end {symbol_put} ;
  13.  
  14.  
  15. procedure Print_Char; {print ASCII chars not belonging to Pascal}
  16.     begin
  17.     if Write_Col >= Out_Line_Len then Print_Line(Indent + Continue_Spaces);
  18.     if Formatting then Write_A(Ch);
  19.     Get_Char;
  20.     end {print_char} ;
  21.  
  22.  
  23. procedure Scan_Blanks; {scan off blanks in the input}
  24.     begin
  25.     while (Ch = ' ') and not End_File do Get_Char;
  26.     end;
  27.  
  28.  
  29. procedure String_Constant;
  30.  
  31.     var
  32.         String_End: Boolean;
  33.  
  34.     begin
  35.     New_Input_Line := false;
  36.     Symbol_Found := true;
  37.     Sym := Str_Const;
  38.  
  39.     repeat
  40.         if Ch = '#' then
  41.             begin
  42.             Symbol_Put(Ch);
  43.  
  44.             if Ch = '$' then
  45.                 begin
  46.                 Symbol_Put(Ch);
  47.  
  48.                 while Ch in ['0'..'9', 'A'..'F', 'a'..'f'] do
  49.                     Symbol_Put(UpperCase[Ch]);
  50.                 end
  51.             else while Ch in ['0'..'9'] do Symbol_Put(Ch);
  52.             end
  53.         else if Ch = '^' then
  54.             begin
  55.             Symbol_Put(Ch);
  56.             if Ch in ['@'..'_', 'a'..'z'] then Symbol_Put(UpperCase[Ch]);
  57.             end
  58.         else if Ch = '''' then
  59.             begin
  60.             String_End := false;
  61.  
  62.             repeat
  63.                 Symbol_Put(Ch);
  64.                 if Ch = '''' then
  65.                     begin
  66.                     Symbol_Put(Ch);
  67.                     String_End := Ch <> '''';
  68.                     end;
  69.             until New_Input_Line or String_End;
  70.  
  71.             end;
  72.  
  73.         String_End := (Ch <> '#') and (Ch <> '^') and (Ch <> '''');
  74.     until New_Input_Line or String_End;
  75.  
  76.     if not String_End then Abort(Syntax);
  77.     end; {String_Constant}
  78.  
  79.  
  80. procedure Test_Resv_Wrd;
  81.  
  82.     var
  83.         Id: Word_Type;
  84.         Index: 1..No_Res_Words;
  85.         P: 1..Max_Word_Len;
  86.  
  87.     begin {test for reserved word}
  88.  
  89.     if (Sym_Len >= 2) and (Sym_Len <= Max_Word_Len) then
  90.         begin
  91.  
  92.         for P := 1 to Max_Word_Len do
  93.             if P > Sym_Len then Id[P] := ' '
  94.             else Id[P] := LowerCase[Symbol[P]];
  95.  
  96.         with Res_Len[Sym_Len] do
  97.             begin {length index search}
  98.             Index := Low_Index;
  99.  
  100.             while (Resv_Wrd[Index] <> Id) and (Index < Hi_Index) do
  101.                 Index := Index + 1;
  102.  
  103.             end {length index search} ;
  104.  
  105.         if Resv_Wrd[Index] = Id then Sym := Res_Symbol[Index]
  106.         else Sym := Identifier;
  107.         end
  108.     else Sym := Identifier;
  109.     end {test_resv_wrd} ;
  110.  
  111. {*-----------------------------*
  112.  | Identifier or Reserved Word |
  113.  *-----------------------------*}
  114.  
  115.  
  116. procedure Adjust_Spelling;
  117. {
  118. ! Adjust the spelling of the current identifier to the first spelling
  119. ! encountered for the same identifier. Identifiers are matched without
  120. ! regard to case or break-characters. If this is the first appearance of
  121. ! this identifier, the exact spelling is saved for future use. If it is
  122. ! not the first appearance, it is replaced with the spelling from the first
  123. ! appearance.
  124. }
  125.  
  126.     var
  127.         This_Id: Id_Ptr;                {Ref for current id}
  128.         Hash_Base: Hash_Value;          {hash value for this ident}
  129.         This_Piece: String_Block_Index; {current piece of string table}
  130.         This_Char: String_Piece_Index;  {character in current piece}
  131.         J: Line_Index;                  {induction var}
  132.  
  133.  
  134.     function Hash_Ident: Hash_Value; {hash the current identifier}
  135.  
  136.         var
  137.             i: Line_Index;              {induction var}
  138.             H: Hash_Value;              {partial hash value}
  139.  
  140.         begin
  141.         H := 0;
  142.         for i := 1 to Sym_Len do
  143.             if Symbol[i] <> '_' then
  144.                 H := (H * 3 + Ord(UpperCase[Symbol[i]])) mod Hash_Max;
  145.         Hash_Ident := H;
  146.         end; {Hash_Ident}
  147.  
  148.  
  149.     function Same_Ident(P: Id_Ptr): Boolean;
  150.     {
  151.     ! Returns true if the identifier pointed to by p is the same as the
  152.     ! current identifier
  153.     }
  154.  
  155.         var
  156.             i: Integer;                 {induction var on symbol characters}
  157.             J: Integer;                 {count of characters in id}
  158.             This_Piece: String_Block_Index; {current piece of string table}
  159.             This_Char: String_Piece_Index; {current character within the
  160.                                             piece}
  161.  
  162.         begin
  163.  
  164.         if P = nil then Same_Ident := true
  165.         else
  166.             begin
  167.             i := 0;
  168.             J := 0;
  169.             This_Piece := (P^.Start - 1) div String_Block_Size;
  170.             This_Char := (P^.Start - 1) mod String_Block_Size;
  171.  
  172.             repeat
  173.                 if i < Sym_Len then
  174.                     repeat
  175.                         i := i + 1;
  176.                     until (Symbol[i] <> '_') or (i = Sym_Len);
  177.  
  178.                 if J < P^.Len then
  179.                     repeat
  180.                         J := J + 1;
  181.  
  182.                         if This_Char = String_Block_Max then
  183.                             begin
  184.                             This_Piece := This_Piece + 1;
  185.                             This_Char := 0;
  186.                             end
  187.                         else This_Char := This_Char + 1;
  188.                     until (J = P^.Len) or
  189.                           (String_Index[This_Piece]^[This_Char] <> '_');
  190.             until ((J = P^.Len) and (i = Sym_Len)) or
  191.                   (UpperCase[Symbol[i]] <>
  192.                   UpperCase[String_Index[This_Piece]^[This_Char]]);
  193.  
  194.             Same_Ident := (J = P^.Len) and (i = Sym_Len) and
  195.                           ((UpperCase[Symbol[i]] =
  196.                           UpperCase[String_Index[This_Piece]^[This_Char]]) or
  197.                           (Symbol[i] = '_') or
  198.                           (String_Index[This_Piece]^[This_Char] = '_'));
  199.             end;
  200.         end; {Same_Id}
  201.  
  202.     begin
  203.     Hash_Base := Hash_Ident; {hash for current identifier}
  204.     This_Id := Hash_Table[Hash_Base];
  205.  
  206.     while not Same_Ident(This_Id) do This_Id := This_Id^.Next;
  207.  
  208.     if This_Id = nil then
  209.         begin {Add this identifier to the table for future reference}
  210.         new(This_Id);
  211.  
  212.         with This_Id^ do
  213.             begin
  214.             Next := Hash_Table[Hash_Base];
  215.             Hash_Table[Hash_Base] := This_Id;
  216.             Len := Sym_Len;
  217.             Start := String_Top + 1;
  218.             end;
  219.  
  220.         if String_Top = 0 then new(String_Index[0]);
  221.         This_Piece := String_Top div String_Block_Size;
  222.         This_Char := String_Top mod String_Block_Size;
  223.         for J := 1 to Sym_Len do
  224.             begin
  225.             if This_Char = String_Block_Max then
  226.                 begin
  227.                 This_Piece := This_Piece + 1;
  228.                 new(String_Index[This_Piece]);
  229.                 This_Char := 0;
  230.                 end
  231.             else This_Char := This_Char + 1;
  232.             String_Top := String_Top + 1;
  233.             String_Index[This_Piece]^[This_Char] := Symbol[J];
  234.             end;
  235.         end
  236.     else
  237.         with This_Id^ do
  238.             begin
  239.             This_Piece := Start div String_Block_Size;
  240.             This_Char := Start mod String_Block_Size;
  241.             Sym_Len := Len;
  242.             for J := 1 to Len do
  243.                 begin
  244.                 Symbol[J] := String_Index[This_Piece]^[This_Char];
  245.                 if This_Char = String_Block_Max then
  246.                     begin
  247.                     This_Piece := This_Piece + 1;
  248.                     This_Char := 0;
  249.                     end
  250.                 else This_Char := This_Char + 1;
  251.                 end;
  252.             end;
  253.  
  254.     end; {Adjust_Spelling}
  255.  
  256.  
  257. procedure Set_Symbol_Case(Kind: Symbols);
  258.  
  259.     var
  260.         Last_Underscore: Boolean;       {true if last char underscore}
  261.         i, J: Line_Index;               {induction vars}
  262.  
  263.     begin {Convert a reserved word or identifier to the proper case}
  264.     if Kind = Identifier then
  265.         begin
  266.         if Portability_Mode then
  267.             begin
  268.             J := 0;
  269.             Last_Underscore := true;
  270.             for i := 1 to Sym_Len Do
  271.                 if Symbol[i] = '_' then Last_Underscore := true
  272.                 else if Last_Underscore then
  273.                     begin
  274.                     Last_Underscore := false;
  275.                     J := J + 1;
  276.                     Symbol[J] := UpperCase[Symbol[i]];
  277.                     end
  278.                 else
  279.                     begin
  280.                     J := J + 1;
  281.                     Symbol[J] := LowerCase[Symbol[i]];
  282.                     end;
  283.  
  284.             for i := J + 1 to Sym_Len do Symbol[i] := ' ';
  285.             Sym_Len := J;
  286.             end
  287.         else if First_Spelling then Adjust_Spelling
  288.         else if Uc_Idents then
  289.             for i := 1 to Sym_Len do Symbol[i] := UpperCase[Symbol[i]]
  290.         else if Lc_Idents then
  291.             for i := 1 to Sym_Len do Symbol[i] := LowerCase[Symbol[i]];
  292.         end
  293.     else
  294.         begin
  295.         if Uc_Res_Words then
  296.             for i := 1 to Sym_Len do Symbol[i] := UpperCase[Symbol[i]]
  297.         else if Lc_Res_Words then
  298.             for i := 1 to Sym_Len do Symbol[i] := LowerCase[Symbol[i]];
  299.         end;
  300.     end; {Set_Symbol_Case}
  301.  
  302.  
  303. procedure Alpha_Char;
  304.     begin {identifier or reserved word to symbol}
  305.     New_Input_Line := false;
  306.     Symbol_Found := true;
  307.     while Ch in ['A'..'Z', 'a'..'z', '0'..'9', '_'] do Symbol_Put(Ch);
  308.     Test_Resv_Wrd;
  309.     Set_Symbol_Case(Sym);
  310.     end {alpha char} ;
  311.  
  312.  
  313. procedure Numeric_Char;
  314.     begin
  315.     {unsigned number to symbol}
  316.     New_Input_Line := false;
  317.     Symbol_Found := true;
  318.     Sym := Number;
  319.     if Ch = '$' then
  320.         begin {Hexadecimal number}
  321.         Symbol_Put('$');
  322.  
  323.         while Ch in ['0'..'9', 'A'..'F', 'a'..'f'] do
  324.             Symbol_Put(UpperCase[Ch]);
  325.  
  326.         end
  327.     else
  328.         begin
  329.  
  330.         while (Ch >= '0') and (Ch <= '9') do {integer or fractional portion}
  331.             Symbol_Put(Ch);
  332.  
  333.         if Ch = '.' then
  334.             begin
  335.             Symbol_Put(Ch);
  336.  
  337.             if Ch = '.' then
  338.                 begin {actually subrange, must fudge}
  339.                 Sym_Len := Sym_Len - 1; {erase period}
  340.                 Double_Period := true;
  341.                 end
  342.             else
  343.                 while (Ch >= '0') and (Ch <= '9') do Symbol_Put(Ch);
  344.  
  345.             end;
  346.  
  347.         if (Ch = 'E') or (Ch = 'e') then
  348.             begin {exponential portion}
  349.             Symbol_Put('E');
  350.             if (Ch = '+') or (Ch = '-') then {sign} Symbol_Put(Ch);
  351.  
  352.             while (Ch >= '0') and (Ch <= '9') do {characteristic}
  353.                 Symbol_Put(Ch);
  354.  
  355.             end {exponential}
  356.         end;
  357.     end {numeric char} ;
  358.  
  359.  
  360. procedure Special_Char;
  361.     begin {operators or delimiters to symbol}
  362.     Symbol_Found := true; {untrue only for comments}
  363.     New_Input_Line := false;
  364.  
  365.     case Ch of {special symbols}
  366.         '+':
  367.             begin {plus}
  368.             Sym := Plus;
  369.             Symbol_Put(Ch);
  370.             end {plus} ;
  371.  
  372.         '-':
  373.             begin {minus}
  374.             Sym := Minus;
  375.             Symbol_Put(Ch);
  376.             end {minus} ;
  377.  
  378.         '*':
  379.             begin {multiply}
  380.             Sym := Mult;
  381.             Symbol_Put(Ch);
  382.             end {multiply} ;
  383.  
  384.         '/':
  385.             begin {divide}
  386.             Sym := Divide;
  387.             Symbol_Put(Ch);
  388.             end; {divide}
  389.  
  390.         '.':
  391.             begin {subrange or period}
  392.             Sym := Period;
  393.             Symbol_Put(Ch);
  394.             if Double_Period then
  395.                 begin {fudge a subrange}
  396.                 Symbol[2] := '.';
  397.                 Sym_Len := 2;
  398.                 Sym := Subrange;
  399.                 end
  400.             else if Ch = '.' then
  401.                 begin {subrange}
  402.                 Sym := Subrange;
  403.                 Symbol_Put(Ch);
  404.                 end;
  405.             Double_Period := false;
  406.             end {subrange or period} ;
  407.  
  408.         ',':
  409.             begin {comma}
  410.             Sym := Comma;
  411.             Symbol_Put(Ch);
  412.             end {comma} ;
  413.  
  414.         ';':
  415.             begin {semicolon}
  416.             Sym := Semicolon;
  417.             Symbol_Put(Ch);
  418.             end {semicolon} ;
  419.  
  420.         ':':
  421.             begin {becomes, or colon}
  422.             Sym := Colon;
  423.             Symbol_Put(Ch);
  424.             if Ch = '=' then
  425.                 begin {becomes}
  426.                 Sym := Becomes;
  427.                 Symbol_Put(Ch);
  428.                 end {becomes}
  429.             end {becomes, or colon} ;
  430.  
  431.         '=':
  432.             begin {equals}
  433.             Sym := Equal;
  434.             Symbol_Put(Ch);
  435.             end {equals} ;
  436.  
  437.         '<':
  438.             begin {less than, less equal, not equal}
  439.             Sym := Rel_Op;
  440.             Symbol_Put(Ch);
  441.             if (Ch = '=') or (Ch = '>') then Symbol_Put(Ch);
  442.             end {less than, less equal, not equal} ;
  443.  
  444.         '>':
  445.             begin {greater equal, greater than}
  446.             Sym := Rel_Op;
  447.             Symbol_Put(Ch);
  448.             if Ch = '=' then Symbol_Put(Ch);
  449.             end {great than, or great equals} ;
  450.  
  451.         '^':
  452.             begin
  453.             { Determine whether we have the pointer symbol or the start of
  454.               a string constant (like " = ^M^J; ") }
  455.  
  456.             if In_Type_Or_Var_Dcl or
  457.                (Last_Sym in [Identifier, Close_Brack]) then
  458.                 begin {pointer}
  459.                 Sym := Pointer;
  460.                 Symbol_Put(Ch);
  461.                 end
  462.             else String_Constant;
  463.             end;
  464.  
  465.         '''', '#': String_Constant;
  466.  
  467.         ')':
  468.             begin {close parenthesis}
  469.             Sym := Close_Paren;
  470.             Symbol_Put(Ch);
  471.             end {close parenthesis} ;
  472.  
  473.         '[':
  474.             begin {open bracket}
  475.             Sym := Open_Brack;
  476.             Symbol_Put(Ch);
  477.             end {open bracket} ;
  478.  
  479.         ']':
  480.             begin {close bracket}
  481.             Sym := Close_Brack;
  482.             Symbol_Put(Ch);
  483.             end {close bracket} ;
  484.         end; {case}
  485.     end {special_char} ;
  486.  
  487. {*------------------*
  488.  | Start of Comment |
  489.  *------------------*}
  490.  
  491.  
  492. procedure Comment_Char;
  493.  
  494.     var
  495.         Init_Char: Char;                {starting character}
  496.  
  497.     begin {possible start of comment}
  498.  
  499.     if Ch = '(' then
  500.         begin {see if comment or just open paren}
  501.         Init_Char := Ch;
  502.         Symbol_Put(Ch);
  503.  
  504.         if Ch = '*' then
  505.             begin
  506.             Sym_Len := 0;
  507.             Do_Comment(New_Input_Line, Column - 1, Init_Char);
  508.             end
  509.         else
  510.             begin
  511.             Sym := Open_Paren;
  512.             New_Input_Line := false;
  513.             Symbol_Found := true;
  514.             end;
  515.         end
  516.     else Do_Comment(New_Input_Line, Column, Ch);
  517.     end; {Comment_Char}
  518.  
  519. {*---------------------------*
  520.  | Get Next Symbol (get_sym) |
  521.  *---------------------------*}
  522.  
  523.  
  524. procedure Get_Sym;
  525.     begin {extract next basic sym from text}
  526.     Sym_Len := 0;
  527.     Symbol_Found := false;
  528.     Sym_Written := false;
  529.  
  530.     repeat
  531.         if End_File then
  532.             begin
  533.             Sym := Text_End;
  534.             Symbol_Found := true
  535.             end
  536.         else if Ch = ' ' then Scan_Blanks
  537.         else
  538.             begin
  539.  
  540.             case Ch of {lexical analysis}
  541.                 '0'..'9', '$': Numeric_Char;
  542.  
  543.                 'A'..'Z', 'a'..'z', '_': Alpha_Char;
  544.  
  545.                 ')', '*', '/', '+', ',', '-', '.', ':', ';', '<', '=', '>',
  546.                 '[', ']', '^', '''', '#':
  547.                     Special_Char;
  548.  
  549.                 '(', '{': Comment_Char;
  550.  
  551.                 '!', '&', '?', '\', '`', '|', '~', '}', '"', '@': Print_Char;
  552.  
  553.                 else
  554.                     if Formatting and (Ch = Chr(Ff)) then
  555.                         begin
  556.                         Print_Line(0);
  557.                         Print_Char;
  558.                         Space(0);
  559.                         Clear_Breaks;
  560.                         End_Line := true;
  561.                         end
  562.                     else Get_Char;
  563.                 end
  564.             end;
  565.     until Symbol_Found
  566.     end {get_sym} ;
  567.  
  568. {*-------------------------*
  569.  | Parser Utility Routines |
  570.  *-------------------------*}
  571.  
  572.  
  573. procedure Next_Sym;
  574.     begin {output current sym and input next}
  575.  
  576.     if Sym <> Text_End then
  577.         begin {symbol}
  578.         if not Sym_Written then Put_Sym;
  579.         Get_Sym;
  580.         end {symbol}
  581.  
  582.     end {next_sym} ;
  583.  
  584.  
  585. procedure check(Fsym: Set_Of_Syms);
  586.     begin {check if the next symbol is in fsym}
  587.     if not (Sym in Fsym) then Abort(Syntax);
  588.     end; {check}
  589.  
  590.  
  591. procedure Check_Sym(Desired: Symbols);
  592.     begin {abort if current symbol not desired, else next_sym}
  593.     if Sym = Desired then Next_Sym
  594.     else Abort(Syntax);
  595.     end; {Check_Sym}
  596.  
  597.  
  598. procedure Next_On_New_Line(Spacing, Delta: Integer);
  599. {
  600. ! Space "spacing" lines, indent, put new symbol, and increment indent
  601. ! by "delta"
  602. }
  603.     begin
  604.     if (Blank_Lines > 0) or (Current_Line = 0) then Spacing := Spacing - 1;
  605.  
  606.     repeat
  607.         Format_Line(Indent);
  608.         Spacing := Spacing - 1;
  609.     until Spacing < 0;
  610.  
  611.     Indent_Plus(Delta);
  612.     Stat_Indent := Indent;
  613.     Next_Sym;
  614.     end; {Next_On_New_Line}
  615.  
  616.  
  617. procedure Log_Symbol_Start(var Log: Col_Log);
  618.     begin {log the starting loc of the next symbol}
  619.  
  620.     with Log do
  621.         begin
  622.         Log_Char := Char_Count + 1;
  623.         Log_Col := Write_Col + 1;
  624.         Log_Line := Current_Line;
  625.         end;
  626.  
  627.     end; {Log_Symbol_Start}
  628.  
  629. {*--------------------*
  630.  | Statement bunching |
  631.  *--------------------*}
  632.  
  633.  
  634. procedure Bunch(Start: Col_Log; {start of statement}
  635.                 var Success: Boolean);
  636. {
  637. ! Move a statement up to the previous line if it will fit
  638. }
  639.     begin
  640.  
  641.     with Start do
  642.         if Formatting and (Char_Count - Log_Char < Buf_Size) and
  643.            (Char_Count >= Log_Char) and (Log_Line + 1 = Current_Line) and
  644.            (Write_Col - Indent + Log_Col < Out_Line_Len) then
  645.             begin {move it up, adjusting things as we go}
  646.  
  647.             with Unwritten[Log_Char mod Buf_Size] do
  648.                 begin
  649.                 Action_Is := Spaces;
  650.                 Spacing := 1;
  651.                 Write_Col := Write_Col - Indent + Log_Col + 1;
  652.                 end;
  653.  
  654.             Current_Line := Current_Line - 1;
  655.             Success := true;
  656.             end
  657.         else Success := false;
  658.  
  659.     end; {Bunch}
  660.  
  661.  
  662. procedure Bunch_Statement(Start: Col_Log);
  663.  
  664.     var
  665.         Tab_Int: Integer;               {tab interval}
  666.         Next_Tab: Integer;              {next tab location}
  667.  
  668.     begin {see if we can put multiple statements on a line}
  669.     if Formatting then
  670.         with Start do
  671.             begin
  672.             Tab_Int := (Out_Line_Len - Indent) div Stats_Per_Line;
  673.             if Tab_Int = 0 then Tab_Int := 1;
  674.             if Log_Col = Indent + 1 then Log_Col := Indent;
  675.  
  676.             {fudge for start}
  677.  
  678.             Next_Tab := (Log_Col - Indent + Tab_Int - 1) div Tab_Int *
  679.                         Tab_Int + Indent;
  680.  
  681.             if (Next_Tab > Indent) and (Log_Line + 1 = Current_Line) and
  682.                (Char_Count - Log_Char < Buf_Size) and
  683.                (Next_Tab + Write_Col - Indent <= Out_Line_Len) then
  684.                 begin {move up to prior line and fiddle pointers}
  685.  
  686.                 with Unwritten[Log_Char mod Buf_Size] do
  687.                     begin
  688.                     Action_Is := Spaces;
  689.                     Spacing := Next_Tab - Log_Col + 1;
  690.                     end;
  691.  
  692.                 Write_Col := Next_Tab + Write_Col - Indent;
  693.                 Current_Line := Current_Line - 1;
  694.                 end;
  695.             end;
  696.  
  697.     end; {Bunch_Statement}
  698.  
  699.  
  700. procedure Terminal_Semicolon;
  701. {
  702. ! Parse a possible terminal semicolon at the end of a statement. This
  703. ! is done this way to make sure that it gets indented properly
  704. }
  705.     begin
  706.     if (Sym = Semicolon) and not Sym_Written then Put_Sym;
  707.     end; {Terminal_Semicolon}
  708.