-- $Header: /cf/ua/arcadia/alex-ayacc/ayacc/src/RCS/source_file_body.a,v 1.1 88/08/08 14:29:03 arcadia Exp $ 

-- Copyright (c) 1990 Regents of the University of California.
-- All rights reserved.
--
--    The primary authors of ayacc were David Taback and Deepak Tolani.
--    Enhancements were made by Ronald J. Schmalz.
--
--    Send requests for ayacc information to ayacc-info@ics.uci.edu
--    Send bug reports for ayacc to ayacc-bugs@ics.uci.edu
--
-- Redistribution and use in source and binary forms are permitted
-- provided that the above copyright notice and this paragraph are
-- duplicated in all such forms and that any documentation,
-- advertising materials, and other materials related to such
-- distribution and use acknowledge that the software was developed
-- by the University of California, Irvine.  The name of the
-- University may not be used to endorse or promote products derived
-- from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

-- Module       : source_file_body.ada
-- Component of : ayacc
-- Version      : 1.2
-- Date         : 11/21/86  12:36:09
-- SCCS File    : disk21~/rschm/hasee/sccs/ayacc/sccs/sxsource_file_body.ada

-- $Header: /cf/ua/arcadia/alex-ayacc/ayacc/src/RCS/source_file_body.a,v 1.1 88/08/08 14:29:03 arcadia Exp $ 
-- $Log:	source_file_body.a,v $
--Revision 1.1  88/08/08  14:29:03  arcadia
--Initial revision
--
-- Revision 0.1  86/04/01  15:12:32  ada
--  This version fixes some minor bugs with empty grammars 
--  and $$ expansion. It also uses vads5.1b enhancements 
--  such as pragma inline. 
-- 
-- 
-- Revision 0.0  86/02/19  18:42:02  ada
-- 
-- These files comprise the initial version of Ayacc
-- designed and implemented by David Taback and Deepak Tolani.
-- Ayacc has been compiled and tested under the Verdix Ada compiler
-- version 4.06 on a vax 11/750 running Unix 4.2BSD.
--  

with Text_IO, Ayacc_File_Names;
use  Text_IO;
package body Source_File is

  SCCS_ID : constant String := "@(#) source_file_body.ada, Version 1.2";



  Rcs_ID : constant String := "$Header: /cf/ua/arcadia/alex-ayacc/ayacc/src/RCS/source_file_body.a,v 1.1 88/08/08 14:29:03 arcadia Exp $";

    Input_File : File_Type;

    Max_Line_Length : constant := 1024;

    type Long_STR is
	record
	    Name   : String(1..Max_Line_Length);
	    Length : Natural := 0;
	end record;

    Current_Line  : Long_STR;
    Previous_Line : Long_STR;
    Column_Number : Natural;   -- column number of current_line.
    Line_Number   : Natural;


    Get_New_Line       : Boolean := True;   
    End_of_Source_File : Boolean := False;



    procedure Open is
	use Ayacc_File_Names;
    begin
	Open(Input_File, In_File, Get_Source_File_Name);
	Current_Line  := ((others => ' '), 0);
	Previous_Line := ((others => ' '), 0);
	Column_Number := 1;
	Line_Number   := 0;
    exception
	when Name_Error | Use_Error =>
	    Put_Line("Ayacc: Error Opening """ & Get_Source_File_Name & """.");
            raise;
    end Open;


    procedure Close is
    begin
	Close(Input_File);
    end Close;


    function Is_End_of_File return Boolean is
    begin
	return End_of_File(Input_File);
    end Is_End_of_File;

    function Source_Line_Number return Natural is
    begin
	return Line_Number;
    end Source_Line_Number;


    function Maximum_Line_Length return Natural is
    begin
      return Max_Line_Length;
    end Maximum_Line_Length;


    procedure Get_Char(Ch: out Character) is
    begin

	if Get_New_Line then
	    Previous_Line := Current_Line;
	    Get_Line(Input_File, Current_Line.Name, Current_Line.Length);
	    Get_New_Line := False;
	    Column_Number := 1;
	    Line_Number := Line_Number + 1;
	end if;

	if Column_Number > Current_Line.Length then
	    if End_of_File(Input_File) then
		Ch := Eof;
		End_of_Source_File := True;
		return;
	    end if;
	    Ch := Eoln;
	    Get_New_Line := True;
	else
	    Ch := Current_Line.Name(Column_Number);
	    Column_Number := Column_Number + 1;
	end if;

    end Get_Char;


    -- Note: You can't correctly peek at next character if the last character
    -- read is a EOLN. It is assumed that the lexical analyzer won't
    -- call this function in that case.
    function Peek_Next_Char return Character is
    begin
	if Column_Number > Current_Line.Length then
	    if End_of_File(Input_File) then
		return Eof;
	    else
		return Eoln;
	    end if;
	end if;
	return Current_Line.Name(Column_Number);
    end Peek_Next_Char;



    procedure Unget_Char(Ch : in Character) is
    begin
	if Get_New_Line then
	    Get_New_Line := False;
	elsif End_of_Source_File then
	    End_of_Source_File := False;
	elsif Column_Number = 1 then
	    Put_Line("Ayacc: Error in Unget_Char, Attempt to 'unget' an EOLN");
	    raise Pushback_Error;
	else
	    Column_Number := Column_Number - 1;
	end if;
    end Unget_Char;



    procedure Print_Context_Lines is
	Ptr_Location : Integer := 0;
    begin

	    --  Print previous line followed by current line  --

	Put(Integer'Image(Line_Number-1) & Ascii.Ht);
	Put_Line(Previous_Line.Name(1..Previous_Line.Length));
	Put(Integer'Image(Line_Number) & Ascii.Ht);
	Put_Line(Current_Line.Name(1..Current_Line.Length));


        --  Correct for any tab characters so that the pointer will
        --  point to the proper location on the source line.
        for I in 1..Column_Number - 1 loop
	    if Current_Line.Name(I) = Ascii.Ht then -- Adjust for tab.
	        Ptr_Location := (((Ptr_Location / 8) + 1) * 8);
	    else
	        Ptr_Location := Ptr_Location + 1;
	    end if;
        end loop;

	Put(Ascii.Ht);
        for I in 1..Ptr_Location - 1 loop
	    Put('-');
        end loop;
        Put('^');

    end Print_Context_Lines;


    procedure Read_Line(Source_Line: out String; Last: out Natural) is
    begin
	Get_Line(Input_File, Source_Line, Last);
	Line_Number := Line_Number + 1;
    end Read_Line;


end Source_File;
