#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	gen.c
#	makefile
#	pascal.g
#	pmain.c
#	sym.c
#	sym.h
# This archive created: Tue Mar 27 14:35:33 1990
# By:	CARP Research Group ()
export PATH; PATH=/bin:$PATH
if test -f 'gen.c'
then
	echo shar: will not over-write existing file "'gen.c'"
else
cat << \SHAR_EOF > 'gen.c'
int n=50;

main(argc, argv)
int argc;
char *argv[];
{
	int i;

	if ( argc == 2 ) n = atoi(argv[1]);

	printf("#attrib <<#define D_Integer>>\n");
	printf("s\t:\t(a)* ;\n");
	printf("a\t:\t\"A%d\"", 0);
	for (i=1; i<=n-1; i++)
	{
		printf("\n\t|\t\"A%d\"", i);
	}
	printf("\n\t;\n");
}
SHAR_EOF
fi # end of overwriting check
if test -f 'makefile'
then
	echo shar: will not over-write existing file "'makefile'"
else
cat << \SHAR_EOF > 'makefile'
GRM =pascal.g
GSRC=pascal.c err.c pscan.c
GOBJ=pascal.o err.o pscan.o

SRC =$(GSRC) pmain.c sym.c
OBJ =$(GOBJ) pmain.o sym.o

CFLAGS=-I../h -O
AFLAGS=

pas : $(OBJ) $(SRC)
	cc -g -o pas $(OBJ)
parser.dlg : $(GRM)
	antlr $(AFLAGS) $(GRM)
pscan.c : parser.dlg
	dlg -C2 parser.dlg pscan.c
pmain.o : pmain.c

sym.o : sym.c

err.o : err.c

pascal.c : $(GRM)
	antlr $(AFLAGS) $(GRM)
SHAR_EOF
fi # end of overwriting check
if test -f 'pascal.g'
then
	echo shar: will not over-write existing file "'pascal.g'"
else
cat << \SHAR_EOF > 'pascal.g'
/*
 * File: pascal.g
 *
 * P a s c a l  G r a m m a r
 *
 * Some of the grammar could be more readable if it were spread out.  However,
 * to show the concise nature of ANTLR, I am squishing it (show off).
 * Theoretically, it would be possible to put the entire grammar into one
 * rule with lots-o-parenthesis and duplicate subrules.
 *
 * This grammar is considered Public Domain and is distributed as is.
 *
 * Terence Parr (c) 1990
 * Purdue University
 * January 1990
 *
 */
#attrib <<
			#include "sym.h"
			#define aStackSize	400
			typedef Sym *Attrib;
			#define aCreate(attr)	{*(attr) = CurSym;}
			extern Sym *CurSym;
		>>

<<
Sym *CurSym;
static int level = 0;
>>

#token TypeID
#token VarID
#token ProcID
#token ProgID
#token FuncID
#token ConstID
#token "[\t\ ]"		<< LexSkip(); >>
#token "\n"			<< lex_line++; LexSkip(); >>
#token "\{~[\}]*\}"	<< LexSkip(); >>


/* G r o s s  S y n t a x  C o n t r o l */


program		:	<<Sym *globals=NULL, *p;>>
				"program" WORD		<<$2->token=ProgID;aSymAdd($2->symbol,$2);>>
				<<printf("program %s level %d:\n\n", $2->symbol, level);>>
			 	<<aSymScope(&globals);>>
				"\(" idList "\)"	<<addlist($4,VarID,level);>>
				";"
				block "."
				<<
				  p = aSymRmScope(&globals);
				  printf("global (level %d) symbols:", level);
				  for (; p != NULL; p=p->scope) printf(" %s", p->symbol);
				  printf("\n\n");
				>>
				"@"
			;

block		:	<<Sym **oldscope = aSymScope(NULL);>>
				decl
				( routine <<aSymScope(oldscope);>> )*
				"begin"
					slist
				"end"
			;

routine		:	<<int tok; Sym *rout,*p,*locals=NULL;>>
				("procedure" <<tok=ProcID;>> | "function" <<tok=FuncID;>>)
				(	WORD <<rout=$1; $1->token=tok; aSymAdd($1->symbol,$1);>>
				|	ProcID
				|	FuncID
				)
				<<aSymScope(&locals); level++;>>
				{"\(" parmGroup (";" parmGroup)* "\)"}
				{ ":" TypeID }
				";"
				block ";"
				<<
				  p = aSymRmScope(&locals);
				  printf("subprogram %s level %d:\n", rout->symbol, --level);
				  printf("local (level %d) symbols:", level+1);
				  for (; p != NULL; p=p->scope) printf(" %s", p->symbol);
				  printf("\n\n");
				>>
			;

parmGroup	:	{"var"} idList ":" TypeID <<addlist($2,VarID,level);>>
			;

slist		:	statement ( ";" statement )* ;

statement	:	{UINT ":"}
				{	(var | FuncID) ":=" expr
				|	ProcID { "\(" expr ("," expr)* "\)" }
				|	"begin" slist "end"
				|	"if" expr "then" statement {"else" statement}
				|	"case" expr "of"
						(constant ("," constant)* ":" statement ";")*
					"end"
				|	"while" expr "do" statement
				|	"repeat" slist "until" expr
				|	"for" VarID ":=" expr ("to"|"downto") expr "do" statement
				|	"with" var ( "," var )* "do" statement
				|	"goto" UINT
				}
			;


/* D e c l a r a t i o n  S e c t i o n */


decl		:	("label" UINT ( "," UINT )* ";")*
				{	"const" WORD "=" constant ";"
					<<$2->token = ConstID; aSymAdd($2->symbol,$2);>>
					(	WORD <<$1->token = ConstID; aSymAdd($1->symbol,$1);>>
						"=" constant ";"
					)*
				}
				{	"type" WORD	"=" type ";"
					<<$2->token = TypeID; aSymAdd($2->symbol,$2);>>
					(	WORD	<<$1->token = TypeID; aSymAdd($1->symbol,$1);>>
						"=" type ";"
					)*
				}
				{	"var" idList ":" type ";"	<<addlist($2,VarID,level);>>
					( idList ":" type ";"		<<addlist($1,VarID,level);>>
					)*
				}
			;

simpleType	:	TypeID
			|	"\(" wordList <<addlist($2,ConstID,level);>> "\)"
			|	constant ".." constant
			;

type		:	simpleType
			|	"^" TypeID
			|	{PACKED} structType
			;

structType	:	"array" "\[" simpleType ("," simpleType)* "\]" "of" type
			|	"file" "of" type
			|	"set" "of" simpleType
			|	"record" fixedPart {";"} (fixedPart {";"} )* {variantPart} "end"
			;

fixedPart	:	idList ":" type ;

variantPart	:	"case"
				{WORD ":"}
				TypeID "of" variant {";"} (variant {";"})*
			;

variant		:	constant ( "," constant )*
				":" "\(" fixedPart {";"} (fixedPart {";"})* {variantPart} "\)"
			;

/* Use 'next' field of symbol rec to link elements together into idlist */
idList		:	<<Sym *list=NULL;>>			/* Return list of id's */
				(	WORD	<<$1->next=list; list=$1;>>
				|	VarID	<<{Sym *p=aSymNew($1->symbol);
							   p->next=list; list=p;}>>
				)
				( ","
					(	WORD <<$1->next=list; list=$1;>>
					|	VarID <<{Sym *p=aSymNew($1->symbol);
								 p->next=list; list=p;}>>
					)
				)*
				<<$0 = list;>>
			;

wordList	:	<<Sym *list=NULL;>>			/* Return list of words */
				WORD	<<$1->next=list; list=$1;>>
				( "," WORD <<$2->next=list; list=$2;>> )*
				<<$0 = list;>>
			;

constant	:	{"\+"|"\-"} (ConstID | UINT | UNUM)
			|	LITERAL
			;

uconstant	:	ConstID
			|	UNUM
			|	UINT
			|	"nil"
			|	LITERAL
			;
			

/* E x p r e s s i o n  S e c t i o n */


expr		:	simpleExpr {("="|"\<"|"\>"|"\<\>"|"\<="|"\>="|"in") simpleExpr} ;

simpleExpr	:	{"\+"|"\-"} term {("\+"|"\-"|"or") term} ;

term		:	factor {("\*"|"/"|"div"|"mod"|"and") factor} ;

factor		:	uconstant
			|	var
			|	FuncID { "\(" expr ("," expr)* "\)" }
			|	"\(" expr "\)"
			|	"not" factor
			|	"\[" {expr {".." expr}} ("," expr {".." expr})* "\]"
			;

var			:	(VarID|WORD) ref
			;

ref			:	"\[" expr ("," expr)* "\]" ref
			|	"^" ref
			|	"." (WORD|VarID) ref
			|
			;

#token LITERAL "' ~[\0-\31']* '"
#token UINT "[0-9]+"
#token SINT	"{\+|\-} [0-9]+"
#token UNUM	"[0-9]* {. [0-9]*} {E{\+|\-} [0-9]+}"	/* Floating point */
#token WORD "[a-zA-Z] [a-zA-Z0-9]*"
		<<
		{
			register Sym *p;

			p = aSymGet(LexText);
			if ( p == NULL ) p = aSymNew(LexText, WORD);
			else Token = p->token;
			CurSym = p;
		}
		>>
SHAR_EOF
fi # end of overwriting check
if test -f 'pmain.c'
then
	echo shar: will not over-write existing file "'pmain.c'"
else
cat << \SHAR_EOF > 'pmain.c'
#include <stdio.h>
#ifdef MEMCHK
#include "trax.h"
#else
char *calloc(), *malloc();
#endif
#include "sym.h"
typedef Sym *Attrib;
#include "attrib.h"
#include "tokens.h"

#define SymStrTable		1000
#define HashSize		1001

struct _pre {
	char *symbol;
	int token;
};

struct _pre predef[] = {
	 /* Predefined Constants */
	 { "maxint", ConstID },

	 /* Predefined Types */
	 {"real", TypeID},
	 {"boolean", TypeID},
	 {"char", TypeID},
	 {"integer", TypeID},
	 {"text", TypeID},

	 /* Predefined Functions */
	 { "odd", FuncID },
	 { "eoln", FuncID },
	 { "eof", FuncID },
	 { "abs", FuncID },
	 { "sqr", FuncID },
	 { "sin", FuncID },
	 { "cos", FuncID },
	 { "arctan", FuncID },
	 { "ln", FuncID },
	 { "exp", FuncID },
	 { "sqrt", FuncID },
	 { "ord", FuncID },
	 { "chr", FuncID },
	 { "pred", FuncID },
	 { "succ", FuncID },
	 { "round", FuncID },
	 { "trunc", FuncID },

	 /* Predefined Procedures */
	 { "put", ProcID },
	 { "get", ProcID },
	 { "reset", ProcID },
	 { "rewrite", ProcID },
	 { "new", ProcID },
	 { "dispose", ProcID },
	 { "read", ProcID },
	 { "readln", ProcID },
	 { "write", ProcID },
	 { "writeln", ProcID },
	 { "page", ProcID },

	 {NULL, 0}
};

main(argc, argv)
int argc;
char *argv[];
{
	BLKvars;
	Sym *p;
	FILE *f;
	
	if ( argc==1 ) return;
	f = fopen(argv[1], "r");
	if ( f==NULL ) {fprintf(stderr, "Can't Open '%s'\n", argv[1]); return;}
	aSourceFile = argv[1];

	aSymInit(HashSize, SymStrTable);
	LoadSymTable();

	ANTLR(program, f);		/* Parse program from stdin */
	/*statsym();*/
	exit(0);
}

LoadSymTable()
{
	struct _pre *p = &(predef[0]);
	Sym *sym;

	while ( p->symbol != NULL )
	{
		sym = aSymNew(p->symbol);
		sym->token = p->token;
		aSymAdd(sym->symbol, sym);
		p++;
	}
}

addlist(list, token, level)
Sym *list;
int token, level;
{
	register Sym *p, *q;

	for (p=list; p!=NULL; p=q)
	{
		p->token = token;	/* Set token to that passed in */
		p->level = level;
		q = p->next;
		aSymAdd(p->symbol, p);
	}
}
SHAR_EOF
fi # end of overwriting check
if test -f 'sym.c'
then
	echo shar: will not over-write existing file "'sym.c'"
else
cat << \SHAR_EOF > 'sym.c'
/*
 * Simple symbol table manager using coalesced chaining to resolve collisions
 *
 * Doubly-linked lists are used for fast removal of entries.
 *
 * 'sym.h' must have a definition for typedef "Sym".  Sym must include at
 * minimum the following fields:
 *
 *		...
 *		char *symbol;
 *		struct ... *next, *prev, **head, *scope;
 *		...
 *
 * 'head' is &(table[hash(itself)]).
 * The hash table is not resizable at run-time.
 * The scope field is used to link all symbols of a current scope together.
 * Scope() sets the current scope (linked list) to add symbols to.
 * Any number of scopes can be handled.  The user passes the address of
 * a pointer to a symbol table
 * entry (INITIALIZED TO NULL first time).
 *
 * Available Functions:
 *
 *	aSymInit(s1,s2)	-- Create hash table with size s1, string table size s2.
 *	aSymDone(s1,s2)	-- Free hash and string table created with aSymInit().
 *	aSymAdd(key,rec)-- Add 'rec' with key 'key' to the symbol table.
 *	aSymGet(key)	-- Return pointer to last record entered under 'key'
 *			   Else return NULL
 *	aSymDel(p)	-- Unlink the entry associated with p.  This does
 *			   NOT free 'p' and DOES NOT remove it from a scope
 *			   list.  If it was a part of your intermediate code
 *			   tree or another structure.  It will still be there.
 *			   It is only removed from the symbol table.
 *	aSymScope(sc)	-- Specifies that everything added to the symbol
 *			   table with aSymAdd() is added to the list (scope)
 *			   'sc'.  'sc' is of 'Sym **sc' type and must be
 *			   initialized to NULL before trying to add anything
 *			   to it (passing it to aSymScope()).  Scopes can be
 *			   switched at any time and merely links a set of
 *			   symbol table entries.  If a NULL pointer is
 *                         passed, the current scope is returned.
 *	aSymRmScope(sc)	-- Remove (aSymDel()) all elements of scope 'sc'
 *			   from the symbol table.  The entries are NOT
 *			   free()'d.  A pointer to the first
 *			   element in the "scope" is returned.  The user
 *			   can then manipulate the list as he/she chooses
 *			   (such as freeing them all). NOTE that this
 *			   function sets your scope pointer to NULL,
 *			   but returns a pointer to the list for you to use.
 *	aSymStat()	-- Print out the symbol table and some relevant stats.
 *	aSymNew(key)	-- Create a new record with calloc() of type Sym.
 *			   Add 'key' to the string table and make the new
 *			   records 'symbol' pointer point to it.
 *	aSymSaveStr(s)	-- Add s to the string table and return a pointer
 *			   to it.  Very fast routine allocation routine
 *			   and does not require strlen() nor calloc().
 *
 * Example:
 *
 *	#include <stdio.h>
 *	#include "sym.h"
 *
 *	main()
 *	{
 *	    Sym *scope1, *scope2, *a, *p;
 *	
 *	    aSymInit(101, 100);
 *	
 *	    a = aSymNew("Apple");	aSymAdd(a->symbol, a);	-- No scope
 *	    aSymScope( &scope1 );	-- enter scope 1
 *	    a = aSymNew("Plum");	aSymAdd(a->symbol, a);
 *	    aSymScope( &scope2 );	-- enter scope 2
 *	    a = aSymNew("Truck");	aSymAdd(a->symbol, a);
 *	
 *    	    p = aSymGet("Plum");
 *    	    if ( p == NULL ) fprintf(stderr, "Hmmm...Can't find 'Plum'\n");
 *	
 *    	    p = aSymRmScope(&scope1)
 *    	    for (; p!=NULL; p=p->scope) {printf("Scope1:  %s\n", p->symbol);}
 *    	    p = aSymRmScope(&scope2)
 *    	    for (; p!=NULL; p=p->scope) {printf("Scope2:  %s\n", p->symbol);}
 *     }
 *
 * Terence Parr
 * Purdue University
 * February 1990
 */

#include <stdio.h>
#include "sym.h"

char *calloc();

#define StrSame		0

static Sym **CurScope = NULL;
static unsigned size = 0;
static Sym **table=NULL;
static char *strings;
static char *strp;
static int strsize = 0;

aSymInit(sz, strs)
int sz, strs;
{
	if ( sz <= 0 || strs <= 0 ) return;
	table = (Sym **) calloc(sz, sizeof(Sym *));
	if ( table == NULL )
	{
		fprintf(stderr, "Cannot allocate table of size %d\n", sz);
		exit(1);
	}
	strings = (char *) calloc(strs, sizeof(char));
	if ( strings == NULL )
	{
		fprintf(stderr, "Cannot allocate string table of size %d\n", strs);
		exit(1);
	}
	size = sz;
	strsize = strs;
	strp = strings;
}

aSymDone()
{
	if ( table != NULL ) free( table );
	if ( strings != NULL ) free( strings );
}
aSymAdd(key, rec)
char *key;
register Sym *rec;
{
	register h=0;
	register char *p=key;
	
	while ( *p != '\0' ) h = (h<<1) + *p++;
	h %= size;
	
	if ( CurScope != NULL ) {rec->scope = *CurScope; *CurScope = rec;}
	rec->next = table[h];			/* Add to doubly-linked list */
	rec->prev = NULL;
	if ( rec->next != NULL ) (rec->next)->prev = rec;
	table[h] = rec;
	rec->head = &(table[h]);
}

Sym *
aSymGet(key)
char *key;
{
	register h=0;
	register char *p=key;
	register Sym *q;
	
	while ( *p != '\0' ) h = (h<<1) + *p++;
	h %= size;
	
	for (q = table[h]; q != NULL; q = q->next)
	{
		if ( strcmp(key, q->symbol) == StrSame ) return( q );
	}
	return( NULL );
}

/*
 * Unlink p from the symbol table.  Hopefully, it's actually in the
 * symbol table.
 *
 * If p is not part of a bucket chain of the symbol table, bad things
 * will happen.
 *
 * Will do nothing if all list pointers are NULL
 */
aSymDel(p)
register Sym *p;
{
	if ( p == NULL ) {fprintf(stderr, "aSymDel(NULL)\n"); exit(1);}
	if ( p->prev == NULL )	/* Head of list */
	{
		register Sym **t = p->head;
		
		if ( t == NULL ) return;	/* not part of symbol table */
		(*t) = p->next;
		if ( (*t) != NULL ) (*t)->prev = NULL;
	}
	else
	{
		(p->prev)->next = p->next;
		if ( p->next != NULL ) (p->next)->prev = p->prev;
	}
	p->next = p->prev = NULL;	/* not part of symbol table anymore */
	p->head = NULL;
}

/* S c o p e  S t u f f */

/* Set current scope to 'scope'; return current scope if 'scope' == NULL */
Sym **
aSymScope(scope)
Sym **scope;
{
	if ( scope == NULL ) return( CurScope );
	CurScope = scope;
	return( scope );
}

/* Remove a scope described by 'scope'.  Return pointer to 1st element in scope */
Sym *
aSymRmScope(scope)
register Sym **scope;
{
	register Sym *p;
	Sym *start;

	if ( scope == NULL ) return(NULL);
	start = p = *scope;
	for (; p != NULL; p=p->scope) {aSymDel( p );}
	*scope = NULL;
	return( start );
}

aSymStat()
{
	static unsigned short count[20];
	int i,n=0,low=0, hi=0;
	register Sym **p;
	float avg=0.0;
	
	for (i=0; i<20; i++) count[i] = 0;
	for (p=table; p<&(table[size]); p++)
	{
		register Sym *q = *p;
		int len;
		
		if ( q != NULL && low==0 ) low = p-table;
		len = 0;
		if ( q != NULL ) fprintf(stderr, "[%d]", p-table);
		while ( q != NULL )
		{
			len++;
			n++;
			fprintf(stderr, " %s", q->symbol);
			q = q->next;
			if ( q == NULL ) fprintf(stderr, "\n");
		}
		count[len]++;
		if ( *p != NULL ) hi = p-table;
	}

	fprintf(stderr, "Storing %d recs used %d hash positions out of %d\n",
					n, size-count[0], size);
	fprintf(stderr, "%f %% utilization\n",
					((float)(size-count[0]))/((float)size));
	for (i=0; i<20; i++)
	{
		if ( count[i] != 0 )
		{
			avg += (((float)(i*count[i]))/((float)n)) * i;
			fprintf(stderr, "Bucket len %d == %d (%f %% of recs)\n",
							i, count[i], ((float)(i*count[i]))/((float)n));
		}
	}
	fprintf(stderr, "Avg bucket length %f\n", avg);
	fprintf(stderr, "Range of hash function: %d..%d\n", low, hi);
}

/*
 * Given a string, this function allocates and returns a pointer to a
 * symbol table record whose "symbol" pointer is reset to a position
 * in the string table.
 */
Sym *
aSymNew(text)
char *text;
{
	Sym *p;
	char *aSymSaveStr();
	
	if ( (p = (Sym *) calloc(1,sizeof(Sym))) == 0 )
	{
		fprintf(stderr,"Out of memory\n");
		exit(1);
	}
	p->symbol = aSymSaveStr(text);
	
	return(p);
}

/* Add a string to the string table and return a pointer to it.
 * Bump the pointer into the string table to next avail position.
 */
char *
aSymSaveStr(s)
register char *s;
{
	register char *start=strp;

	while ( *s != '\0' ) { *strp++ = *s++; }
	*strp++ = '\0';

	return( start );
}
SHAR_EOF
fi # end of overwriting check
if test -f 'sym.h'
then
	echo shar: will not over-write existing file "'sym.h'"
else
cat << \SHAR_EOF > 'sym.h'

typedef struct symrec {
			char *symbol;
			struct symrec *next, *prev, **head, *scope;
			int token;
			int level;
		} Sym, *SymPtr;

Sym *aSymGet();
Sym *aSymNew();
Sym *aSymRmScope();
Sym **aSymScope();
char *aSymSaveStr();
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0
