include	<lexnum.h>
include	<ctype.h>
include <fset.h>
include	"vex.h"

#* HISTORY *
#* B.Simon	??		original
#  Phil Hodge	12-Jul-2005	Add 'int vex_gettok()' and declare 'debug'
#				to be bool rather than int, in vex_compile.

define	YYMAXDEPTH	64
define	YYOPLEN		1
define	yyparse		vex_parse

# Tokens generated by xyacc have been moved to vex.h

define	yyclearin	yychar = -1
define	yyerrok		yyerrflag = 0
define	YYMOVE		call amovi (Memi[$1], Memi[$2], YYOPLEN)
define	YYERRCODE	256

# line 148 "vexcompile.y"


# VEX_COMPILE -- Compile an expression, producing pseudocode
#
# This procedure takes a string containing a fortran expression and produces
# pseudocode that can be evaluated by vex_eval(). The pseudocode is stored in
# structure adressed by the pointer returned as the function value. This 
# structure is freed by calling vex_free(). If the string begins with an @ 
# symbol, the rest of the string is treated as a the name of a file which
# contains the expression. The expression can contain all the fortran 
# operators, including logical and relational operators and supports all the
# fortran intrinsic functions which can take real arguments. It also supports
# conditional expressions of the form: if <expr> then <expr> else <expr>
# Variables must follow the fortran rules, and may be up to 31 characters long.
# All variables and constants are treated as real numbers. A variable may
# contain non-alphanumeric characters if it is preceded by a dollar sign, in
# which case all characters until the next blank are part of the variable name.
#
# B.Simon	21-May-90	Original
# B.Simon	19-Apr-91	Revised to handle multiple types
# B.Simon	31-Mar-94	Better syntax error message
# B.Simon	15-Oct-98	Embed strings in pseudocode

pointer procedure vex_compile (expr)

char	expr[ARB]	# i: Expression to be parsed
#--
include	"vex.com"

int	ic, fd, len
bool	debug
pointer	sp, pcode

data	debug	/ false /

int	open(), stropen(), strlen(), fstati(), yyparse()

int	vex_gettok()
extern	vex_gettok

begin
	# Open the expression as a file

	for (ic = 1; IS_WHITE(expr[ic]); ic = ic + 1)
	    ;

	if (expr[ic] == '@') {
	    fd = open (expr[ic+1], READ_ONLY, TEXT_FILE)
	    len = fstati (fd, F_FILESIZE) + 1

	} else {
	    len = strlen (expr[ic]) + 1
	    fd = stropen (expr[ic], len, READ_ONLY)
	}

	# Create pseudocode structure

	call malloc (pcode, SZ_VEXSTRUCT, TY_STRUCT)

	call malloc (VEX_CODE(pcode), 2 * len, TY_INT)
	call stk_init (VEX_STACK(pcode))

	# Initialize parsing common block

	call smark (sp)
	call salloc (line, SZ_LINE, TY_CHAR)

	ch = line
	Memc[line] = EOS

	ncode = 0
	maxcode = 2 * len
	code = VEX_CODE(pcode)
	stack = VEX_STACK(pcode)

	# Parse expression to produce reverse polish code

	if (yyparse (fd, debug, vex_gettok) == ERR) {
	    call eprintf ("%s\n%*t^\n")
	    call pargstr (Memc[line])
	    call pargi (ch-line)

	    call error (1, "Syntax error in expression")
	}

	# Clean up and return pseudocode structure

	call stk_clear (VEX_STACK(pcode))

	call close (fd)
	call sfree (sp)
	return (pcode)
end

# VEX_GETTOK -- Get the next token from the input

int procedure vex_gettok (fd, value)

int	fd		# i: File containing expression to be lexed
pointer	value		# o: Address on parse stack to store token
#--
include	"vex.com"

double	constant
int	ic, jc, nc, type, index
int	idftype[4], keytype[3], btype[9]
pointer	sp, errmsg, token

string  fn1tok	FN1STR
string	fn2tok	FN2STR

string	idftok	"indefi indefr indefd indef"
data	idftype	/ Y_INT, Y_REAL, Y_DOUBLE, Y_REAL /

string	keytok	"if then else"
data	keytype	/ Y_IF, Y_THEN, Y_ELSE /

string	btoken  ".or. .and. .eq. .ne. .lt. .gt. .le. .ge. .not."
data	btype   / Y_OR, Y_AND, Y_EQ, Y_NE, Y_LT, Y_GT, Y_LE, Y_GE, Y_NOT /

string	badsymb "Operator not recognized (%s)"

int	getline(), lexnum(), ctod(), stridxs(), word_match()

begin
	# Allocate dynamic memory for strings

	call smark (sp)
	call salloc (errmsg, SZ_LINE, TY_CHAR)
	call malloc (token, MAX_TOKEN, TY_CHAR)

	# Skip over leading white space and comments

	while (Memc[ch] <= BLANK || Memc[ch] == CMTCHAR) {

	    # If all characters have been read from the current line 
	    # or a comment character was found, get the next line

	    if (Memc[ch] == EOS || Memc[ch] == CMTCHAR) {
		ch = line
		if (getline (fd, Memc[line]) == EOF) {
		    Memc[ch] = EOS
		    break
		}
	    } else {
		ch = ch + 1
	    }
	}

	# The token type is determined from the first character in the token

	Memc[token] = EOS

	# End of expression token

	if (Memc[ch] == EOS) {
	    type = Y_DONE

	# Numeric constant is too difficult to parse,
	# Pass the job to lexnum and ctod

	} else if (IS_DIGIT(Memc[ch])) {

	    ic = 1
	    index = lexnum (Memc[ch], ic, nc)
	    if (index != LEX_REAL) {
		type = Y_INT
	    } else if (nc > 8) {
		type = Y_DOUBLE
	    } else {
		jc = stridxs ("dD", Memc[ch])
		if (jc == 0 || jc > nc) {
		    type = Y_REAL
		} else {
		    type = Y_DOUBLE
		}
	    }

	    ic = 1
	    nc = ctod (Memc[ch], ic, constant)
	    nc = min (nc, MAX_TOKEN)

	    call strcpy (Memc[ch], Memc[token], nc)
	    ch = ch + ic - 1

	# Token is alphanumeric. Determine what type of token

	} else if (IS_ALPHA (Memc[ch])) {

	    # Gather characters in token

	    for (ic = 1; ic <= MAX_TOKEN; ic = ic + 1) {
		if (Memc[ch] != '_' && ! IS_ALNUM(Memc[ch]))
		    break

		if (IS_UPPER(Memc[ch]))	
		    Memc[token+ic-1] = TO_LOWER(Memc[ch])
		else
		    Memc[token+ic-1] = Memc[ch]
		ch = ch + 1
	    }
	    Memc[token+ic-1] = EOS

	    # Check to see if token is string "INDEF"

	    index = word_match (Memc[token], idftok)

	    if (index > 0) {
		type = idftype[index]
		call strupr (Memc[token])

	    } else {

		# Check to see if token is function or keyword name
		# If not, add it as a new variable

		index = word_match (Memc[token], fn1tok)
		if (index > 0) {
		    type = Y_FN1

		} else {
		    index = word_match (Memc[token], fn2tok)
		    if (index > 0) {
			type = Y_FN2

		    } else {
			index = word_match (Memc[token], keytok)
			if (index > 0) {
			    type = keytype[index]
			    Memc[token] = EOS
			} else {
			    type = Y_VAR
			}
		    }
		}
	    }

	# Tokens beginning with a dot are numbers or boolean operators

	} else if (Memc[ch] == DOT) {

	    if (IS_DIGIT (Memc[ch+1])) {
		ic = 1
		index = lexnum (Memc[ch], ic, nc)

		if (index != LEX_REAL) {
		    type = Y_INT
		} else if (nc < 9) {
		    type = Y_REAL
		} else {
		    type = Y_DOUBLE
		}

		ic = 1
		nc = ctod (Memc[ch], ic, constant)
		nc = min (nc, MAX_TOKEN)

		call strcpy (Memc[ch], Memc[token], nc)
		ch = ch + ic - 1

	    } else {

		# Gather characters in token

		ch = ch + 1
		Memc[token] = DOT
		for (ic = 2; ic < MAX_TOKEN && Memc[ch] != DOT; ic = ic + 1) {
		    if (Memc[ch] == EOS)
			break
		    if (IS_UPPER(Memc[ch]))	
			Memc[token+ic-1] = TO_LOWER(Memc[ch])
		    else
			Memc[token+ic-1] = Memc[ch]
		    ch = ch + 1
		}

		Memc[token+ic-1] = Memc[ch]
		Memc[token+ic] = EOS
		ch = ch + 1

		index = word_match (Memc[token], btoken)
		if (type > 0) {
		    type = btype[index]
		} else {
		    call sprintf (Memc[errmsg], SZ_LINE, badsymb)
		    call pargstr (Memc[token])
		    call error (1, Memc[errmsg])
		}
	    }

	# Characters preceded by a dollar sign are identifiers

	} else if (Memc[ch] == DOLLAR) {

	    ch = ch + 1
	    for (ic = 1; ic <= MAX_TOKEN && Memc[ch] > BLANK; ic = ic + 1) {
		if (IS_UPPER(Memc[ch]))	
		    Memc[token+ic-1] = TO_LOWER(Memc[ch])
		else
		    Memc[token+ic-1] = Memc[ch]
		ch = ch + 1
	    }
	    Memc[token+ic-1] = EOS

	    type = Y_VAR

	# Anything else is a symbol
	
	} else {
	    switch (Memc[ch]) {
	    case '*':
		if (Memc[ch+1] != '*') {
		    type = Y_MUL
		} else {
		    type = Y_POW
		    ch = ch + 1
		}
	    case '/':
		type = Y_DIV
	    case '+':
		type = Y_ADD
	    case '-':
		type = Y_SUB
	    case '(':
		type = Y_LPAR
	    case ')':
		type = Y_RPAR
	    case ',':
		type = Y_COMMA
	    case '<':
		if (Memc[ch+1] != '=') {
		   type = Y_LT
		} else {
		   type = Y_LE
		   ch = ch + 1
		}
	    case '>':
		if (Memc[ch+1] != '=') {
		   type = Y_GT
		} else {
		   type = Y_GE
		   ch = ch + 1
		}
	    case '|':
		if (Memc[ch+1] != '|') {
		   type = Y_WRONG
		} else {
		   type = Y_OR
		   ch = ch + 1
		}
	    case '&':
		if (Memc[ch+1] != '&') {
		   type = Y_WRONG
		} else {
		   type = Y_AND
		   ch = ch + 1
		}
	    case '=':
		if (Memc[ch+1] != '=') {
		   type = Y_WRONG
		} else {
		   type = Y_EQ
		   ch = ch + 1
		}
	    case '!':
		if (Memc[ch+1] != '=') {
		   type = Y_NOT
		} else {
		   type = Y_NE
		   ch = ch + 1
		}
	    default:
		Memc[ch+1] = EOS
		call sprintf (Memc[errmsg], SZ_LINE, badsymb)
		    call pargstr (Memc[ch])
		call error (1, Memc[errmsg])
	    }

	    ch = ch + 1
	}

	# 
	if (Memc[token] == EOS) {
	    call mfree (token, TY_CHAR)
	    token = NULL
	}

	Memi[value] = token
	return (type)
end

# VEX_ADDCODE -- Add an instruction to the code array

procedure vex_addcode (type)

int	type		# i: Instruction type
#--
include	"vex.com"

begin

	if (ncode == maxcode)
	    call error (1, "Expression too complex")
	else {
	    Memi[code] = type
	    code = code + 1
	    ncode = ncode + 1
	}

end

# VEX_ADDSTR -- Embed a string constant in the pseudo-code

procedure vex_addstr (token)

pointer	token		# u: Pointer to token string
#--
include "vex.com"

int	ic

begin
	if (token == NULL)
	    call error (1, "Expression token missing")

	if (Memc[token] == EOS)
	    call error (1, "Expression token blank")

	ic = 0
	repeat {
	    ic = ic + 1

	    if (ncode == maxcode)
		call error (1, "Expression too complex")
	    else {
		Memi[code] = Memc[token+ic-1]
		code = code + 1
		ncode = ncode + 1
	    }

	} until (Memc[token+ic-1] == EOS)

	call mfree (token, TY_CHAR)
end

# VEX_GETSTR -- Retrieve a token string from the pseudocode array

procedure vex_getstr (op, token, maxch)

pointer	op		# u: Location of token string in pseudocode
char	token[ARB]	# o: Token string
int	maxch		# i: Maximum length of token
#--
int	ic

begin
	# The token begins one position after op and is 
	# termminated by an EOS

	ic = 0
	repeat {
	    ic = ic + 1
	    op = op + 1
	    if (ic <= maxch)
		token[ic] = Memi[op]

	} until (Memi[op] == EOS)

end
define	YYNPROD		27
define	YYLAST		264
# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.

# Parser for yacc output, translated to the IRAF SPP language.  The contents
# of this file form the bulk of the source of the parser produced by Yacc.
# Yacc recognizes several macros in the yaccpar input source and replaces
# them as follows:
#	A	user suppled "global" definitions and declarations
# 	B	parser tables
# 	C	user supplied actions (reductions)
# The remainder of the yaccpar code is not changed.

define	yystack_	10		# statement labels for gotos
define	yynewstate_	20
define	yydefault_	30
define	yyerrlab_	40
define	yyabort_	50

define	YYFLAG		(-1000)		# defs used in user actions
define	YYERROR		goto yyerrlab_
define	YYACCEPT	return (OK)
define	YYABORT		return (ERR)


# YYPARSE -- Parse the input stream, returning OK if the source is
# syntactically acceptable (i.e., if compilation is successful),
# otherwise ERR.  The parameters YYMAXDEPTH and YYOPLEN must be
# supplied by the caller in the %{ ... %} section of the Yacc source.
# The token value stack is a dynamically allocated array of operand
# structures, with the length and makeup of the operand structure being
# application dependent.

int procedure yyparse (fd, yydebug, yylex)

int	fd			# stream to be parsed
bool	yydebug			# print debugging information?
int	yylex()			# user-supplied lexical input function
extern	yylex()

short	yys[YYMAXDEPTH]		# parser stack -- stacks tokens
pointer	yyv			# pointer to token value stack
pointer	yyval			# value returned by action
pointer	yylval			# value of token
int	yyps			# token stack pointer
pointer	yypv			# value stack pointer
int	yychar			# current input token number
int	yyerrflag		# error recovery flag
int	yynerrs			# number of errors

short	yyj, yym		# internal variables
pointer	yysp, yypvt
short	yystate, yyn
int	yyxi, i
errchk	salloc, yylex



short	yyexca[70]
data	(yyexca(i),i=  1,  8)	/  -1,   1,   0,  -1,  -2,   0,  -1,  41/
data	(yyexca(i),i=  9, 16)	/ 276,   0, 277,   0, 278,   0, 279,   0/
data	(yyexca(i),i= 17, 24)	/  -2,  18,  -1,  42, 276,   0, 277,   0/
data	(yyexca(i),i= 25, 32)	/ 278,   0, 279,   0,  -2,  19,  -1,  43/
data	(yyexca(i),i= 33, 40)	/ 276,   0, 277,   0, 278,   0, 279,   0/
data	(yyexca(i),i= 41, 48)	/  -2,  20,  -1,  44, 276,   0, 277,   0/
data	(yyexca(i),i= 49, 56)	/ 278,   0, 279,   0,  -2,  21,  -1,  45/
data	(yyexca(i),i= 57, 64)	/ 274,   0, 275,   0,  -2,  22,  -1,  46/
data	(yyexca(i),i= 65, 70)	/ 274,   0, 275,   0,  -2,  23/
short	yyact[264]
data	(yyact(i),i=  1,  8)	/  58,  22,  23,  24,  25,  20,  21,  18/
data	(yyact(i),i=  9, 16)	/  19,  17,  17,  31,  29,  28,  15,  26/
data	(yyact(i),i= 17, 24)	/  27,  22,  23,  24,  25,  20,  21,  18/
data	(yyact(i),i= 25, 32)	/  19,  55,  17,  29,  28,  30,  26,  27/
data	(yyact(i),i= 33, 40)	/  22,  23,  24,  25,  20,  21,  18,  19/
data	(yyact(i),i= 41, 48)	/  54,  17,  20,  21,  18,  19,   1,  17/
data	(yyact(i),i= 49, 56)	/   0,   0,   0,  29,  28,   0,  26,  27/
data	(yyact(i),i= 57, 64)	/  22,  23,  24,  25,  20,  21,  18,  19/
data	(yyact(i),i= 65, 72)	/  53,  17,  18,  19,   0,  17,   0,   0/
data	(yyact(i),i= 73, 80)	/   0,   0,   2,   0,  29,  28,   0,  26/
data	(yyact(i),i= 81, 88)	/  27,  22,  23,  24,  25,  20,  21,  18/
data	(yyact(i),i= 89, 96)	/  19,  51,  17,   0,   0,   0,   0,   0/
data	(yyact(i),i= 97,104)	/   0,   0,   0,   0,   0,  29,  28,   0/
data	(yyact(i),i=105,112)	/  26,  27,  22,  23,  24,  25,  20,  21/
data	(yyact(i),i=113,120)	/  18,  19,  35,  17,   0,  29,  28,   0/
data	(yyact(i),i=121,128)	/  26,  27,  22,  23,  24,  25,  20,  21/
data	(yyact(i),i=129,136)	/  18,  19,  57,  17,  29,  28,   0,  26/
data	(yyact(i),i=137,144)	/  27,  22,  23,  24,  25,  20,  21,  18/
data	(yyact(i),i=145,152)	/  19,  28,  17,  26,  27,  22,  23,  24/
data	(yyact(i),i=153,160)	/  25,  20,  21,  18,  19,   0,  17,  26/
data	(yyact(i),i=161,168)	/  27,  22,  23,  24,  25,  20,  21,  18/
data	(yyact(i),i=169,176)	/  19,   3,  17,  14,   0,   0,   6,   7/
data	(yyact(i),i=177,184)	/   8,   9,  10,  11,   4,   0,   0,   0/
data	(yyact(i),i=185,192)	/  14,   0,  13,   6,   7,   8,   9,  10/
data	(yyact(i),i=193,200)	/  11,   4,  12,   0,   0,  14,   0,  13/
data	(yyact(i),i=201,208)	/   6,   7,   8,   9,  10,  11,   0,  12/
data	(yyact(i),i=209,216)	/   5,   0,   0,   0,  13,  16,   0,   0/
data	(yyact(i),i=217,224)	/   0,   0,   0,   0,  12,  32,  33,  34/
data	(yyact(i),i=225,232)	/   0,   0,  36,  37,  38,  39,  40,  41/
data	(yyact(i),i=233,240)	/  42,  43,  44,  45,  46,  47,  48,  49/
data	(yyact(i),i=241,248)	/  50,   0,   0,   0,  52,   0,   0,   0/
data	(yyact(i),i=249,256)	/   0,   0,   0,   0,   0,   0,   0,   0/
data	(yyact(i),i=257,264)	/   0,   0,   0,   0,   0,   0,   0,  56/
short	yypact[59]
data	(yypact(i),i=  1,  8)	/ -87,-1000,-256,-1000, -61,-139,-1000,-1000/
data	(yypact(i),i=  9, 16)	/-1000,-1000,-229,-247, -61, -61, -61,-1000/
data	(yypact(i),i= 17, 24)	/-154, -61, -61, -61, -61, -61, -61, -61/
data	(yypact(i),i= 25, 32)	/ -61, -61, -61, -61, -61, -61, -61, -61/
data	(yypact(i),i= 33, 40)	/-276,-115,-170, -61,-276,-276,-276,-216/
data	(yypact(i),i= 41, 48)	/-216,-238,-238,-238,-238,-275,-275,-115/
data	(yypact(i),i= 49, 56)	/-127,-195,-220,-1000,-244,-1000, -61, -74/
data	(yypact(i),i= 57, 59)	/-259,-1000,-1000/
short	yypgo[4]
data	(yypgo(i),i=  1,  4)	/   0,  46,  74, 208/
short	yyr1[27]
data	(yyr1(i),i=  1,  8)	/   0,   1,   1,   2,   2,   3,   3,   3/
data	(yyr1(i),i=  9, 16)	/   3,   3,   3,   3,   3,   3,   3,   3/
data	(yyr1(i),i= 17, 24)	/   3,   3,   3,   3,   3,   3,   3,   3/
data	(yyr1(i),i= 25, 27)	/   3,   3,   3/
short	yyr2[27]
data	(yyr2(i),i=  1,  8)	/   0,   2,   1,   6,   1,   1,   1,   1/
data	(yyr2(i),i=  9, 16)	/   1,   4,   6,   2,   2,   3,   3,   3/
data	(yyr2(i),i= 17, 24)	/   3,   3,   3,   3,   3,   3,   3,   3/
data	(yyr2(i),i= 25, 27)	/   3,   3,   3/
short	yychk[59]
data	(yychk(i),i=  1,  8)	/-1000,  -1,  -2, 256, 267,  -3, 261, 262/
data	(yychk(i),i=  9, 16)	/ 263, 264, 265, 266, 281, 273, 258, 270/
data	(yychk(i),i= 17, 24)	/  -3, 285, 282, 283, 280, 281, 276, 277/
data	(yychk(i),i= 25, 32)	/ 278, 279, 274, 275, 272, 271, 258, 258/
data	(yychk(i),i= 33, 40)	/  -3,  -3,  -3, 268,  -3,  -3,  -3,  -3/
data	(yychk(i),i= 41, 48)	/  -3,  -3,  -3,  -3,  -3,  -3,  -3,  -3/
data	(yychk(i),i= 49, 56)	/  -3,  -3,  -3, 259,  -3, 259, 260, 269/
data	(yychk(i),i= 57, 59)	/  -3,  -2, 259/
short	yydef[59]
data	(yydef(i),i=  1,  8)	/   0,  -2,   0,   2,   0,   4,   5,   6/
data	(yydef(i),i=  9, 16)	/   7,   8,   0,   0,   0,   0,   0,   1/
data	(yydef(i),i= 17, 24)	/   0,   0,   0,   0,   0,   0,   0,   0/
data	(yydef(i),i= 25, 32)	/   0,   0,   0,   0,   0,   0,   0,   0/
data	(yydef(i),i= 33, 40)	/  11,  12,   0,   0,  13,  14,  15,  16/
data	(yydef(i),i= 41, 48)	/  17,  -2,  -2,  -2,  -2,  -2,  -2,  24/
data	(yydef(i),i= 49, 56)	/  25,   0,   0,  26,   0,   9,   0,   0/
data	(yydef(i),i= 57, 59)	/   0,   3,  10/

begin
	call smark (yysp)
	call salloc (yyv, (YYMAXDEPTH+2) * YYOPLEN, TY_STRUCT)

	# Initialization.  The first element of the dynamically allocated
	# token value stack (yyv) is used for yyval, the second for yylval,
	# and the actual stack starts with the third element.

	yystate = 0
	yychar = -1
	yynerrs = 0
	yyerrflag = 0
	yyps = 0
	yyval = yyv
	yylval = yyv + YYOPLEN
	yypv = yylval

yystack_
	# SHIFT -- Put a state and value onto the stack.  The token and
	# value stacks are logically the same stack, implemented as two
	# separate arrays.

	if (yydebug) {
	    call printf ("state %d, char 0%o\n")
		call pargs (yystate)
		call pargi (yychar)
	}
	yyps = yyps + 1
	yypv = yypv + YYOPLEN
	if (yyps > YYMAXDEPTH) {
	    call sfree (yysp)
	    call eprintf ("yacc stack overflow\n")
	    return (ERR)
	}
	yys[yyps] = yystate
	YYMOVE (yyval, yypv)

yynewstate_
	# Process the new state.
	yyn = yypact[yystate+1]

	if (yyn <= YYFLAG)
	    goto yydefault_			# simple state

	# The variable "yychar" is the lookahead token.
	if (yychar < 0) {
	    yychar = yylex (fd, yylval)
	    if (yychar < 0)
		yychar = 0
	}
	yyn = yyn + yychar
	if (yyn < 0 || yyn >= YYLAST)
	    goto yydefault_

	yyn = yyact[yyn+1]
	if (yychk[yyn+1] == yychar) {		# valid shift
	    yychar = -1
	    YYMOVE (yylval, yyval)
	    yystate = yyn
	    if (yyerrflag > 0)
		yyerrflag = yyerrflag - 1
	    goto yystack_
	}

yydefault_
	# Default state action.

	yyn = yydef[yystate+1]
	if (yyn == -2) {
	    if (yychar < 0) {
		yychar = yylex (fd, yylval)
		if (yychar < 0)
		    yychar = 0
	    }

	    # Look through exception table.
	    yyxi = 1
	    while ((yyexca[yyxi] != (-1)) || (yyexca[yyxi+1] != yystate))
		yyxi = yyxi + 2
	    for (yyxi=yyxi+2;  yyexca[yyxi] >= 0;  yyxi=yyxi+2) {
		if (yyexca[yyxi] == yychar)
		    break
	    }

	    yyn = yyexca[yyxi+1]
	    if (yyn < 0) {
		call sfree (yysp)
		return (OK)			# ACCEPT -- all done
	    }
	}


	# SYNTAX ERROR -- resume parsing if possible.

	if (yyn == 0) {
	    switch (yyerrflag) {
	    case 0, 1, 2:
		if (yyerrflag == 0) {		# brand new error
		    call eprintf ("syntax error\n")
yyerrlab_
		    yynerrs = yynerrs + 1
		    # fall through...
		}

	    # case 1:
	    # case 2: incompletely recovered error ... try again
		yyerrflag = 3

		# Find a state where "error" is a legal shift action.
		while (yyps >= 1) {
		    yyn = yypact[yys[yyps]+1] + YYERRCODE
		    if ((yyn >= 0) && (yyn < YYLAST) &&
			(yychk[yyact[yyn+1]+1] == YYERRCODE)) {
			    # Simulate a shift of "error".
			    yystate = yyact[yyn+1]
			    goto yystack_
		    }
		    yyn = yypact[yys[yyps]+1]

		    # The current yyps has no shift on "error", pop stack.
		    if (yydebug) {
			call printf ("error recovery pops state %d, ")
			    call pargs (yys[yyps])
			call printf ("uncovers %d\n")
			    call pargs (yys[yyps-1])
		    }
		    yyps = yyps - 1
		    yypv = yypv - YYOPLEN
		}

		# ABORT -- There is no state on the stack with an error shift.
yyabort_
		call sfree (yysp)
		return (ERR)


	    case 3: # No shift yet; clobber input char.

		if (yydebug) {
		    call printf ("error recovery discards char %d\n")
			call pargi (yychar)
		}

		if (yychar == 0)
		    goto yyabort_		# don't discard EOF, quit
		yychar = -1
		goto yynewstate_		# try again in the same state
	    }
	}


	# REDUCE -- Reduction by production yyn.

	if (yydebug) {
	    call printf ("reduce %d\n")
		call pargs (yyn)
	}
	yyps  = yyps - yyr2[yyn+1]
	yypvt = yypv
	yypv  = yypv - yyr2[yyn+1] * YYOPLEN
	YYMOVE (yypv + YYOPLEN, yyval)
	yym   = yyn

	# Consult goto table to find next state.
	yyn = yyr1[yyn+1]
	yyj = yypgo[yyn+1] + yys[yyps] + 1
	if (yyj >= YYLAST)
	    yystate = yyact[yypgo[yyn+1]+1]
	else {
	    yystate = yyact[yyj+1]
	    if (yychk[yystate+1] != -yyn)
		yystate = yyact[yypgo[yyn+1]+1]
	}

	# Perform action associated with the grammar rule, if any.
	switch (yym) {
	    
case 1:
# line 34 "vexcompile.y"
{
			# Normal exit. Code a stop instruction
			call vex_addcode (Y_DONE)
			return (OK)
		}
case 2:
# line 39 "vexcompile.y"
{
			return (ERR)
		}
case 3:
# line 44 "vexcompile.y"
{
			# Code an if instruction
			call vex_addcode (Y_IF)
		}
case 4:
# line 48 "vexcompile.y"
{
			# Null action
		}
case 5:
# line 53 "vexcompile.y"
{
			# Code a push variable instruction
			call vex_addcode (Y_VAR)
			call vex_addstr (Memi[yypvt])
		}
case 6:
# line 58 "vexcompile.y"
{
			# Code a push variable instruction
			call vex_addcode (Y_INT)
			call vex_addstr (Memi[yypvt])
		}
case 7:
# line 63 "vexcompile.y"
{
			# Code a push variable instruction
			call vex_addcode (Y_REAL)
			call vex_addstr (Memi[yypvt])
		}
case 8:
# line 68 "vexcompile.y"
{
			# Code a push variable instruction
			call vex_addcode (Y_DOUBLE)
			call vex_addstr (Memi[yypvt])
		}
case 9:
# line 73 "vexcompile.y"
{
			# Code a single argument function call
			call vex_addcode (Y_FN1)
			call vex_addstr (Memi[yypvt-3*YYOPLEN])
		}
case 10:
# line 78 "vexcompile.y"
{
			# Code a double argument function call
			call vex_addcode (Y_FN2)
			call vex_addstr (Memi[yypvt-5*YYOPLEN])
		}
case 11:
# line 83 "vexcompile.y"
{
			# Code a negation instruction
			call vex_addcode (Y_NEG)
		}
case 12:
# line 87 "vexcompile.y"
{
			# Code a logical not
			call vex_addcode (Y_NOT)
		}
case 13:
# line 91 "vexcompile.y"
{
			# Code an exponentiation instruction
			call vex_addcode (Y_POW)
		}
case 14:
# line 95 "vexcompile.y"
{
			# Code a multiply instruction
			call vex_addcode (Y_MUL)
		}
case 15:
# line 99 "vexcompile.y"
{
			# Code a divide instruction
			call vex_addcode (Y_DIV)
		}
case 16:
# line 103 "vexcompile.y"
{
			# Code an addition instruction
			call vex_addcode (Y_ADD)
		}
case 17:
# line 107 "vexcompile.y"
{
			# Code a subtraction instruction
			call vex_addcode (Y_SUB)
		}
case 18:
# line 111 "vexcompile.y"
{
			# Code a less than instruction
			call vex_addcode (Y_LT)
		}
case 19:
# line 115 "vexcompile.y"
{
			# Code a greater than instruction
			call vex_addcode (Y_GT)
		}
case 20:
# line 119 "vexcompile.y"
{
			# Code a less than or equal instruction
			call vex_addcode (Y_LE)
		}
case 21:
# line 123 "vexcompile.y"
{
			# Code a greater than instruction
			call vex_addcode (Y_GE)
		}
case 22:
# line 127 "vexcompile.y"
{
			# Code a logical equality instruction
			call vex_addcode (Y_EQ)
		}
case 23:
# line 131 "vexcompile.y"
{
			# Code a logical inequality instruction
			call vex_addcode (Y_NE)
		}
case 24:
# line 135 "vexcompile.y"
{
			# Code a logical and instruction
			call vex_addcode (Y_AND)
		}
case 25:
# line 139 "vexcompile.y"
{
			# Code a logical or instruction
			call vex_addcode (Y_OR)
		}
case 26:
# line 143 "vexcompile.y"
{
			# Null action
		}	}

	goto yystack_				# stack new state and value
end
