
#ifndef _parser_H_
#define _parser_H_

/*	parser.H: headers for parser class  */

/*
	Copyright Carnegie Mellon University 1992, 1994 - All rights reserved
	$Disclaimer:  $
*/

/* a semantic action routine is the C code in braces, {...}, in grammar rules.
	Actions may terminate with the special macros defined here.	
	parser_CLEARIN and parser_ERROROK have meaning primarily in 
	rules whose right hand sides begin with the special token 'error'
	The other macros are useful only on rare occasions.
*/
#define parser_ACCEPT 	{return 1;}	/* parse succeeds immediately */
#define parser_ABORT	{return 2;}	/* parse fails immediately */
#define parser_ERROR	{return 3;}	/* initiate syntax error.
		The parser will NOT generate a message in this case */
#define parser_CLEARIN	{return 4;}	/* discard currently pending token */
#define parser_ERROROK	{return 5;}	/* leave error state */
#define parser_CLINEROK	{return 6;}	/* discard token; leave error state */
#define parser_CLINERR	{return 7;}	/* discard token; enter error state */

/* The following are values that may be returned by parser_Parse.
	They may also be passed as the severity argument to the Error method.
	After issuing a parser_FATAL error, the action routine must 
	still conclude with parser_ABORT to terminate.
	After issuing a parser_SYNTAX error, the action routine should 
	usually conclude with parser_ERROR to initiate syntax error recovery.
*/
#define parser_OK 	0	/* parsed successfully */
#define parser_WARNING	21	/* processing continues */
#define parser_SERIOUS	22	/* compile ceases, but continue error check */
#define parser_SYNTAX	23	/* like parser_SERIOUS, but was syntax error */
#define parser_FATAL	24	/* cannot even continue error checking */

/* the value parser_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 parser_FREEMSG	(1<<15)

typedef int (*parser_lexerfptr)(void *lexrock, void *yylval);
typedef void (*parser_enumresfptr)(void *rock, char *word, int tokennumber);
typedef void (*parser_killfptr)(class parser *self, void *vsp);
typedef void (*parser_errfptr)(int severity, char *msg, class parser *parser);
typedef int (*parser_semfptr)(int i, void *pyyval, void *yyvsp,
	class parser *parser);

/* parser_tables store values generated by the parser generator */
struct parser_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 eltsz;		/* sizeof(YYSTYPE) */
	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]
		*/
	parser_semfptr actions;
};


class parser
{
public:

	virtual int Parse(parser_lexerfptr lexer, void *lexerrock);
		/* 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 */

	virtual void Error(int severity, char *msg);
		/* call this to report an error */
	virtual void ErrorGuts(int severity, char *severityname, char *msg);
		/* override this to provide error processing */

	static class parser *GetCurrentparser();
		/* during parser_Parse, this returns the current parser object 
		This can be used to call the Error method */ 

	virtual void EnumerateReservedWords(parser_enumresfptr 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
		*/
	virtual int TokenNumberFromName(char *name);
		/* returns the token number corresponding to the string;
		  typical strings:  
			"function", "setID", "tokNULL", "'a'", "\":=\""  
		  if the name is not found, returns 0 */

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

	static int ParseNumber(char *buf, long *plen, 
			long *intval, double *dvlval);
		/* parses a number from buf and sets *plen to length found
		sets *intval to integer value and
			if syntax is for a real, sets *dblval to real value
		returns 1 if syntactically an integer, 2 for a double,
			and 0 for a syntax error */

	static int TransEscape(char *buf, int *plen);
		/* buf holds a character sequence (at least three chars)
		  that occurred after a backslash in a string.
		  The translation is returned as an int.
		  The number of characters used is returned in *plen.
			  (plen may be NULL)
		  The translations are a superset of C:
		      escape seq      :  translation
		      --------------- :  ------------
		      \\ \' \" \b \t  :  as in C
		      \n \v \f \r     :  as in C
		      \ddd	      :  octal digits, as in C
		      \?	      :  DEL  or  \177
		      \e	      :  ESC  or  ctl-[ or \033
		      \^@	      :  NUL  or  \000
		      \^a ... \^z     :  ctl-a ... ctl-z  or  \001 ... \032
		      \^[  \^\	\^]   :  \033  \034  \035
		      \^^  \^_	      :  \036  \037
		*/

	parser();
	
	virtual ~parser();

	inline void SetRock(void *r)		{ (this->rock = (r)); }
	inline void  *GetRock()			{ return (this->rock); }
	inline int   GetErrorState()		{ return (this->errorstate); }
	/* to change errorstate, an action concludes with
		parser_ERROR or parser_ERROROK  */
	inline void SetKillVal(parser_killfptr kv) { (this->killval = (kv)); }
	inline parser_killfptr GetKillVal()	{ return (this->killval); }
	inline void SetMaxSeverity(int s)	{ (this->maxSeverity = (s)); }
	inline int GetMaxSeverity()		{ return (this->maxSeverity); }
	inline void SetNErrors(int n)		{ (this->nerrors = (n)); }
	inline int GetNErrors()			{ return (this->nerrors); }
	inline char ** GetTokenNames()		{ return(this->tables->names);}
	inline short GetNTokens()		{ return (this->tables->num_tokens); }
	inline void SetTables(struct parser_tables *t)
						{ (this)->tables = (t); }
	inline char TranslateTokenNumber(int x)  
		{ return ((x)==(-1) ? 0 :     
		((unsigned)(x) <= this->tables->max_user_token  
			? this->tables->translate[x]   
			: this->tables->num_tokens + this->tables->num_nt)); }

/* data members */

	struct parser_tables *tables;	/* tables from Bison */
	class lexan *lex;	/* $$ stream of lexemes.  called as
		currtok = lexan_NextToken(self->lex, &yylval) */
	void *rock;		/* passed to action() */
	parser_killfptr 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 */
};

#endif /* _parser_H_ */
