Oracle/Pro*Ada/LSE/DEC Ada utility

From: Gijs Bok <gijs_at_mbase97.hacktic.nl>
Date: Fri, 27 Aug 1993 23:49:12 +0200
Message-ID: <H.eg.3V5A2BYqjAQ_at_mbase97.hacktic.nl>


Hi,
a couple of weeks ago I asked whether people would be interested in the utility I wrote to make Proada work with LSE/VMS/DEC Ada. A few people were interested, so here goes.

I suspect that PRO*X (X is some language) suffers from the same lack of LSE support, so maybe users of another language can port this utility to that language. If anybody does, please let me know.

The main feature is that you can REVIEW Proada errors in LSE, so you can quickly locate erroneous SQL code, without having to examine the .LIS file and looking up the line number.

Other features:
- precompile a .PAD file in LSE with COMPILE. - precompile .PAD-file, load&compile generated Ada code. Review   any errors in Proada or Ada compilation with one command: "PRO".   Ada errors will point you to the Ada files, not the .PAD file.   A common mistake is to edit the Ada file, while you should edit the   .PAD file. Therefore the ADA buffers are made Unmodifiable.

How it works:
A filter (written in Ada) translates the .LIS output of proada to a diagnostics (.DIA) file.
LSE is taught a new language: PROADA, with extension .PAD. The compilation command is LSE_PROADA.
LSE_PROADA is a DCL commandfile that calls proada, and the filter. If succesful, it also compiles the generated ADA files. The command PRO does this compilation, and additionally loads the generated ADA files into Unmodifiable LSE buffers, you can review errors in the Ada code as well.

How to instal it:

Call this file "LSE_PROADA.COM", and
install it in your LOGIN.COM as symbol "LSE_PROADA". Change the [maarten.lse] to the directory containing PAD_DIA.EXE.

------------------------------------cut----------------------

$ set noon
$ device=f$parse("''p1'",,,"DEVICE")
$ directory=f$parse("''p1'",,,"DIRECTORY")
$ name=f$parse("''p1'",,,"NAME")
$ full_directory=device+directory
$ basename=full_directory+name
$ diafile="''basename'.dia"
$ lisfile="''basename'.lis"
$ adafile="''basename'.ada"
$ oradclfile="''basename'.ora_dcl"
$ set def 'full_directory'
$ proada iname='p1' lname='lisfile' sqlcheck=semantics userid=/ ireclen=255 oreclen=255 lreclen=255
$ severity=$severity
$ define/nolog/job proada_pad_file 'p1'
$ define/nolog/job dia_file 'diafile'
$ write sys$output "name ''p1'"
$ define/nolog proada_dia_file 'diafile'
$ define/nolog proada_lis_file 'lisfile'
$ run [maarten.lse]pad_dia
$ write sys$output "proada-severity ''severity'"
$ if 'severity' .ne. 1 then goto einde
$! severity=1=Succes
$! try to compile the generated ada files

$ ada /optimize=development 'oradclfile' /diagnostics='diafile'
$ severity=$severity
$ if 'severity' .ne. 1 then goto einde
$ ada /optimize=development 'adafile' /diagnostics='diafile'
$ severity=$severity
$ write sys$output "ada-severity ''severity'"
$ einde:
$ exit 'severity'
------------------------------------cut----------------------



Compile this ada program and call the executable PAD_DIA.EXE. It will be called from LSE_PROADA.COM.
The program should be easily ported to say, C. If you encounter any problems please don't hesitate to mail me. Note: this is not the most beautiful piece of software I've ever written, but it does the job.

------------------------------------cut----------------------
-- This program converts the 'list' (.lis) output of the pro*ada precompiler -- into a diagnostics (.dia) file.

with text_io; use text_io;

procedure PAD_DIA is

    IN_FILE_LOGICAL : constant STRING := "PROADA_LIS_FILE:";     OUT_FILE_LOGICAL : constant STRING := "PROADA_DIA_FILE:";     PAD_SOURCE_LOGICAL : constant STRING := "PROADA_PAD_FILE:";

    MAX_DIAGNOSTICS : constant POSITIVE := 30;
    LIS_FILE : FILE_TYPE;
    DIA_FILE : FILE_TYPE;

    LINE : STRING(1..300);
    LENGTH : NATURAL; -- length of line
    ERROR_MESSAGE		: array (1..20) of STRING(1..200);
    ERROR_MESSAGE_LENGTH	: array (1..20) of NATURAL;
    NUMBER_OF_ERROR_MESSAGES : NATURAL;     
    COLUMN_NUMBER		: STRING(1..5);
    COLUMN_NUMBER_LENGTH	: NATURAL;

    SOURCE_LINE_NUMBER		: STRING(1..5);
    SOURCE_LINE_NUMBER_LENGTH	: NATURAL;

    NUMBER_OF_EMITTED_DIAGNOSTICS : NATURAL := 0;     READING_ERROR_MESSAGE : BOOLEAN := FALSE;     NOT_FOUND : exception; -- raised by FIND

    function FIND( START_AT_POSITION : in POSITIVE;

                    SEARCH_STRING : in STRING) return POSITIVE is     begin

	for I in START_AT_POSITION..LENGTH-SEARCH_STRING'LENGTH+1 loop
	    if LINE(I..I+SEARCH_STRING'LENGTH-1) = SEARCH_STRING then
		return I;
	    end if;
	end loop;
	raise NOT_FOUND;

    end FIND;

    function FIND_NON_NUMERIC( START_AT_POSITION: in POSITIVE)

                return POSITIVE is
    begin

	for I in START_AT_POSITION..LENGTH loop
	    if LINE(I) < '0' or LINE(I) > '9' then
		return I;
	    end if;
	end loop;
	raise NOT_FOUND;

    end FIND_NON_NUMERIC;

    function ERROR_LIMIT_REACHED return BOOLEAN is     begin

        return NUMBER_OF_EMITTED_DIAGNOSTICS >= MAX_DIAGNOSTICS;     end ERROR_LIMIT_REACHED;

    procedure EMIT_NEW_LINE is
    begin

        NEW_LINE(FILE => DIA_FILE);
    end EMIT_NEW_LINE;

    procedure EMIT(LINE: in STRING) is
    begin

	PUT(FILE => DIA_FILE,
	    ITEM => LINE);

    end EMIT;

    procedure EMIT_LINE(LINE: in STRING) is     begin

	EMIT(LINE);
	EMIT_NEW_LINE;

    end EMIT_LINE;

    procedure EMIT(CHAR : in CHARACTER) is     begin

	PUT(FILE => DIA_FILE,
	    ITEM => CHAR);

    end EMIT;

    procedure EMIT_QUOTED_STRING(LINE: in STRING) is

        QUOTE : constant CHARACTER := '"';
    begin

	EMIT(QUOTE);
	for I in LINE'RANGE loop
	    EMIT(LINE(I));
	    if LINE(I)=QUOTE then
		EMIT(QUOTE); -- double it
	    end if;
	end loop;
	EMIT(QUOTE);

    end EMIT_QUOTED_STRING;

    procedure EMIT_DIAGNOSTIC is
    begin

        EMIT_LINE("start diagnostic");

	EMIT_LINE(
	    "region/file " &
	    PAD_SOURCE_LOGICAL &
	    "/line=" &
	    SOURCE_LINE_NUMBER(1..SOURCE_LINE_NUMBER_LENGTH) &
	    "/column_range=(1,65535)/primary" );

	EMIT_LINE(
	    "region/nested/column_range=(" &
	    COLUMN_NUMBER(1..COLUMN_NUMBER_LENGTH) &
	    ")" );

	for I in 1..NUMBER_OF_ERROR_MESSAGES loop
	    EMIT( "message/text=quoted ");
	    EMIT_QUOTED_STRING(
		ERROR_MESSAGE(I)(1..ERROR_MESSAGE_LENGTH(I)));
	    EMIT_NEW_LINE;
	end loop;

	EMIT_LINE("end diagnostic");

	NUMBER_OF_EMITTED_DIAGNOSTICS := NUMBER_OF_EMITTED_DIAGNOSTICS + 1;

    end EMIT_DIAGNOSTIC;

    procedure EMIT_ERROR_LIMIT_DIAGNOSTIC is

	ERROR_LIMIT_MESSAGE : constant STRING :=
	    " Error limit (" & INTEGER'IMAGE(MAX_DIAGNOSTICS) &
	    " ) reached.";
    begin
	NUMBER_OF_ERROR_MESSAGES := 1;
	ERROR_MESSAGE(1)(1..ERROR_LIMIT_MESSAGE'LENGTH) := ERROR_LIMIT_MESSAGE;
	ERROR_MESSAGE_LENGTH(1) := ERROR_LIMIT_MESSAGE'LENGTH;
	EMIT_DIAGNOSTIC;

    end EMIT_ERROR_LIMIT_DIAGNOSTIC;

    procedure EMIT_HEADER is
    begin

	EMIT_LINE("! Generated by Maarten's fabulous .DIA file generator");
	EMIT_LINE("start module");

    end EMIT_HEADER;

    procedure EMIT_TRAILER is
    begin

        EMIT_LINE("end module");
    end EMIT_TRAILER;

    procedure CLEAR_DIAGNOSTIC is
    begin

        NUMBER_OF_ERROR_MESSAGES := 0;
    end CLEAR_DIAGNOSTIC;

    function BEGIN_OF_ERROR_MESSAGE return BOOLEAN is     begin

        return LENGTH > 8 and LINE(1..4) = "PCC-";     end BEGIN_OF_ERROR_MESSAGE;

    function END_OF_ERROR_MESSAGE return BOOLEAN is     begin

	if LINE(LENGTH) /= '!' then 
	    return FALSE;
	else
	    for I in 1..LENGTH-1 loop
		if  LINE(I) /= ASCII.HT and 
		    LINE(I) /= ' '      and 
		    LINE(I) /= '.'       
		then
		    return FALSE;
		end if;
	    end loop;
	    return TRUE;
	end if;

    end END_OF_ERROR_MESSAGE;

    procedure GET_LINE is

        POSITION1, POSITION2 : NATURAL;
    begin

	POSITION1 := FIND(1,         "line ");
	POSITION1 := POSITION1 + 5;
	POSITION2 := FIND_NON_NUMERIC(POSITION1);
	POSITION2 := POSITION2 - 1;
	SOURCE_LINE_NUMBER_LENGTH := POSITION2 - POSITION1 + 1;
	SOURCE_LINE_NUMBER(1..SOURCE_LINE_NUMBER_LENGTH) := 
	    LINE(POSITION1..POSITION2);
    exception
	when NOT_FOUND =>
	    SOURCE_LINE_NUMBER(1..2) := "-1";
	    SOURCE_LINE_NUMBER_LENGTH := 2;

    end GET_LINE;

    procedure GET_COLUMN is

        POSITION1, POSITION2 : NATURAL;
    begin

	POSITION1 := FIND(1,         "column ");
	POSITION1 := POSITION1 + 7;
	POSITION2 := FIND_NON_NUMERIC(POSITION1);
	POSITION2 := POSITION2 - 1;
	COLUMN_NUMBER_LENGTH := POSITION2 - POSITION1 + 1;
	COLUMN_NUMBER(1..COLUMN_NUMBER_LENGTH) := 
	    LINE(POSITION1..POSITION2);
    exception
	when NOT_FOUND =>
	    COLUMN_NUMBER(1..1) := "1";
	    COLUMN_NUMBER_LENGTH := 1;

    end GET_COLUMN;

    procedure ADD_ERROR_MESSAGE_LINE_TO_DIAGNOSTIC is     begin

	NUMBER_OF_ERROR_MESSAGES := NUMBER_OF_ERROR_MESSAGES + 1;
	ERROR_MESSAGE(NUMBER_OF_ERROR_MESSAGES)(1..LENGTH) := LINE(1..LENGTH);
	ERROR_MESSAGE_LENGTH(NUMBER_OF_ERROR_MESSAGES) := LENGTH;
    end ADD_ERROR_MESSAGE_LINE_TO_DIAGNOSTIC;

    function LINE_IS_EMPTY return BOOLEAN is     begin

	for I in 1..LENGTH loop
	    if LINE(I) /= ' ' and
	       LINE(I) /= ASCII.HT then
		return FALSE;
	    end if;
	end loop;
	return TRUE;

    end LINE_IS_EMPTY;

    procedure PROCESS_LINE(LINE : in STRING) is     begin

	if LINE_IS_EMPTY then 
	    return; 
	end if;
	if BEGIN_OF_ERROR_MESSAGE then
	    READING_ERROR_MESSAGE := TRUE;
	    GET_LINE;
	    GET_COLUMN;
	    ADD_ERROR_MESSAGE_LINE_TO_DIAGNOSTIC;
	elsif END_OF_ERROR_MESSAGE then
	    EMIT_DIAGNOSTIC;
	    CLEAR_DIAGNOSTIC;
	    READING_ERROR_MESSAGE := FALSE;
	elsif READING_ERROR_MESSAGE then
	    ADD_ERROR_MESSAGE_LINE_TO_DIAGNOSTIC;
	end if;

    end PROCESS_LINE;

begin -- PAD_DIA

    OPEN( FILE => LIS_FILE,

	    MODE => IN_FILE,
	    NAME => IN_FILE_LOGICAL);

    CREATE( FILE => DIA_FILE,
	    NAME => OUT_FILE_LOGICAL);

    EMIT_HEADER;     CLEAR_DIAGNOSTIC;     while not END_OF_FILE(LIS_FILE) and not ERROR_LIMIT_REACHED loop

	GET_LINE(LIS_FILE, LINE, LENGTH);
	PROCESS_LINE(LINE(1..LENGTH));

    end loop;

    if ERROR_LIMIT_REACHED then

        EMIT_ERROR_LIMIT_DIAGNOSTIC;
    end if;

    EMIT_TRAILER;     CLOSE(LIS_FILE);
    CLOSE(DIA_FILE);          end PAD_DIA;

------------------------------------cut----------------------


Make sure these LSE definitions are executed. Put them in a .LSE file for example. I keep forgetting the names of the logicals tou auto-load these files. Please look them up, since I don't have the manual here.

------------------------------------cut----------------------
DELETE LANGUAGE ADA
DEFINE LANGUAGE ADA -
    /COMMENT=( -
	ASSOCIATED_IDENTIFIER = PREVIOUS, -
	NOBEGIN, -
	NOEND, -
	NOFIXED, -
	NOLINE, -
	TRAILING=("-- |","--")) -
    /CAPABILITIES=DIAGNOSTICS -
    /COMPILE_COMMAND="ADA" -
    /EXPAND_CASE=AS_IS -
    /FILE_TYPES=(.ADA,.ADC,.ORA_DCL) -

    /NOHELP_LIBRARY -
    /IDENTIFIER_CHARACTERS= -
        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789" -
    /INITIAL_STRING="{compilation_unit}" -
    /LEFT_MARGIN=CONTEXT_DEPENDENT -
    /OVERVIEW_OPTIONS=( -
        MINIMUM_LINES=1, -
        TAB_RANGE=(4,8)) -
    /PLACEHOLDER_DELIMITERS=( -
        REQUIRED=      ("{","}"), -
        REQUIRED_LIST= ("{","}..."), -
        OPTIONAL=      ("[","]"), -
        OPTIONAL_LIST= ("[","]..."), -
        PSEUDOCODE= ("½","+")) -
    /PUNCTUATION_CHARACTERS=",;().'" -
    /QUOTED_ITEM=(QUOTES="""'") -
    /RIGHT_MARGIN=80 -
    /TAB_INCREMENT=4 -
    /TAG_TERMINATORS=(":") -
    /TOPIC_STRING="ADA Language_Topics" -
    /VERSION="V2.0" -
    /NOWRAP DEFINE LANGUAGE PROADA -
    /COMMENT=( -
	ASSOCIATED_IDENTIFIER = PREVIOUS, -
	NOBEGIN, -
	NOEND, -
	NOFIXED, -
	NOLINE, -
	TRAILING=("-- |","--")) -
    /CAPABILITIES=NODIAGNOSTICS -
    /COMPILE_COMMAND="LSE_PROADA" -
    /EXPAND_CASE=AS_IS -
    /FILE_TYPES=(.PAD) -

    /NOHELP_LIBRARY -
    /IDENTIFIER_CHARACTERS= -
        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789" -
    /INITIAL_STRING="{compilation_unit}" -
    /LEFT_MARGIN=CONTEXT_DEPENDENT -
    /OVERVIEW_OPTIONS=( -
        MINIMUM_LINES=1, -
        TAB_RANGE=(4,8)) -
    /PLACEHOLDER_DELIMITERS=( -
        REQUIRED=      ("{","}"), -
        REQUIRED_LIST= ("{","}..."), -
        OPTIONAL=      ("[","]"), -
        OPTIONAL_LIST= ("[","]..."), -
        PSEUDOCODE= ("½","+")) -
    /PUNCTUATION_CHARACTERS=",;().'" -
    /QUOTED_ITEM=(QUOTES="""'") -
    /RIGHT_MARGIN=80 -
    /TAB_INCREMENT=4 -
    /TAG_TERMINATORS=(":") -
    /TOPIC_STRING="ADA Language_Topics" -
    /VERSION="V1.0" -
    /NOWRAP DEFINE COMMAND PRO "DO ""COMPILE/REVIEW"", ""END REVIEW"", ""CALL PROTPU"", ""REVIEW /file=dia_file"""

DEFINE COMMAND PROREV "REVIEW /file=dia_file"

DEFINE KEY "F14" "SHOW BUF"

------------------------------cut--------------------------
Also copy every Ada ADJUSTMENT, PLACEHOLDER, TAG and TOKEN to a PROADA one. Put these copies also in the .LSE file. They are not necessary, but they make every LSE gadget for Ada also available for Proada (.PAD) files.

Make sure the following TPU procedure is known. E.g., put it in a .TPU file and set a logical to auto-load it.

------------------------------cut--------------------------
PROCEDURE protpu
LOCAL filetype, curfile, padfile, lisfile, commando, dclbuf,

      adabuf, lisbuf, dclfile;
filetype := FILE_PARSE(GET_INFO(CURRENT_BUFFER,"file_name"),"","",TYPE); IF filetype <> ".PAD"
THEN

	MESSAGE("Buffer does not contain a PROADA file");
	ABORT;
ENDIF;
curfile     := FILE_PARSE(GET_INFO(CURRENT_BUFFER,"file_name"),"","", DIRECTORY, NAME);
adafile     := FILE_PARSE(curfile,".ADA",    "", DIRECTORY, NAME, TYPE);
oradclfile  := FILE_PARSE(curfile,".ORA_DCL","", DIRECTORY, NAME, TYPE);
lisfile     := FILE_PARSE(curfile,".LIS",    "", DIRECTORY, NAME, TYPE);
padbufn     := padfile;
adabufn     := FILE_PARSE(curfile,".ADA",    "", NAME, TYPE);
lisbufn     := FILE_PARSE(curfile,".LIS",    "", NAME, TYPE);
oradclbufn := FILE_PARSE(curfile,".ORA_DCL","", NAME, TYPE); adabuf := GET_INFO(BUFFER, "find_buffer", adabufn); IF adabuf <> 0
THEN
        DELETE(adabuf);
ENDIF;
adabuf := CREATE_BUFFER(adabufn, adafile); set (modifiable, adabuf, off);
oradclbuf := GET_INFO(BUFFER, "find_buffer", oradclbufn); IF oradclbuf <> 0
THEN
        DELETE(oradclbuf);
ENDIF;
oradclbuf := CREATE_BUFFER(oradclbufn, oradclfile); set (modifiable, oradclbuf, off);
ENDPROCEDURE;
------------------------------cut--------------------------

Good Luck!
Let me know if you are using it. Suggestions are welcomed.

-- 
Gijs Bok (gijs_at_mbase97.hacktic.nl)
Listen to M-BASE music!
Received on Fri Aug 27 1993 - 23:49:12 CEST

Original text of this message