/*	parse.ch: headers for parse class  */

/*
	$Disclaimer: 
*Permission to use, copy, modify, and distribute this software and its 
*documentation for any purpose is hereby granted without fee, 
*provided that the above copyright notice appear in all copies and that 
*both that copyright notice, this permission notice, and the following 
*disclaimer appear in supporting documentation, and that the names of 
*IBM, Carnegie Mellon University, and other copyright holders, not be 
*used in advertising or publicity pertaining to distribution of the software 
*without specific, written prior permission.
*
*IBM, CARNEGIE MELLON UNIVERSITY, AND THE OTHER COPYRIGHT HOLDERS 
*DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 
*ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT 
*SHALL IBM, CARNEGIE MELLON UNIVERSITY, OR ANY OTHER COPYRIGHT HOLDER 
*BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 
*DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 
*WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 
*ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
*OF THIS SOFTWARE.
* $
*/

/*
	Copyright Carnegie Mellon University 1992 - All rights reserved
	$Disclaimer: 
*Permission to use, copy, modify, and distribute this software and its 
*documentation for any purpose is hereby granted without fee, 
*provided that the above copyright notice appear in all copies and that 
*both that copyright notice, this permission notice, and the following 
*disclaimer appear in supporting documentation, and that the names of 
*IBM, Carnegie Mellon University, and other copyright holders, not be 
*used in advertising or publicity pertaining to distribution of the software 
*without specific, written prior permission.
*
*IBM, CARNEGIE MELLON UNIVERSITY, AND THE OTHER COPYRIGHT HOLDERS 
*DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 
*ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT 
*SHALL IBM, CARNEGIE MELLON UNIVERSITY, OR ANY OTHER COPYRIGHT HOLDER 
*BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 
*DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 
*WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 
*ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
*OF THIS SOFTWARE.
* $
*/

/*
 The parse object uses tables generated by bison with the -n flag,

 For details see parse.doc

*/

/* an 'action routine' is the C code in braces, {...}, in grammar rules.
	Action routines do not usually contain return statements, but they
	may when using the parse object.  
	The values defined below may be returned.
	Other valid return values are:
		parse_CLEARIN | parse_ERROROK
		parse_CLEARIN | parse_ERROR
		parse_ERROROK | parse_ERROR
		parse_CLEARIN | parse_ERROROK | parse_ERROR
	the last three of which are unusual and indicate the end
	of one error and the start of the next.  (It would be better
	to just report one error to the user.)
	parse_CLEARIN and parse_ERROROK have meaning primarily in 
	rules whose right hand sides begin with the special token 'error'
*/
#define parse_ACCEPT 	(1<<1)	/* parse succeeds immediately */
#define parse_ABORT	(1<<2)	/* parse fails immediately */
#define parse_ERROR	(1<<3)	/* initiate syntax error.
		The parser will NOT generate a message in this case */
#define parse_CLEARIN	(1<<4)	/* discard the currently pending token */
#define parse_ERROROK	(1<<5)	/* leave error state */

/* the following are values that may be returned by parse_Run.
	in addition, all but parse_OK are possible values for the
	severity argument to self->error().
	After issuing a parse_FATAL error, the action routine must 
	still return parse_ABORT to terminate.
	After issuing one of the other error messages, the action routine
	may return parse_ERROR to initiate syntax error recovery.
*/
#define parse_OK 	0
#define parse_WARNING	(1<<6)	/* processing continues */
#define parse_SERIOUS	(1<<7)	/* compile ceases, but continue error check */
#define parse_SYNTAX	(1<<8)  /* like parse_SERIOUS, but was syntax error */
#define parse_FATAL	(1<<9)  /* cannot even continue error checking */

/* the value parse_FREEMSG is or'ed with the severity value to indicate 
	that the error processor is responsible for freeing the message
	The message will be freed by the default error handler;
	otherwise, the error handler must arrange to do so
*/
#define parse_FREEMSG	(1<<15)

/* the rock argument to reduceActions */
#define parse_ROCK rock
#define parse_ROCKTYPE void *


/* parse_tables store values generated by the parser generator */
static struct parse_tables {
	short num_tokens; 	/* number of terminal symbols */
	short num_nt; 		/* number of nonterminals */
	short max_user_token;	/* max of old-style token numbers */
	short num_rules; 	/* number of rules in the grammar */
	short num_states; 	/* number of states in parser */
	short final_state; 	/* state number of the termination state */
	short defflag;	 	/* value in actx and nextx indicating to use
					defred and defgoto, respectively */
	short table_max; 	/* index of highest entry in table and valid */

	char **names;	/* names[i] is text of i'th token or non-terminal
		tokens occupy the first num_tokens locations
		non-terminals occupy the subsequent num_nt locations
		tokens may be: 
			identifiers - all letters
				an identifier represents either
				a reserved word or a token class
				(by convention, a class name begins 'set'.
				An initial 'tok' in an identifier is ignored
				as in tokNULL for the reserved word NULL)
			character literals - 'x'
			string literals - "xxx"
			$ or $illegal. - internal to parser

		The lexical analyzer must report tokens by their index
		in 'names'.   And must report EOF as token 0.
	*/
	char *translate;	/* newstyle token number for
			each oldstyle token number.  The translation is:
			given below under TranslateTokenNumber */

	/* the grammar */
	short *lhs;	/* lhs[r] is symbol on left of rule r */
	short *rhsx;	/* rhsx[r] is index into rhs for rule r */
	short *rhssz;	/* rhssz[r] counts symbols on the right of rule r */
	short *rhs;  	/* right sides of all rules */

	/* parser control */
	short *table;	/* various stuff, see below */
	short *valid;	/* bounds check for table, see below */
	short *defred;	/* defred[s] is default reduction in state s */
	short *actx;	/* in state s for lookahead token i 
		if actx[s] == defflag, use defred[s] as rule to reduce by 
		if valid[actx[s]+i] == i
			action from table[actx[s] + i]:
			+n: shift: stack state n & token value; enter state n
			-n: reduce by rule n
			0:  reduce by rule defred[s]
		else reduce by rule defred[s]
			** error ** if defred[s] is zero
		*/
	short *defnext; /* defnext[i] is the default successor state 
			after reducing a rule with lhs == ntokens+i */
	short *nextx;	/* after  removing rhs items from stack and
			reducing to a rule with lhs non-terminal
			having value i+ntokens, the subsequent top state is s
		if nextx[i] == defflag then use defnext[i] as new state
		else if (valid[s+nextx[i]]) == s
			then new state is table[s+nextx[i]]
		otherwise, new state is defnext[i]
		*/
};

class parse {

methods:

	Run(/* struct parse *self */) returns int;
		/* causes the parser to run to completion
		using the tables and lexan stream previously defined to it.
		Returns one of the severity values above, indicating
		the highest severity error encountered */
	Error(/* struct parse *self, */ int severity, char *msg);
		/* process an error.  if self->error exists,
		call it instead of printing the error */
	SetErrorHandler(/* struct parse *self, */ void (*handler)())
			returns void *;  
		/* set the error handler.  new value may be NULL
		to restore default action.  Returns previous handler. 
		handler is called with args (parseobject, severity, msg) */
	EnumerateReservedWords(/* struct parse *self, */ void (*handler)(),
			void *rock);
		/* the handler is called for each alphabetic reserved word:
			handler(rock, char *word, int tokennumber) 
		  but it is not called for names beginning with "set"
		  and for names beginning with "tok", 
			only the rest of the name is passed
		  uppercase letters are converted to lower, and vice versa
		*/
	TokenNumberFromName(/* struct parse *self, */ char *name)
			returns int;
		/* returns the token number corresponding to the string;
		  typical strings:  
			"function", "setID", "tokNULL", "'a'", "\":=\""  
		  if the name is not found, returns 0 */

classprocedures:

	Create(struct parse_tables *desc, struct lexan *lex,
		int (*action)(), void *rock, int (*error)())
			returns struct parse *;
		/* create a new parse object suitable 
			for parsing the given lexan stream.
			See parse.doc. */

	SetDebug(boolean value) returns boolean;
		/* sets the debug flag to the given value.
			Returns prior value */

	GetCurrentParse() returns struct parse *;
		/* during parse_Run, this returns the current parse object 
		This should be used to get the self argument for calling 
		parse_Error */

	InitializeClass() returns boolean;
	InitializeObject(struct parse *self) returns boolean;
	FinalizeObject(struct parse *self);

macromethods:

	SetLex(struct lexan *l)		(self->lex = (l))
	GetLex()			(self->lex)
	SetRock(void *r)		(self->rock = (r))
	GetRock()			(self->rock)
	GetErrorHandler()		(self->errorhandler)
	/* SetErrorHandler is a method */
	GetErrorState()			(self->errorstate)
	/* to change errorstate, return 
		parse_ERROR or parse_ERROROK from an action  */
	SetKillVal(void (*kv)()) 	(self->killval = (kv))
	GetKillVal()			(self->killval)
	SetMaxSeverity(int s)		(self->maxSeverity = (s))
	GetMaxSeverity()		(self->maxSeverity)
	SetNErrors(int n)		(self->nerrors = (n))
	GetNErrors()			(self->nerrors)
	GetTokenNames()		(self->tables->names)
	GetNTokens()		(self->tables->num_tokens)
	TranslateTokenNumber(int x)  \
		((x)==(-1) ? 0 :     \
		((unsigned)(x) <= self->tables->max_user_token  \
			? self->tables->translate[x]   \
			: self->tables->num_tokens + self->tables->num_nt))

data:
	struct parse_tables *tables;	/* tables from Bison */
	struct lexan *lex;	/* $$ stream of lexemes.  called as
		currtok = lexan_NextToken(self->lex, &yylval) */
	void *rock;		/* passed to action() */
	int (*action)();	/* for reduction call   
		self->action(rulenum, &yyval, vsp, self->rock) 
		returned value is either parse_OK or one of the others
		defined above 	*/
	void (*errorHandler)();	/* if non-NULL, this function is called
		by parse_Error instead of printing a message.
		prior to the call, parse_Error updates 
		nerrors and maxSeverity.
		The call is 
			self->errorHandler(self, severity, msg);
		where severity is one of the values defined above */
	void (*killval)();	/* if non-NULL, this function is called
		for each value element skipped over on the stack during 
		error processing or at early termination.  The call is
			(self->killval)(self, pointer-from-value-stack) */
	int errorstate;		/* 0 if ok, >0 if processing a syntax error */
	int nerrors;		/* number of errors encountered */
	int maxSeverity;	/* greatest severity error encountered */
};
