PROGRAM CREATE_ENTRY_FOR_EXTERNALDECLARATIONS;
{                            by
                      Robert H. Harsch
                     ph: (916) 487-2216
             2362 American River Dr, Suite 311
                   Sacramento, Ca. 95825.
                    All rights reserved.		}

{ only the first 6 characters are significant }

CONST	$ENTRY_KEY='{@';  { string we look for to pick up entry
			name and insert into file name.ZZZ }

	$MAIN_PROGRAM_BEGIN='L99'; { string to look for to stop
			program.  Nothing is copied beyond
			this point to file name.ZZZ }

TYPE
	$STRING0= STRING 0;
	$STRING32= STRING 80;
	$STRING255= STRING 255;
	BYTE= 0..255;

	SYM_LINK= ^SYM_TYPE; { symbol (entry points) linked }
	SYM_TYPE= RECORD
			$SYM: $STRING32;
			PTR: SYM_LINK
		END;

VAR
	INFILE,OUTFILE: TEXT;
	$SYMBOL, $LINE: $STRING255;
	$CH, $TAB: CHAR;
	K,I: INTEGER;
	LOWERCASE, IDSTART, IDENTIFIER: SET OF CHAR;
	PROGRAM_DONE, BADCHAR, PREV_DEFN, FOUND_ENTRY: BOOLEAN;
	SYM_DEFN_ROOT: SYM_LINK;
	UPPERCASE: ARRAY['a'..'z'] OF 'A'..'Z';


FUNCTION LENGTH(X: $STRING255): INTEGER; EXTERNAL;
FUNCTION INDEX(X,Y: $STRING255): INTEGER; EXTERNAL;
PROCEDURE SETLENGTH(VAR X: $STRING0; Y: INTEGER); EXTERNAL;



PROCEDURE GET_FILE_NAME_FROM_COMMAND_LINE(VAR $INF: $STRING32);
VAR	I: INTEGER;

FUNCTION PEEK(ADDR: INTEGER): BYTE;
	TYPE	CONTENTS= PACKED RECORD
				BYT: BYTE { byte in memory }
			END; { of record }
		FORM=(INTEGR,ADDRESS);
		REFERENCE= RECORD
			CASE FORM OF
				INTEGR:  (I: INTEGER);
				ADDRESS: (P: ^CONTENTS)
			END;

	VAR	TEMP: REFERENCE;

	BEGIN { of function peek }
		TEMP.I:= ADDR;
		PEEK:= TEMP.P^.BYT
	END; { of function peek }

	BEGIN { of procedure GET_FILE_NAME_FROM_COMMAND_LINE }
	SETLENGTH($INF,0);
	FOR I:= 129 TO 128 + PEEK(128) DO
			APPEND( $INF, CHR(PEEK(I)) )
	END; { of procedure GET_FILE_NAME_FROM_COMMAND_LINE }



PROCEDURE OPENFILES;
CONST	$M1= 'Input file (without entry points): ';
	$M2= 'Output file (with entry points): ';
VAR	$FILENAME, $NAME_EXT: $STRING32;
	$CR : CHAR; { carriage return }
	BEGIN
		$CR:= CHR(13); { carriage return }
		GET_FILE_NAME_FROM_COMMAND_LINE($FILENAME);
		$NAME_EXT:= $FILENAME;
		APPEND($NAME_EXT, '.SRC');
		APPEND($NAME_EXT,$CR);	{ see note #3 of
				hot news, filenames passed to
				rewrite or reset must be
				deleted with a carriage return}
		RESET($NAME_EXT, INFILE);
		WRITELN($M1, $NAME_EXT);
		$NAME_EXT:= $FILENAME;
		APPEND($NAME_EXT, '.ZZZ');
		APPEND($NAME_EXT,$CR);	{ see note #3 of
				hot news, filenames passed to
				rewrite or reset must be
				deleted with a carriage return}
		REWRITE($NAME_EXT, OUTFILE);
		WRITELN($M2, $NAME_EXT);
	END; { of procedure openfiles }



PROCEDURE WRITEOUT(VAR $SYMBOL: $STRING32;
			PREV_DEFN, BADCHAR: BOOLEAN);
CONST	$MSG1= 'Error, symbol previously defined';
	$MSG2= 'Error, "#" or "_" character in symbol defined';
VAR	$TAB: CHAR;
	SYM_NODE: SYM_LINK;
	BEGIN
		$TAB:= CHR(9);
		WRITELN(OUTFILE,$TAB,'ENTRY',$TAB, $SYMBOL);
		WRITELN(OUTFILE,$SYMBOL,':');

		{ write info to screen }
		WRITELN;
		WRITELN('Entry symbol found:');
		WRITELN($TAB,'ENTRY',$TAB, $SYMBOL);
		WRITELN($SYMBOL,':');
		IF PREV_DEFN THEN
			WRITELN($MSG1);
		IF BADCHAR THEN
			WRITELN($MSG2);

		{ insert new symbol into link list }
		NEW(SYM_NODE);
		SYM_NODE^.$SYM:= $SYMBOL;
		SYM_NODE^.PTR:= SYM_DEFN_ROOT;
		SYM_DEFN_ROOT:= SYM_NODE;
	END; { of procedure writeout }



PROCEDURE WAS_$SYMBOL_PREVIOUSLY_DEFN(
		VAR $SYMBOL: $STRING32;
		VAR PREV_DEFN: BOOLEAN);
VAR	SYM_NODE: SYM_LINK;
	BEGIN
		SYM_NODE:= SYM_DEFN_ROOT;
		PREV_DEFN:= FALSE;
		WHILE (SYM_NODE <> NIL) AND NOT PREV_DEFN DO
			WITH SYM_NODE^ DO
				IF $SYM = $SYMBOL
					THEN PREV_DEFN:= TRUE
					ELSE SYM_NODE:= PTR;
	END; { of procedure WAS_$SYMBOL_PREVIOUSLY_DEFN }


BEGIN { of main program }
WRITELN;
WRITELN('Program for automatic insertion of entry points.');
WRITELN('By Robert Harsch.');
WRITELN;
WRITELN('WORKING.');

{ initialize global variables }
SYM_DEFN_ROOT:= NIL;
FOR $CH:='a' TO 'z' DO
	UPPERCASE[$CH]:= CHR(ORD('A') + (ORD($CH) - ORD('a')));
LOWERCASE:= ['a'..'z'];  { We will convert lower case
		characters to upper case like the assembler. }
{ set of "IDentifier START" and "IDentifier" characters }
IDSTART:= ['A'..'Z'] + LOWERCASE + ['$', '%', '.'] + ['#','_'];
IDENTIFIER:= IDSTART + ['0'..'9'];

OPENFILES;
REPEAT
	SETLENGTH($LINE,0);
	READLN(INFILE,$LINE);
	WRITELN(OUTFILE,$LINE);
	APPEND($LINE, ' '); 	{ sentinel }
	I:= INDEX ($LINE, $ENTRY_KEY);
	K:= I + LENGTH ( $ENTRY_KEY );
	FOUND_ENTRY:= (I > 0) AND ( $LINE[K] IN IDSTART );
	IF FOUND_ENTRY THEN
		BEGIN
		SETLENGTH($SYMBOL,0);

		{ pick up first 6 significant chars, and
		convert lower to upper case, store in $SYMBOL }
		I:= K; BADCHAR:= FALSE;
		REPEAT
			IF $LINE[I] IN LOWERCASE THEN
				$LINE[I]:= UPPERCASE[$LINE[I]];
			IF $LINE[I] IN ['#','_'] THEN
				BADCHAR:= TRUE;
			APPEND($SYMBOL,$LINE[I]);
			I:= I + 1
		UNTIL NOT ($LINE[I] IN IDENTIFIER) OR (I-K =6);

		WAS_$SYMBOL_PREVIOUSLY_DEFN($SYMBOL,PREV_DEFN);
		WRITEOUT($SYMBOL,PREV_DEFN,BADCHAR);
		END;
	PROGRAM_DONE:= (INDEX($LINE, $MAIN_PROGRAM_BEGIN) = 1)
				AND
		 	NOT ($LINE[4] IN IDENTIFIER);
UNTIL PROGRAM_DONE;
WRITELN('PROGRAM IS DONE.');

END.