[net.sources] YACC + ATTRIBUTES

henk@dutesta.UUCP (Henk Hesselink) (11/18/83)

enjoy!!!

CUT AT THE DOTTED LINE AND FEED TO /BIN/SH
------------------------------------------------------------------------
echo x - READ.ME
cat > READ.ME <<'!End-Of-READ.ME!'

YACC PREPROCESSOR

In this directory the sources are included of a very simple, but
useful, preprocessor for YACC. The preprocessor accepts an extension
of the usual YACC input, generates some code for the proper manipulation
of attributes and generates output that is legal input to YACC.
A simple example, named example, is included in this directory.
The only way to call the preprocessor is

	prep inputfile outputfile

A functional description of the preprocessor can be found in
SIGPLAN NOTICES, 18 (10) October 1983.
Assembling a runnable version of the preprocessor should give no problems,
just run the makefile. There might be a slight problem with
identifiernames, our PWB C compiler only uses the first 8 characters.
I usually use longer names but the tails of identifiers can differ
now and then.

				Good luck,
				j van katwijk
			..!{decvax,philabs}!mcvax!dutesta!katwijk
!End-Of-READ.ME!
echo x - ex2
cat > ex2 <<'!End-Of-ex2!'
%token	ONE
%token	TWO
%token	THREE
%token	FOUR
%token	FIVE
%token	SIX
%token	SEVEN
%token	EIGHT
%token	NINE
%token	DOT
%attributes	number (^float)
%attribute	front (^int)
%attribute	back (^int, float)
%attribute	fd (|int, ^float)
%attribute	id (^int)
%attribute	zero_th_digit (^int)
%attribute	inc_dig_pos (|int, float, ^int)

%%
number (^f_val):
		front (^i_val) =
		{ $f_val = (float) $i_val;
		} |
		front (^i_val) DOT back (^p, ffract) =
		{ $f_val = (float) $i_val + $ffract;
		} ;

front (^i_val):	id (^d_val) |
		front (^o_ival) id (^d_val) =
		{ $i_val = 10 * $o_ival + $d_val;
		} ;

back (^pos, ffract):
		zero_th_digit (^pos1) fd (|pos1, ^val) |
		back (^o_pos, ofval) inc_dig_pos (|o_pos, ofval, ^npos)
						fd (|npos, ^val) =
		{ $ffract = $ofval + $val;
		} ;

fd (|pos, ^val):
		id (^digit_val) =
		{ $val = ( (float) $digit_val) / (power (10, $pos));
		} ;
zero_th_digit (^pos):
		=
		{ $pos = 1;
		} ;

inc_dig_pos (|o_pos, dummy, ^n_pos) :
		=
		{ $n_pos = $o_pos + 1;
		} |
		ONE =
		{ $digit_val = 1;
		} |
		TWO =
		{ $digit_val = 2;
		} |
		THREE =
		{ $digit_val = 3;
		} |
		FOUR =
		{ $digit_val = 4;
		} |
		FIVE =
		{ $digit_val = 5;
		} |
		SIX =
		{ $digit_val = 6;
		} |
		SEVEN =
		{ $digit_val = 7;
		} |
		EIGHT =
		{ $digit_val = 8;
		} |
		NINE =
		{ $digit_val = 9;
		} ;
%%
!End-Of-ex2!
echo x - example
cat > example <<'!End-Of-example!'
%token	ONE
%token	TWO
%token	THREE
%token	FOUR
%token	FIVE
%token	SIX
%token	SEVEN
%token	EIGHT
%token	NINE
%token	DOT
%attributes	number (^float)
%attribute	front (^int)
%attribute	back (^int, float)
%attribute	fd (|int, ^float)
%attribute	id (^int)
%attribute	zero_th_digit (^int)
%attribute	inc_dig_pos (|int, float, ^int)

%%
number (^f_val):
		front (^i_val) =
		{ $f_val = (float) $i_val;
		} |
		front (^i_val) DOT back (^p, ffract) =
		{ $f_val = (float) $i_val + $ffract;
		} ;

front (^i_val):	id (^d_val) |
		front (^o_ival) id (^d_val) =
		{ $i_val = 10 * $o_ival + $d_val;
		} ;

back (^pos, ffract):
		zero_th_digit (^pos1) fd (|pos1, ^val) |
		back (^o_pos, ofval) inc_dig_pos (|o_pos, ofval, ^npos)
						fd (|npos, ^val) =
		{ $ffract = $ofval + $val;
		} ;

fd (|pos, ^val):
		id (^digit_val) =
		{ $val = ( (float) $digit_val) / (power (10, $pos));
		} ;
zero_th_digit (^pos):
		=
		{ $pos = 1;
		} ;

inc_dig_pos (|o_pos, dummy, ^n_pos) :
		=
		{ $n_pos = $o_pos + 1;
		} ;
id (^digit_val):
		ONE =
		{ $digit_val = 1;
		} |
		TWO =
		{ $digit_val = 2;
		} |
		THREE =
		{ $digit_val = 3;
		} |
		FOUR =
		{ $digit_val = 4;
		} |
		FIVE =
		{ $digit_val = 5;
		} |
		SIX =
		{ $digit_val = 6;
		} |
		SEVEN =
		{ $digit_val = 7;
		} |
		EIGHT =
		{ $digit_val = 8;
		} |
		NINE =
		{ $digit_val = 9;
		} ;
%%
!End-Of-example!
echo x - makefile
cat > makefile <<'!End-Of-makefile!'
# makefile for yacc preprocesor
CFLAGS = -c -O
DEBUG =
LIBS =
MACH = -DPDP11


.c.o:
	cc $(CFLAGS) $(DEBUG) $<

prep:	prep.h prep1.o prep2.o prep3.o prep4.o
	cc -n -o prep prep4.o prep[123].o $(LIBS)
	size prep
!End-Of-makefile!
echo x - prep.h
cat > prep.h <<'!End-Of-prep.h!'
#
/*
 *	common structures, definitions and so on
 */


/*
 *
 *	J van Katwijk
 *	Delft University of Technology,
 *	Department of Mathematics,
 *	132 Julianalaan
 *	Delft, The Netherlands
 *
 *	See for a functional description:
 *
 *	SIGPLAN NOTICES
 *	October 1983, 18 (10) pp 12 .. 16
 */
#define	MAXATTR	10
#define	PAR_SIZ	10
#define	TAGSIZE	3000
#define MAXDEF	20		/* I donot know */
#define	NONTERM	200		/* include .../dextern?? */
#define	WSTACKSIZE	40	/* arbitrary choice	*/
#define	OUTSTACKSIZE	20	/* idem			*/

#define	NAMESIZE	25	/* idem			*/

#define	FATAL	030
#define	WARNING	040

#define	AS_LOCAL	010
#define	AS_STACK	020
#define	LOC_STRING	"_L%dL_"

struct type_elem {
	int un_number;		/* union field number */
	char *type_name;	/* type to be united  */
};

struct param {
	int par_no;
	int direction;	/* INPUT or OUTPUT */
	struct type_elem *par_desc;
};

struct att_def {
	int i_par, o_par;
	struct param attributes [MAXATTR];
	char *nonterm;
	char hasdefinition;
};

struct stack_elem {
	char par_name [PAR_SIZ];	/* keep it simple */
	struct type_elem *par_def;
	struct {
		char how_to_access;
		int ac_offset;
		int ac_lab;
	} access;		/* for access function */
};

/*
 *	some token definitions
 */
#define	ENDFILE	0
#define	COLON	1
#define	SEMI	2
#define	BAR	3
#define	INPUT	3	/* oh yes !!! */
#define	EQ_SYMB	4
#define	IDENT	5
#define	TERM	6
#define	LEFT	7
#define	BINARY	8
#define	RIGHT	9
#define	MARK	10
#define	PREC	11
#define	LCURL	12
#define	START	13
#define	TYPE	14
#define	UNION	15
#define	ATTR_DEF	16
#define	COMMA	17
#define	LPAR	18
#define	RPAR	19
#define	OUTPUT	20
#define	NUMBER	21


extern	FILE	*finput, *foutput;
extern	int	lineno;
extern	int	tok;
extern	char	tokname[];
extern	char	*infile;
extern		error ();

extern	struct att_def *lookup ();

#define	islower(x)	('a' <= x && x <= 'z')
#define	isupper(x)	('A' <= x && x <= 'Z')
#define	isdigit(x)	('0' <= x && x <= '9')
!End-Of-prep.h!
echo x - prep1.c
cat > prep1.c <<'!End-Of-prep1.c!'
#
#include	<stdio.h>
#include	"prep.h"

/*
 *
 *	J van Katwijk
 *	Delft University of Technology,
 *	Department of Mathematics,
 *	132 Julianalaan
 *	Delft, The Netherlands
 *
 *	See for a functional description:
 *
 *	SIGPLAN NOTICES
 *	October 1983, 18 (10) pp 12 .. 16
 */

/*
 *
 *      Some notes:
 *
 *


	Two stacks are maintained, a working stack and
	a destination stack.
	The latter one is some coding of the situation to
	be achieved after the reduction.
	The working stack is basically used to compute the
	stack layout at the moment of reduction.
	During the way up to get there, the stack is
	used to verify the ordering and typing of the
	input attributes.
	At the reductionpoint two cases must be distinguished:

	-       The workstack contains only input attributes,
		i.e. those attributes inherited from the
		lhs of the rule

		In this case the runtime stack will be extended
		to contain the output attributes of the lhs symbol.
		The output attributes are made addressable on this
		stack.
		No end of reduction code is further been generated.

	-       The workstack contains also output attributes.
		In order to avoid temporarily sharing of the
		stack locations, the output parameters of the
		lhs symbol of the rule are made addressable as
		ordinary local variables. (These variables
		are declared with unusual names etc.). At the
		end of the reduction code the runtime stack
		is adjusted and the preprocessor generated
		temp's are stored on the stack.
 */

/*
 * rules:
 *      definitie : attr_def symbol [ ( [[|inputdefs]^outputdefs]) ]
 *
 *      rule : lhs : alternative {|alternative} ;
 *
 *
 *      alternative : [ {member} ] [= action]
 *
 *      member : symbol [ ( [|inputlist][^outputlist]) ]
 *
 */
proc_def ()     /* process a definition */
{
	register char *curr_def;

	if (tok != ATTR_DEF)
	   return;      /* cannot happen */

	tok = gettok ();
	if (tok != IDENT)
	   error (FATAL, "syntax error in attribute definition");

	curr_def = new_def (tokname);

	tok = gettok ();
	if (tok != LPAR)
	   return;

	tok = gettok ();
	if (tok == INPUT)
	   proc_intypes (curr_def);
	if (tok == OUTPUT)
	   proc_outtypes (curr_def);

	if (tok != RPAR)
	   error (FATAL, "syntax error in definition for %s",
						curr_def -> nonterm);
	tok = gettok ();
	return;
}

proc_intypes (definition)
register struct att_def *definition;
{
	register int i = 0;
	if (tok != INPUT)
	   return;      /* cannot happen */

	tok = gettok ();
	while (tok == IDENT)
	{ set_input (definition, tokname);
	  tok = gettok ();
	  if (tok == RPAR)
	     return;
	  if (tok != COMMA)
	     error (FATAL, "syntax error (missing comma) in def %s",
							definition -> nonterm);

	  tok = gettok ();
	}

	if (tok != OUTPUT)
	   error (FATAL, "syntax error (missing ^) def %s",
						definition -> nonterm);

	return;
}

proc_outtypes (definition)
register struct att_def *definition;
{
	if (tok != OUTPUT)
	   return;      /* cannot happen */

	tok = gettok ();
	while (tok == IDENT)
	{
	   set_output (definition, tokname);
	   tok = gettok ();
	   if (tok == RPAR)
	      return;
	   if (tok != COMMA)
	      error (FATAL, "syntax error (comma expected) def %s",
						definition -> nonterm);

	   tok = gettok ();
	}

	error (FATAL, "syntax error, identifier expected in def for %s",
						definition -> nonterm);
	return;
}

/*
 *      Now for the rule recorgnition, recall that
 *      the symbols of the rules themselves still
 *      have to be processed by YACC.
 */

struct att_def *lhs_side ()
{
	register int par_i_cnt =0;
	register int par_o_cnt =0;

	register struct att_def *lhs_member;

	if (tok != IDENT)
	   error (FATAL, "syntax error in lhs");

	fprintf (foutput,"%s	:", tokname);
	lhs_member = lookup (tokname);

	tok = gettok ();
	if (tok == LPAR)
	{
	   if (lhs_member == 0)
	      error (FATAL, "illegal left hand side %s", tokname);

	   setdefined (lhs_member);
	   tok = gettok ();
	   if (tok != INPUT)
	      goto try_output;

	   tok = gettok ();
	   while (tok == IDENT)
	   {  par_i_cnt ++;
	      push (lhs_member, par_i_cnt, tokname);
	      tok = gettok ();
	      if (tok == RPAR)
	         goto lhs_check;

	      if (tok != COMMA)
	         error (FATAL, "syntax error (comma expected) lhs %s",
							lhs_member -> nonterm);
	      tok = gettok ();
	   }

try_output:
	   if (tok != OUTPUT)
	      error (FATAL, "^ expected in lhs %s", lhs_member -> nonterm);

	   tok = gettok ();
	   while (tok == IDENT)
	   { par_o_cnt++;
	     dest_par (lhs_member, par_o_cnt, tokname);
	     tok = gettok ();
	     if (tok == RPAR)
	        goto lhs_check;

	     if (tok != COMMA)
		error (FATAL, "syntax error (comma expected) lhs %s",
							lhs_member -> nonterm);
	     tok = gettok ();
	   }

lhs_check:
	if (tok != RPAR)
	   error (FATAL, ") expected, lhs %s", lhs_member -> nonterm);
	tok = gettok ();
	}

	if (par_i_cnt != in_pars (lhs_member) ||
	    par_o_cnt != out_pars(lhs_member) )
	   error (FATAL, "incorrect number parameters for %s",
						lhs_member -> nonterm);

	return lhs_member;
}

rule ()
{
	register struct att_def *lhs_def;

	init_stack ();
	lhs_def = lhs_side ();
	if (tok != COLON)
	   error (FATAL, " `:' expected following %s",
					lhs_def -> nonterm);

	tok = gettok ();

	proc_alternative (lhs_def);
	while (tok == BAR)
	    { fprintf (foutput, "\n		|");
	      re_init_stack ();
	      tok = gettok ();
	      proc_alternative (lhs_def);
	    }

	if (tok != SEMI)
	   error (FATAL, "`;' expected  %s", lhs_def -> nonterm);

	fprintf (foutput, ";\n");
}

proc_alternative (lefthand)
register struct stack_elem *lefthand;
{
	while (tok == IDENT)
	   { fprintf (foutput, "%s ", tokname);
	     proc_member (lefthand);
	   }

	if (tok == EQ_SYMB)
	   { fprintf (foutput, "=\n");
	     tok = gettok ();
	     cpyact ();
	     tok = gettok ();
	   }
	else
	   adjust_stack ();
}


proc_member (ctxt)
register struct stack_elem *ctxt;
{
	register int in_index, out_index;
	register struct att_def *curr_member;

	if (tok != IDENT)
	   return;      /* cannot happen */

	curr_member = lookup (tokname);

	tok = gettok ();
	if (tok != LPAR)
	   { if (curr_member == (struct att_def *)0)
	        return;

	     if (in_pars (curr_member) + out_pars (curr_member) != 0)
		error (FATAL, "incorrect number of parameters %s",
						ctxt -> nonterm);
	     return;
	   }

	if (curr_member == (struct att_def *)0)	/* and tok == ( */
	   error (FATAL, "parameters with non specified symbol rule %s",
						ctxt -> nonterm);

	tok = gettok ();
	in_index = 0;
	out_index = 0;

	if (tok == INPUT)
	   { tok = gettok ();
	     while (tok == IDENT)
	     {   in_index++;
	         veri_in (curr_member, in_index, tokname);
	         tok = gettok ();
	         if (tok == RPAR)
	            goto par_check;

	         if (tok != COMMA)
		    error (FATAL, "comma expected (member %s)",
						curr_member -> nonterm);

		 tok = gettok ();
	     }
	   }
	if (tok != OUTPUT)
	   error (FATAL, "^ expected  (member %s)",
						curr_member -> nonterm);

	tok = gettok ();
	while (tok == IDENT)
	{   out_index++;
	    veri_out (curr_member, out_index, tokname);
	    tok = gettok ();
	    if (tok == RPAR)
	       break;
	    if (tok != COMMA)
	       error (FATAL, "`,' expected (member %s)",
						curr_member -> nonterm);
	    tok = gettok ();
	}

par_check:
	if ( (in_pars (curr_member) != in_index) ||
	     (out_pars (curr_member) != out_index) )
	   error (FATAL, "incorrect number of parameters (member %s)",
						curr_member -> nonterm);

	if (tok != RPAR)
	   error (FATAL, "`)' expected (member %s)",
						curr_member -> nonterm);
	tok = gettok ();
}


!End-Of-prep1.c!
echo x - prep2.c
cat > prep2.c <<'!End-Of-prep2.c!'
#
#include	<stdio.h>
#include	"prep.h"

/*
 *
 *	J van Katwijk
 *	Delft University of Technology,
 *	Department of Mathematics,
 *	132 Julianalaan
 *	Delft, The Netherlands
 *
 *	See for a functional description:
 *
 *	SIGPLAN NOTICES
 *	October 1983, 18 (10) pp 12 .. 16
 */
/*
 *	scanning/copying routines for YACC preprocessor
 *
 *	j van katwijk
 *
 */
static char c;
static int is_digit (x)
register char x;
{
	return '0' <= x && x <= '9';
}

static int is_letter(x)
register char x;
{
	return ('A' <= x && x <= 'Z') || ('a' <= x && x <= 'z');
}

int is_namelem (x)
register int x;
{
	return (islower(x) ||
		isupper(x) ||
		c == '_'   ||
		c == '.'   ||
		c == '$' );
}

int gettok ()
{
	register int i, base;
	static int peekline;
	register int match, reserve;

/* :
 */
begin:
	reserve = 0;
	lineno += peekline;
	peekline = 0;

	c = getc (finput);
	while (0 <= c && c <= ' ')
	{ if (c == '\n')
	     lineno++;
	  c = getc (finput);
	}

	if (c == '/')   /* go for comment */
	   { lineno += skipcom ();
	     goto begin;
	   }

	switch (c)
	{
	case EOF:
		return ENDFILE;
	case ':':
		return COLON;

	case ';':
		return SEMI;

	case '|':
		return BAR;


	case '{':
		ungetc (c, finput);
		return (EQ_SYMB);
		/* action .... */

	case '<':       /* only for the sake of YACC */
		i = 0;
		while ( (c = getc (finput)) != '>' && c >= 0 && c != 
'\n')
		    { tokname [i] = c;
		      if (++i >= NAMESIZE) --i;
		    }

		if (c!= '>')
		   error (FATAL, "unterminated <...> clause");

		tokname [i] = '\0';
		return (IDENT);

	case ',':
		return COMMA;

	case '^':
		return OUTPUT;

	case '=':
		return EQ_SYMB;

	case '(':
		return LPAR;

	case ')':
		return RPAR;


	case '"':
	case '\'':
		match = c;
		tokname [0] = ' ';
		i = 1;

		for (;;)
		{ c = getc (finput);
		  if (c == '\n' || c == EOF)
		     error (FATAL, "illegal or missing %c", match);
		  if (c == '\\')
		     { c = getc (finput);
		       tokname [i] = '\\';
		       if (++i >= NAMESIZE) --i;
		     }
		  else
		     if (c == match)
			break;

		  tokname [i] = c;
		  if (++i >= NAMESIZE) --i;
		}

		break;

	case '%':
	case '\\':
		switch (c = getc (finput))
		{
			case '0':       return TERM;
			case '<':       return LEFT;
			case '2':       return (BINARY);
			case '>':       return (RIGHT);
			case '%':
			case '\\':      return (MARK);
			case '=':       return (PREC);
			case '{':       return (LCURL);

			default:        reserve = 1;
		}

/* bah, johnson falls through, we follow here:
 */
	default:
		if (isdigit (c))
		   { i = 0;
		     while (isdigit (c))
			 { tokname [i] = c;
			   if (++i >= NAMESIZE) --i;
			   c = getc (finput);
			 }
		     ungetc (c, finput);
		     return (NUMBER);
		   }
		else
		if (is_namelem (c))
		   { i = 0;
		     while (is_namelem (c) || is_digit (c))
			 { tokname [i] = c;
			   if (reserve && isupper(c))
			      tokname [i] += 'a' - 'A';
			   if (++i >= NAMESIZE) --i;
			   c = getc (finput);
			 }
		   }
		else
		   return c;

		ungetc (c, finput);
		}

/* look for reserved words */
	tokname [i] = '\0';

	if (reserve)
	   {
		if (!strcmp (tokname, "term")) return TERM;
		if (!strcmp (tokname, "token")) return TERM;
		if (!strcmp (tokname, "left")) return LEFT;
		if (!strcmp (tokname, "nonassoc")) return BINARY;
		if (!strcmp (tokname, "binary")) return BINARY;
		if (!strcmp (tokname, "right")) return RIGHT;
		if (!strcmp (tokname, "prec")) return RIGHT;
		if (!strcmp (tokname, "start")) return START;
		if (!strcmp (tokname, "type")) return TYPE;
		if (!strcmp (tokname, "union")) return UNION;
		if (!strcmp (tokname, "attributes")) return ATTR_DEF;
		if (!strcmp (tokname, "attribute")) return ATTR_DEF;
		error (FATAL, "non recognized keyword %s", tokname);
	   }

	return (IDENT);
}

/*
 *      copy the union
 *
 */



cpyunion ()
{
	int level, c;
	fprintf (foutput, "\n# line %d \"%s\"\n", lineno, infile);
	fprintf (foutput, "%%union");

	level = 0;
	for (;;)
	{  if ((c = getc (finput)) <0 )
	      error (FATAL, "EOF when parsing %%union");

	   fprintf (foutput, "%c", c);
	   switch (c)
	   {
		case '\n':
			++lineno; break;

		case '{':
			++level;
			break;

		case '}':
			level--;
			if (level == 0)
			   return;
	    }
	  }
}



cpycode ()      /* copies code between { and } */
{
	register int c;
	c = getc (finput);
	if (c == '\n')
	   { c = getc (finput);
	     lineno ++;
	   }

	fprintf (foutput, "\\{");
	while (c >= 0)
	{
		if (c == '\\')
		   if ( (c = getc (finput)) == '}')
		      { fprintf (foutput, "\\}");
		        return;
		      }
		   else
		      fprintf (foutput, "\\");

		if (c == '%')
		   if ( (c = getc (finput)) == '}')
		      { fprintf (foutput, "%}");
		        return;
		      }
		   else
		      fprintf (foutput, "%");

	
		fprintf (foutput, "%c", c);
		if (c == '\n') lineno ++;
		c = getc (finput);
	}

	error (FATAL, "error before %%}");
}

skipcom ()	/* guess what */
{
	register int c;
	register int i = 0;	/* number of lines skipped */

	if (getc (finput) != '*')
	   error (FATAL, "illegal comment");

	c = getc (finput);
	while (c != EOF)
	{
		while (c == '*')
		   if ( (c = getc (finput)) == '/') return i;
		if (c == '\n') i++;
		c = getc (finput);
	}

	error (FATAL, "error EOF within comment");
}

cpyact ()	/* copy C action to closing ; or } */
{
	int brac, c, match, j, s, tok;

	pref_stackadjust ();

	brac = 0;

loop:
	c = getc (finput);

swt:
	switch (c)
	{
	case ';':
		if (brac == 0)
		   { post_adjuststack ();
		     fprintf (foutput, "%c", c);
		     return;
		   }
		goto lcopy;

	case '{':
		brac++;
		goto lcopy;

	case '$':
		s = 1;
		tok = -1;
		c = getc (finput);
		if (c == '<')	/* type description */
		   { ungetc (c, finput);
		     if (gettok () != IDENT)
		        error (FATAL, "bad syntax on $<..> clause");
		     fprintf (foutput, "<%s>", tokname);
		     c = getc (finput);
		   }

		if (c == '$')
		   {  fprintf (foutput, "$$");
		      goto loop;
		   }

		if (c == '-')
		   { s = -s;
		     c = getc (finput);
		   }
		if (isdigit (c))
		   { j = 0;
		     while (isdigit (c))
		     {  j = j * 10 + c - '0';
		        c = getc (finput);
		     }
		     j = j * s;
		     fprintf (foutput, "$%d", j);
		     goto swt;
		   }

		if (is_letter (c))
		   { ungetc (c, finput);
		     tok = gettok ();
		     if (tok != IDENT)
		        error (FATAL, "illegal $construct");
		     fprintf (foutput, "%s", address_of(tokname));
		     goto loop;
		   }

		fprintf (foutput, "$");
		if (s < 0)
		   fprintf (foutput, "-");

		goto swt;


	case '}':
		if (--brac > 0)
		   goto lcopy;

		post_adjuststack ();
		fprintf (foutput, "%c", c);
		return;

	case '/':
		/* look for comment */
		fprintf (foutput, "%c", c);
		c = getc (finput);
		if (c != '*') goto swt;

		while (c != EOF)
		{
			while (c == '*')
			{
				fprintf (foutput, "%c", c);
				if ( (c = getc (finput)) == '/')
				     goto lcopy;
			}
		        fprintf (foutput, "%c", c);
			if (c == '\n') lineno++;
			c = getc (finput);
		}
		error (FATAL, "EOF within comment");

	case '\'':
		match = '\'';
		goto string;

	case '"':
		match = '"';

string:
		fprintf (foutput, "%c", c);
		while ( (c = getc (finput)) != EOF)
		{
			if (c == '\\')
			{
				fprintf (foutput, "%c", c);
				c = getc (finput);
				if (c == '\n') lineno ++;
			}
			else
			if (c == match) goto lcopy;
			else
			if (c == '\n')
			   error (FATAL, "newline in string or char const");

			fprintf (foutput, "%c", c);
		}

		error (FATAL, "EOF in string or character constant");

	case EOF:
		error ("action does not terminate");

	case '\n':
		lineno++;
		goto lcopy;

	}

lcopy:
	fprintf (foutput, "%c", c);
	goto loop;
}

!End-Of-prep2.c!
echo x - prep3.c
cat > prep3.c <<'!End-Of-prep3.c!'
#
#include	<stdio.h>
#include	"prep.h"

/*
 *
 *	J van Katwijk
 *	Delft University of Technology,
 *	Department of Mathematics,
 *	132 Julianalaan
 *	Delft, The Netherlands
 *
 *	See for a functional description:
 *
 *	SIGPLAN NOTICES
 *	October 1983, 18 (10) pp 12 .. 16
 */
/*
 *	low level data/stack management routines for
 *	YACC preprocessor.
 *
 */

/*
 *	tags:
 */
static char name_array [TAGSIZE];
static char *tag_base = &name_array [0];


static int eq_tags (x, y)
register char *x, *y;
{
	while (*x == *y && *x != (char)0 && *y != (char)0)
	      { x++;
	        y++;
	      }

	return (*x == *y);
}

char *new_tag (t)
register char *t;
{
	register char *l_base = tag_base;

	while ( (*tag_base = *t) != (char)0)
	{ tag_base ++;
	  t++;
	}

	tag_base ++;	/* set for next definition */
	return l_base;
}

/*
 *	dealing with types and unions
 */

struct {
	int el_cnt;
	struct type_elem descr [MAXDEF];
} type_descr;

/*
 *	somewhere a definition of a union of all
 *	attribute element types is generated:
 */

print_union ()
{
	register int i;
	register struct type_elem *x;

	if (type_descr. el_cnt == 0) return;	/* nothing */

	fprintf (foutput, "\n#ifndef ATT_SIZE\n");
	fprintf (foutput, "#define ATT_SIZE	150\n");
	fprintf (foutput, "#endif\n");
	fprintf (foutput, "\nunion _attr_elem {\n");

	for (i = 0; i < type_descr. el_cnt; i++)
	{   x = &type_descr.descr [i];
	    fprintf (foutput, "  %s  _t%d;\n",
				x -> type_name, x -> un_number);
	}

	fprintf (foutput, "} _attr_stack [ATT_SIZE];\n");
	fprintf (foutput, "union _attr_elem *_ap =");
	fprintf (foutput, "      &_attr_stack [ATT_SIZE - 1];\n");
}

struct type_elem *add_type (t)
register char *t;
{
	register int i;
	register struct type_elem *x, *y;

	for (i = 0; i < type_descr. el_cnt; i++)
	    { x = &type_descr . descr [i];
	      if (eq_tags (t, x -> type_name))
	         return x;
	    }

	if (type_descr.el_cnt >= MAXDEF)
	   error (FATAL,
		   "too many attribute defs: line %d\n", lineno);

	x = &type_descr. descr [type_descr. el_cnt];
	x -> type_name = new_tag (t);
	x -> un_number = type_descr. el_cnt ++;

	return x;
}


/*
 *	attribute definitions
 */
struct att_def attrib_defs [NONTERM];

static int ndefs = 0;


/*
 *	functions to be defined:
 *
 *		set_input	enter input attrib in def
 *		set_output	enter output attrib in def
 *		in_pars		number of inpars
 *		out_pars	number of outpars
 *		new_def		enter new non terminal
 *		lookup		look for nonterm.
 *		checkdefs	check all attributed symbols to be on lhs
 *		setdefined	set non terminal defined as lhs
 */

setdefined (t)
struct att_def *t;
{
	if (t != (char)0)
	   t -> hasdefinition = (char)1;
}

checkdefs ()
{
	register int i;

	for (i = 0; i < ndefs; i ++)
	    if (attrib_defs [i]. hasdefinition == (char) 0)
	       error (WARNING, "%s not as lhs", attrib_defs [i]. nonterm);
}

struct att_def *lookup (t)
register char *t;
{
	register int i;

	for (i = 0; i < ndefs; i++)
	    if (eq_tags (t, attrib_defs [i]. nonterm))
	       return &attrib_defs [i];

	return (struct att_def *)0;
}

struct att_def *new_def (t)
register char *t;
{
	register struct att_def *x;

	if (lookup (t) != (struct att_def *)0)
	   error (FATAL, "double definition line %d\n", lineno);

	if (ndefs >= NONTERM)
	   error (FATAL, "too much non terminals line %d\n", lineno);

	x = &attrib_defs [ndefs ++];
	x -> i_par = 0;
	x -> o_par = 0;
	x -> nonterm = new_tag (t);
	x -> hasdefinition = (char)0;

	return x;
}

set_input (def, typename)
register struct att_def *def;
register char *typename;
{
	register struct att_def *y;

	if (def -> i_par >= MAXATTR)
	   error (FATAL, "too many input attribs line %d\n", lineno);

	def -> i_par++;
	y = &def -> attributes [def -> i_par];

	y -> par_no = def -> i_par;
	y -> direction = INPUT;
	y -> par_desc = add_type (typename);
}

set_output (def, type_name)
register struct att_def *def;
register char *type_name;
{
	register struct att_def *y;

	if (def -> i_par + def -> o_par >= MAXATTR)
	   error (FATAL, "too many input/output attr's line %d\n", lineno);

	def -> o_par++;

	y = &def -> attributes [def -> i_par + def -> o_par];
	y -> par_no = def -> o_par;
	y -> direction = OUTPUT;
	y -> par_desc = add_type (type_name);
}

int in_pars (def)
register struct att_def *def;
{
	if (def == (struct att_def *)0) return 0;
	return def -> i_par;
}

int out_pars (def)
register struct att_def *def;
{
	if (def == (struct att_def *)0) return 0;
	return def -> o_par;
}

/*
 *	during the processing of a rule a stack is maintained
 *	for the simulation of the run time behaviour
 */
struct {
	int i_top;		/* input pars lhs	*/
	int o_top;		/* output pars lhs	*/
	int w_top;		/* workstack top	*/

	struct stack_elem work_stack [WSTACKSIZE];
	struct stack_elem out_stack  [OUTSTACKSIZE];
} workstack;
/*
 *
 *	functions available during processing a rule:
 *
 *
 *	init_stack ();
 *
 *	push (def, cnt, tag);	/* lhs input param
 *	dest_par (def, cnt, tag)	/* lhs output param
 *
 *	veri_in (member, parno, tag);
 *	veri_out(member, parnp, tag);
 *
 *	address_of (tag)	/* map into a string used for C 
 *
 *	pref_stackadjust ();	/* code for stack adjustment 
 *	post_stackadjust ();	/* code for stack adjustment 
 */
init_stack ()
{
	workstack. i_top = 0;
	workstack. o_top = 0;
	workstack. w_top = 0;
}

re_init_stack ()
{
	workstack. w_top = workstack. i_top;
}


cp_tag (x, y, cnt)
register char *x, *y;
register int cnt;
{
	while (--cnt >= 0)
	      *y++ = *x++;
}


struct type_elem *get_i_type (def, parno)
register struct att_def *def;
register int parno;
{
	if (parno > def -> i_par)
	   error (FATAL, "too high input param for %s",
					def -> nonterm);

	return (def -> attributes [parno].par_desc);
}

struct type_elem *get_o_type (def, parno)
register struct att_def *def;
register int parno;
{
	if (parno > def -> o_par)
	   error (FATAL, "too high output param number for %s",
						def -> nonterm);

	return (def -> attributes [def -> i_par + parno]. par_desc);
}


push (def, parno, tag)
register struct att_def *def;
register char *tag;
int parno;
{
	register struct stack_elem *x;

	if (workstack. i_top ++ >= WSTACKSIZE)
	   error (FATAL, "too much attributes on workstack line %d\n", lineno);
	x = &workstack. work_stack [workstack. i_top];
	cp_tag (tag, &x -> par_name [0], PAR_SIZ);
	x -> par_def = get_i_type (def, parno);
	workstack. w_top = workstack. i_top;
#ifdef DEBUG
	printf ("push: %s %d %s\n",
				&x -> par_name [0], workstack. i_top,
						x -> par_def -> type_name);
#endif
}

dest_par (def, parno, tag)
register struct att_def *def;
register char *tag;
int parno;
{
	register struct stack_elem *x;

	if (workstack.o_top ++ >= OUTSTACKSIZE)
	   error (FATAL, "too much lhs out attributes line %d\n", lineno);

	x = &workstack. out_stack [workstack. o_top];
	cp_tag (tag, &x -> par_name [0], PAR_SIZ);
	x -> par_def = get_o_type (def, parno);
#ifdef DEBUG
	printf ("dest_par : %s %d %s\n",
			x -> par_name, workstack. o_top,
			x -> par_def -> type_name);
#endif
}

veri_in (def, parno, tag)
register struct att_def *def;
register char *tag;
int parno;
{
	register struct stack_elem *x;

	x = &workstack. work_stack[ workstack. w_top
					- in_pars (def) + parno];
	if (!eq_tags (x -> par_name, tag))
	   error (FATAL, "non matching input name %s", tag);
#ifdef DEBUG
	printf ("veri_in: %s at offset %d\n", tag, 
				workstack. w_top - in_pars (def) + parno);
#endif
}

veri_out (def, parno, tag)
register struct att_def *def;
register char *tag;
int parno;
{
	register struct stack_elem *x;

	if (workstack. w_top++ >= WSTACKSIZE)
	   error (FATAL, "too much attribute values line %d\n", lineno);

	x = &workstack. work_stack [workstack. w_top];
	cp_tag (tag, &x -> par_name [0], PAR_SIZ);
	x -> par_def = get_o_type (def, parno);
#ifdef DEBUG
	printf ("veri_out: %s %d %s\n",
		     x -> par_name, workstack. w_top,
					x -> par_def -> type_name);
#endif
}

/*
 * given the tag of an attribute, translate it into a string
 * containing the 'C' code to adress the element on the
 * attribute stack (or the local....)
 */
struct stack_elem *search_stck (t)
register char *t;
{
	register int i;
	register struct stack_elem *x;

	for (i=1; i <= workstack. o_top; i++)
	    { x = &workstack. out_stack [i];
#ifdef DEBUG
		printf ("search: %s\n", &x -> par_name [0]);
#endif
	      if (eq_tags (t, x -> par_name))
	         return x;
	    }
/*
 *	now on the input stack
 */
	for (i = workstack. w_top; i > 0; i--)
	    { x = &workstack. work_stack [i];
#ifdef DEBUG
		printf ("search: %s\n", x -> par_name);
#endif
	      if (eq_tags (t, x -> par_name))
	         return x;
	    }

	error (FATAL, "definition of attribute %s not found\n", t);
}

char *address_of (tag)
register char *tag;
{
	register struct stack_elem *t;
	static char s [20];	/* most numbers will do */

	t = search_stck (tag);
	if (t -> access.how_to_access == AS_LOCAL)
	   sprintf (s, LOC_STRING, t -> access. ac_lab);
	else
	sprintf (s, "_ap [%d]. _t%d",
			t -> access. ac_offset, t -> par_def -> un_number);

	return s;
}


/*
 *	generate code for stack adjustment and to make
 *	output paramers addressable
 */
pref_stackadjust ()
{
	register struct stack_elem *x;
	register int i;
	register int l_top = 0;

	fprintf (foutput, "{");
	if (workstack. i_top == workstack. w_top)
	   { /* no intermediate results, lengthen
	      * the stack
	      */
	     if (workstack. o_top != 0)
	        fprintf (foutput, "	_ap -= %d;\n",
					workstack. o_top);
	     l_top = workstack. o_top;
	     for (i = workstack. o_top; i >= 1; i--)
	         { x = &workstack. out_stack [i];
		   x -> access.how_to_access = AS_STACK;
		   x -> access. ac_offset = workstack. o_top - i;
	         }
	   }
	else
	/* generate for each output parameter a local
	 */
	for (i = 1; i <= workstack. o_top; i++)
	    { x = &workstack. out_stack [i];
	      x -> access. how_to_access = AS_LOCAL;
	      x -> access.ac_lab = i;

	      fprintf (foutput, "	%s ", x -> par_def -> type_name);
	      fprintf (foutput, LOC_STRING, i);
	      fprintf (foutput, ";\n");
	    }

	for (i = workstack. w_top; i > 0; i--)
	    { x = &workstack. work_stack [i];
	      x -> access.how_to_access = AS_STACK;
	      x -> access.ac_offset = 
				l_top + workstack. w_top - i;
	    }
}

/*
 *	after copying the C actions, we possibly have to adjust
 *	the attribute value stack
 */
post_adjuststack ()
{
	register struct stack_elem *x;
	register int i;

	if (workstack. i_top == workstack. w_top)
	   { /* adjustment already doen, no pushing/popping */
	      fprintf(foutput, "}\n");
	   }
	else
	{ /* generate code for adjusting ap */
	  fprintf (foutput,"	_ap += %d; \n",
				workstack. w_top - workstack. i_top);
	  for (i = 1; i <= workstack. o_top; i++)
	      { x = &workstack. out_stack [i];
	        fprintf (foutput, "--_ap; _ap[0]._t%d = ",
					x -> par_def -> un_number);
	        fprintf (foutput, LOC_STRING,
				        x -> access.ac_lab);
		fprintf (foutput, ";\n");
	      }
	   fprintf (foutput, "	}\n");
	}
}

/*
 *	no yacc actions specified, verify the work/output stack,
 *	adjust if necessary
 */
adjust_stack ()
{
	register int diff;
	register int i;

	diff = workstack. w_top - workstack. i_top - workstack. o_top;

	if (diff != 0)
	   {
		fprintf (foutput, "= {\n");
		fprintf (foutput, "_ap += %d; }\n", diff);
	   }

	if (diff < 0)
	   { error (WARNING, "garbage on extended attribute stack");
	     return;
	   }

	for (i = 1; i <= workstack. o_top; i++)
	    {
		if (workstack. out_stack [workstack. o_top - i + 1]. par_def !=
		    workstack. work_stack [workstack. w_top -i + 1]. par_def)
		   error (WARNING, "unequal default transfers %s",
					workstack. out_stack [i -1]. par_name);
	    }
}
!End-Of-prep3.c!
echo x - prep4.c
cat > prep4.c <<'!End-Of-prep4.c!'
#
#include	<stdio.h>
#include	"prep.h"

/*
 *
 *	J van Katwijk
 *	Delft University of Technology,
 *	Department of Mathematics,
 *	132 Julianalaan
 *	Delft, The Netherlands
 *
 *	See for a functional description:
 *
 *	SIGPLAN NOTICES
 *	October 1983, 18 (10) pp 12 .. 16
 */
FILE *finput, *foutput;
char *infile;
char tokname [NAMESIZE];
int tok;
int lineno = 1;

/*
 *	process the declaration section of a YACC source
 */

prep_decls ()
{
	for (tok = gettok (); tok != MARK && tok != ENDFILE; )
	{
	switch (tok)
	{
		case SEMI:
			fprintf (foutput, ";\n");
			tok = gettok ();
			break;

		case START:
			if ( (tok = gettok ()) != IDENT)
			   error (FATAL, "bad start construct (YACC)");

			fprintf (foutput, "%%start %s\n", tokname);
			tok = gettok ();
			continue;


		case TYPE:
			if ( (tok = gettok ()) != IDENT)
			   error (FATAL, "bad syntax in %%type (YACC)");

			fprintf (foutput, "%%typedef %s ", tokname);

			while (1)
			{ tok = gettok ();
			  switch (tok)
			  {
				case IDENT:
					fprintf (foutput, " %s", tokname);
					continue;

				case COMMA:
					fprintf (foutput, " ,");
					continue;

				case SEMI:
					fprintf (foutput, ";\n");
					tok = gettok ();
					break;

				default:
					break;
			    }

			 break;
			 }
			continue;

		case ATTR_DEF:
			proc_def ();
			continue;

		case UNION:
			/* copy the union declaration to output */
			cpyunion ();
			tok = gettok ();
			continue;


		case LEFT:
		case RIGHT:
		case BINARY:
		case TERM:
			fprintf (foutput, "\n");
			switch (tok)
			{
				case LEFT:
					fprintf (foutput, " %%left");
					break;

				case RIGHT:
					fprintf (foutput, " %%right");
					break;

				case BINARY:
					fprintf (foutput, " %%nonassoc");
					break;

				case TERM:
					fprintf (foutput, " %%term");
					break;
			}


			/* get identifiers so defined */
			tok = gettok ();
			if (tok == IDENT)
			   { fprintf (foutput, " %s", tokname);
			    tok = gettok ();
			   }

			while (1)
			{ switch (tok)
			  {
				case COMMA:
					fprintf (foutput, " ,");
					tok = gettok ();
					break;

				case SEMI:
					fprintf (foutput, " ;\n");
					break;

				case IDENT:
					fprintf (foutput, " %s", tokname);
					tok = gettok ();
					continue;

				}

				break;
			}
			continue;

		case LCURL:
			cpycode ();
			tok = gettok ();
			continue;

		default:
			error (FATAL, "syntax error in def part");
		}
	}

/*
 * tok is either MARK or ENDFILE
 */
	if (tok == ENDFILE)
	   error (FATAL, "unexpected EOF before %%");

}

/*
 *	the rules, that is easy
 */
prep_rules ()
{
	fprintf (foutput, "\n%%%%\n");

	tok = gettok ();
	while (tok != ENDFILE && tok != MARK)
	      { rule ();
		tok = gettok ();
	      }


}

prep_post ()
{
	register int c;

	fprintf (foutput, "\n%%%%\n");

	if (tok == MARK)
	   while ( (c = getc (finput)) != EOF)
	           fprintf (foutput, "%c", c);

	print_union ();	/* the attribute type */
	fprintf (foutput, "\n /* processed by a YACC preprocessor */ \n");
}


/*
 *	temp. main program
 *
 *	for yacc preprocessor
 */

error (x, y, z)
register int x;
register char *y;
register int z;
{
	printf ("\n*** error line %d :", lineno);
	printf (y, z);
	printf ("	***\n");
	if (x == FATAL)
	   exit (1);
}

main (argc, argv)
register char **argv;
register int argc;
{
	if (argc != 3)
	   { printf ("usage: prep infile outfile\n");
	     exit (1);
	   }

	infile = argv [1];
	finput = fopen (infile, "r");
	foutput= fopen (argv [2], "w");
	if (finput == 0)
	   error (FATAL, "cannot read from %s", infile);

	if (foutput == 0)
	   error (FATAL, "cannot write to %s", argv[2]);

	prep_decls ();

	prep_rules ();

	prep_post ();

	checkdefs ();
	fclose (foutput);
}

!End-Of-prep4.c!
echo x - rec
cat > rec <<'!End-Of-rec!'
record_type:	record_start (^x, y, z, b) field_list (|x, y, z, b)
				END RECORD =
		{ restore_env ($1, $x);
		} ;

record_start (^x, y, z, b):
		type_start (^list) IS RECORD =
		{ register ac t, r;
		  t = $list;
		  r = alloc (XRECTYPE);
		  r -> tag = $1;
		  introduce (r);
		  $x = new_env (r);
		  $y = r;
		  $z = r;
		  $b = FALSE;
		  $$ = r;
		  list_intro (t);
		} ;

type_start(^list):	type_id =
		{ $list = NULL;	/* discriminants */
		} |
		type_id disc_part =
		{ $list = $2;
		} ;

type_id:	TYPE IDENT =
		{ $$ = $2;	/* keep the tag */
		} ;

field_spec:	subtype_ind opt_expr =
		{ $$ = make_desc ($1, KCOMP, $2);
		} ;

var_part (|y, z, b) :
		selection (|y, z, b) alternatives (|y, z, b)
				END CASE SEM_COL;

selection (|y, z, b):
		CASE s_name IS =
		{ register ac t;
		  t = alloc (XDISCR);
		  t -> comp = $2;
		  $z -> dis = t;
		} ;

alternatives (|y, z, b):
		variant (|y, z, b) |
		alternatives (|y, z, b) variant (|y, z, b) ;

variant (|y, z, b):
		selector (|y, z, b, ^xx, yy, zz, bb) ARROW
					field_list (|xx, yy, zz, bb) =
		{ restore_env ($1, $xx);
		} ;

selector (|y, z, b, ^xx, yy, zz, bb):
		WHEN choices (^others) =
		{ register ac t;
		  if ($bb)
		     warning ("too much alternatives %s", $y -> tag);
		  $b = $others;

		  t = alloc (XVARIANT);
		  introduce (t);
		  t -> varchoice = $2;
		  $xx = new_env (t);
		  $bb = FALSE;
		  $zz = t;
		  $yy = $y;
		  $$ = t;
		} ;

choices (^others):	OTHERS =
		{ register ac t = alloc (XRANGE);
		  $$ = t;
		  $others = TRUE;
		} |
		choice_list (^last) =
		{ $others = FALSE;
		} ;

choice_list (^last):	choice =
		{ $last = $1;
		} |
		choice_list (^l2) BAR choice =
		{ $l2 -> next = $3;
		  $last = $3;
		} ;

choice:		ls_name (^l1, l2) range_constraint =
		{ $2 -> rangetype = $1;
		  $$ = $2;
		} |
		simple_expr =
		{ register ac t;
		  t = alloc (XRANGE);
		  t -> frangeexp = $1;
		  $$ = t;
		} |
		range ;
!End-Of-rec!
-- 
Henk Hesselink, Delft Univ. of Technology
..!{decvax,philabs}!mcvax!dutesta!henk