/*
 * Copyright 2013 Yuichiro Moriguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.morilib.bc;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

/**
 * 
 *
 *
 * @author MORIGUCHI, Yuichiro 2013/07/14
 */
public class BcExprParser {

	//
	private BcLexer lex;
	private List<Object> stack;
	private int stat = 10000;
	private BcNonterminal gt = null;
	private boolean disp = false;

	private static interface V0 {

		public String storeToString();

		public String storeopToString(char op);

	}

	private static class VS implements V0 {

		char ch;

		VS(char c) {
			ch = c;
		}

		public String storeToString() {
			return "ds" + ch;
		}

		public String storeopToString(char op) {
			return String.format("l%cr%cds%c", ch, op, ch);
		}

		public String toString() {
			return "l" + ch;
		}

	}

	private static class VA implements V0 {

		char ch;

		VA(char c) {
			ch = c;
		}

		public String storeToString() {
			return ("s" + BcRootNamespace.TMP_ARRAY1 +
					"r:l" + BcRootNamespace.TMP_ARRAY1);
		}

		public String storeopToString(char op) {
			return String.format("rs%c;%cr%cdl%c:%c",
					BcRootNamespace.TMP_ARRAY2, ch, op,
					BcRootNamespace.TMP_ARRAY2, ch);
		}

		public String toString() {
			return ";" + ch;
		}

	}

	/**
	 * 
	 * @param s
	 * @throws IOException
	 */
	public BcExprParser(String s) throws IOException {
		lex = new BcLexer(s);
		stack = new ArrayList<Object>();
		stack.add(10000);
	}

	/**
	 * 
	 * @param lex
	 */
	public BcExprParser(BcLexer lex) {
		this.lex = lex;
		stack = new ArrayList<Object>();
		stack.add(10000);
	}

	//
	private boolean eqchar(char c) throws IOException {
		if(lex.eqchar(c)) {
			stack.add(Character.valueOf(c));
			return true;
		} else {
			return false;
		}
	}

	//
	private boolean equalTo(Object o) throws IOException {
		if(lex.equalTo(o)) {
			stack.add(o);
			return true;
		} else {
			return false;
		}
	}

	//
	private boolean isSymbol() throws IOException {
		Object o;

		if((o = lex.getSymbol()) != null) {
			stack.add(o);
			return true;
		} else {
			return false;
		}
	}

	//
	private boolean isSymbol(String s) throws IOException {
		if(lex.isSymbol(s)) {
			stack.add(new BcSymbol(s));
			return true;
		} else {
			return false;
		}
	}

	//
	private boolean isEof() {
		return lex.isEof();
	}

	//
	private boolean isNumber() throws IOException {
		Object o;

		if((o = lex.getNumber()) != null) {
			stack.add(o);
			return true;
		} else {
			return false;
		}
	}

	//
	private boolean isRelop() throws IOException {
		Object o;

		if((o = lex.getRelop()) != null) {
			stack.add(o);
			return true;
		} else {
			return false;
		}
	}

	//
	private boolean isAssignop() throws IOException {
		Object o;

		if((o = lex.getAssignop()) != null) {
			stack.add(o);
			return true;
		} else {
			return false;
		}
	}

	//
	private Object pop() {
		stack.remove(stack.size() - 1);
		return stack.remove(stack.size() - 1);
	}

	//
	private void shift(int n) {
		stat = n;
		disp = gt != null && gt.isDisplay();
		gt   = null;
		stack.add(n);
	}

	//
	private void setGoto(BcNonterminal nt) {
		stat = ((Integer)stack.get(stack.size() - 1)).intValue();
		gt   = nt;
		stack.add(gt);
	}

	/*
	 * S -> E
	 * 
	 * E -> ( E )
	 *    | - E
	 *    | E ^ E
	 *    | E / E
	 *    | E * E
	 *    | E % E
	 *    | E + E
	 *    | E - E
	 *    | E relation-operator E
	 *    | ! E
	 *    | E && E
	 *    | E || E
	 *    | symbol ( L )
	 *    | V assign-operator E
	 *    | ++ V
	 *    | -- V
	 *    | V ++
	 *    | V --
	 *    | V
	 *    | number
	 * 
	 * V -> symbol
	 *    | symbol [ E ]
	 * 
	 * L -> L , symbol
	 *    | symbol
	 */
	public boolean parseExpression(BcNamespace ns,
			PrintWriter b) throws IOException {
		List<Object> sem = new ArrayList<Object>();
		BcAssignOp a1;
		BcSymbol y1;
		BcNumber n1;
		int i1, i2;
		String s1;
		V0 v1;

		for(;;) {
			switch(stat) {
			case 10000:
				/*
				 * S -> *E
				 * E -> *( L )
				 *    | *- E
				 *    | *E ^ E
				 *    | *E / E
				 *    | *E * E
				 *    | *E % E
				 *    | *E mod E
				 *    | *E + E
				 *    | *E - E
				 *    | *E relation-operator E
				 *    | *! E
				 *    | *E && E
				 *    | *E || E
				 *    | *symbol ( E )
				 *    | *V assign-operator E
				 *    | *++ V
				 *    | *-- V
				 *    | *V ++
				 *    | *V --
				 *    | *V
				 *    | *number
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(10005);
				} else if(gt == BcNonterminal.VAR) {
					shift(10072);
				} else if(eqchar('(')) {
					shift(10010);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10040);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10050);
				} else if(eqchar('-')) {
					shift(10060);
				} else if(isSymbol()) {
					shift(10070);
				} else if(eqchar('!')) {
					shift(10115);
				} else if(isNumber()) {
					shift(10125);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10005:
				/*
				 * S -> E*
				 * E -> E *^ E
				 *    | E *'/' E
				 *    | E ** E
				 *    | E *% E
				 *    | E *mod E
				 *    | E *+ E
				 *    | E *- E
				 *    | E *relation-operator E
				 *    | E *&& E
				 *    | E *|| E
				 */
				if(isEof()) {
					return disp;
				} else if(eqchar('^')) {
					shift(10140);
				} else if(eqchar('/')) {
					shift(10150);
				} else if(eqchar('*')) {
					shift(10160);
				} else if(eqchar('%')) {
					shift(10170);
				} else if(isSymbol("mod")) {
					shift(13000);
				} else if(eqchar('+')) {
					shift(10180);
				} else if(eqchar('-')) {
					shift(10190);
				} else if(isRelop()) {
					shift(10200);
				} else if(equalTo(BcLogical.AND)) {
					shift(10210);
				} else if(equalTo(BcLogical.OR)) {
					shift(10220);
				} else {
					return disp;
				}
				break;
			case 10010:
				/*
				 * E -> ( *E )
				 *    | *( E )
				 *    | *- E
				 *    | *E ^ E
				 *    | *E / E
				 *    | *E * E
				 *    | *E % E
				 *    | *E mod E
				 *    | *E + E
				 *    | *E - E
				 *    | *E relation-operator E
				 *    | *! E
				 *    | *E && E
				 *    | *E || E
				 *    | *symbol ( E )
				 *    | *V assign-operator E
				 *    | *++ V
				 *    | *-- V
				 *    | *V ++
				 *    | *V --
				 *    | *V
				 *    | *number
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(10020);
				} else if(gt == BcNonterminal.VAR) {
					shift(10072);
				} else if(eqchar('(')) {
					shift(10010);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10040);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10050);
				} else if(eqchar('-')) {
					shift(10060);
				} else if(isSymbol()) {
					shift(10070);
				} else if(eqchar('!')) {
					shift(10115);
				} else if(isNumber()) {
					shift(10125);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10020:
				/*
				 * E -> ( E *)
				 *    | E *^ E
				 *    | E *'/' E
				 *    | E ** E
				 *    | E *% E
				 *    | E *mod E
				 *    | E *+ E
				 *    | E *- E
				 *    | E *relation-operator E
				 *    | E *&& E
				 *    | E *|| E
				 */
				if(eqchar(')')) {
					shift(10030);
				} else if(eqchar('^')) {
					shift(10140);
				} else if(eqchar('/')) {
					shift(10150);
				} else if(eqchar('*')) {
					shift(10160);
				} else if(eqchar('%')) {
					shift(10170);
				} else if(isSymbol("mod")) {
					shift(13000);
				} else if(eqchar('+')) {
					shift(10180);
				} else if(eqchar('-')) {
					shift(10190);
				} else if(isRelop()) {
					shift(10200);
				} else if(equalTo(BcLogical.AND)) {
					shift(10210);
				} else if(equalTo(BcLogical.OR)) {
					shift(10220);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10030:
				/*
				 * E -> ( E )*
				 */
				pop();  pop();  pop();
				setGoto(BcNonterminal.EXPR);
				break;
			case 10040:
				/*
				 * E -> ++ *V
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(10045);
				} else if(gt == BcNonterminal.VAR) {
					shift(10045);
				} else if(isSymbol()) {
					shift(10070);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10045:
				/*
				 * E -> ++ V*
				 */
				pop();  pop();
				v1 = (V0)sem.remove(sem.size() - 1);
				b.format("%s1+%s", v1.toString(), v1.storeToString());
				setGoto(BcNonterminal.EXPR);
				break;
			case 10050:
				/*
				 * E -> -- *V
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.VAR) {
					shift(10055);
				} else if(isSymbol()) {
					shift(10070);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10055:
				/*
				 * E -> -- V*
				 */
				pop();  pop();
				v1 = (V0)sem.remove(sem.size() - 1);
				b.format("%s1-%s", v1.toString(), v1.storeToString());
				setGoto(BcNonterminal.EXPR);
				break;
			case 10060:
				/*
				 * E -> - *E
				 *    | *( E )
				 *    | *- E
				 *    | *E ^ E
				 *    | *E / E
				 *    | *E * E
				 *    | *E % E
				 *    | *E mod E
				 *    | *E + E
				 *    | *E - E
				 *    | *E relation-operator E
				 *    | *! E
				 *    | *E && E
				 *    | *E || E
				 *    | *symbol ( E )
				 *    | *V assign-operator E
				 *    | *++ V
				 *    | *-- V
				 *    | *V ++
				 *    | *V --
				 *    | *V
				 *    | *number
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(10065);
				} else if(gt == BcNonterminal.VAR) {
					shift(10072);
				} else if(eqchar('(')) {
					shift(10010);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10040);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10050);
				} else if(isSymbol()) {
					shift(10070);
				} else if(eqchar('!')) {
					shift(10115);
				} else if(isNumber()) {
					shift(10125);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10065:
				/*
				 * E -> - E*
				 *    | ( *E )
				 *    | E *^ E
				 *    | E *'/' E
				 *    | E *'*' E
				 *    | E *% E
				 *    | E *+ E
				 *    | E *- E
				 *    | E *relation-operator E
				 *    | E *&& E
				 *    | E *|| E
				 */
				pop();  pop();
				b.append("0r-");
				setGoto(BcNonterminal.EXPR);
				break;
			case 10070:
				/*
				 * E -> symbol *( L )
				 * V -> symbol*
				 *    | symbol *[ E ]
				 */
				if(eqchar('(')) {
					sem.add(0);
					shift(10085);
				} else if(eqchar('[')) {
					shift(10100);
				} else {
					sem.add(new VS(ns.getCharacter(
							((BcSymbol)pop()).toString())));
					setGoto(BcNonterminal.VAR);
				}
				break;
			case 10072:
				/*
				 * E -> V *assign-operator E
				 *    | V *++
				 *    | V *--
				 *    | V*
				 */
				if(isAssignop()) {
					shift(10074);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10076);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10078);
				} else {
					pop();
					s1 = sem.remove(sem.size() - 1).toString();
					b.print(s1);
					setGoto(BcNonterminal.EXPR);
				}
				break;
			case 10074:
				/*
				 * E -> V assign-operator *E
				 *    | *( E )
				 *    | *- E
				 *    | *E ^ E
				 *    | *E / E
				 *    | *E * E
				 *    | *E % E
				 *    | *E mod E
				 *    | *E + E
				 *    | *E - E
				 *    | *E relation-operator E
				 *    | *! E
				 *    | *E && E
				 *    | *E || E
				 *    | *symbol ( E )
				 *    | *V assign-operator E
				 *    | *++ V
				 *    | *-- V
				 *    | *V ++
				 *    | *V --
				 *    | *V
				 *    | *number
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(10080);
				} else if(gt == BcNonterminal.VAR) {
					shift(10072);
				} else if(eqchar('(')) {
					shift(10010);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10040);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10050);
				} else if(eqchar('-')) {
					shift(10060);
				} else if(isSymbol()) {
					shift(10070);
				} else if(eqchar('!')) {
					shift(10115);
				} else if(isNumber()) {
					shift(10125);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10076:
				/*
				 * E -> V ++*
				 */
				pop();  pop();
				v1 = (V0)sem.remove(sem.size() - 1);
				b.format("%sd1+%s捨", v1.toString(), v1.storeToString());
				setGoto(BcNonterminal.EXPR);
				break;
			case 10078:
				/*
				 * E -> V --*
				 */
				pop();  pop();
				v1 = (V0)sem.remove(sem.size() - 1);
				b.format("%sd1-%s捨", v1.toString(), v1.storeToString());
				setGoto(BcNonterminal.EXPR);
				break;
			case 10080:
				/*
				 * E -> V assign-operator E*
				 *    | E *^ E
				 *    | E *'/' E
				 *    | E *'*' E
				 *    | E *% E
				 *    | E *mod E
				 *    | E *+ E
				 *    | E *- E
				 *    | E *relation-operator E
				 *    | E *&& E
				 *    | E *|| E
				 */
				if(eqchar('^')) {
					shift(10140);
				} else if(eqchar('/')) {
					shift(10150);
				} else if(eqchar('*')) {
					shift(10160);
				} else if(eqchar('%')) {
					shift(10170);
				} else if(isSymbol("mod")) {
					shift(13000);
				} else if(eqchar('+')) {
					shift(10180);
				} else if(eqchar('-')) {
					shift(10190);
				} else if(isRelop()) {
					shift(10200);
				} else if(equalTo(BcLogical.AND)) {
					shift(10210);
				} else if(equalTo(BcLogical.OR)) {
					shift(10220);
				} else {
					pop();  a1 = (BcAssignOp)pop();  pop();
					v1 = (V0)sem.remove(sem.size() - 1);
					if(a1.isSimple()) {
						b.print(v1.storeToString());
					} else {
						b.print(v1.storeopToString(a1.getOperation()));
					}
					setGoto(BcNonterminal.EXPR2);
				}
				break;
			case 10085:
				/*
				 * E -> symbol ( *L )
				 *    | symbol ( *)
				 *    | *( E )
				 *    | *- E
				 *    | *E ^ E
				 *    | *E / E
				 *    | *E * E
				 *    | *E % E
				 *    | *E mod E
				 *    | *E + E
				 *    | *E - E
				 *    | *E relation-operator E
				 *    | *! E
				 *    | *E && E
				 *    | *E || E
				 *    | *symbol ( E )
				 *    | *V assign-operator E
				 *    | *++ V
				 *    | *-- V
				 *    | *V ++
				 *    | *V --
				 *    | *V
				 *    | *number
				 * V -> *symbol
				 *    | *symbol [ E ]
				 * L -> *L , E
				 *    | *E
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(11000);
				} else if(gt == BcNonterminal.VAR) {
					shift(10072);
				} else if(gt == BcNonterminal.LIST) {
					shift(11010);
				} else if(eqchar('(')) {
					shift(10010);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10040);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10050);
				} else if(eqchar('-')) {
					shift(10060);
				} else if(isSymbol()) {
					shift(10070);
				} else if(eqchar('!')) {
					shift(10115);
				} else if(isNumber()) {
					shift(10125);
				} else if(eqchar(')')) {
					stack.add(null);
					stack.add(null);
					shift(11020);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 11000:
				/*
				 * L -> E*
				 *    | E *^ E
				 *    | E *'/' E
				 *    | E *'*' E
				 *    | E *% E
				 *    | E *mod E
				 *    | E *+ E
				 *    | E *- E
				 *    | E *relation-operator E
				 *    | E *&& E
				 *    | E *|| E
				 */
				if(eqchar('^')) {
					shift(10140);
				} else if(eqchar('/')) {
					shift(10150);
				} else if(eqchar('*')) {
					shift(10160);
				} else if(eqchar('%')) {
					shift(10170);
				} else if(isSymbol("mod")) {
					shift(13000);
				} else if(eqchar('+')) {
					shift(10180);
				} else if(eqchar('-')) {
					shift(10190);
				} else if(isRelop()) {
					shift(10200);
				} else if(equalTo(BcLogical.AND)) {
					shift(10210);
				} else if(equalTo(BcLogical.OR)) {
					shift(10220);
				} else {
					pop();
					sem.set(sem.size() - 1, 1);
					setGoto(BcNonterminal.LIST);
				}
				break;
			case 11010:
				/*
				 * E -> symbol ( L *)
				 * L -> L *, E
				 */
				if(eqchar(')')) {
					shift(11020);
				} else if(eqchar(',')) {
					shift(11030);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 11020:
				/*
				 * E -> symbol ( L )*
				 */
				pop();  pop();  pop();
				y1 = (BcSymbol)pop();
				i1 = ((Integer)sem.remove(sem.size() - 1)).intValue();
				if(y1.toString().equals("sqrt")) {
					if(i1 != 1) {
						throw new BcSyntaxException();
					}
					b.print('v');
				} else if(y1.toString().equals("length")) {
					if(i1 != 1) {
						throw new BcSyntaxException();
					}
					b.print('Z');
				} else if(y1.toString().equals("scale")) {
					if(i1 != 1) {
						throw new BcSyntaxException();
					}
					b.print('X');
				} else if(y1.toString().equals("tentothe")) {
					if(i1 != 1) {
						throw new BcSyntaxException();
					}
					b.print('万');
//				} else if(y1.toString().equals("throw")) {
//					if(i1 != 1) {
//						throw new BcSyntaxException();
//					}
//					b.print('誤');
				} else if(y1.toString().equals("irr")) {
					b.format("%d利", i1);
				} else if((i2 = ns.getArity(y1.toString())) >= 0) {
					if(i1 != i2) {
						throw new BcSyntaxException();
					}
					b.format("l%cx", ns.getFunction(y1.toString()));
				}
				setGoto(BcNonterminal.EXPR);
				break;
			case 11030:
				/*
				 * L -> L , *E
				 *    | *( E )
				 *    | *- E
				 *    | *E ^ E
				 *    | *E / E
				 *    | *E * E
				 *    | *E % E
				 *    | *E mod E
				 *    | *E + E
				 *    | *E - E
				 *    | *E relation-operator E
				 *    | *! E
				 *    | *E && E
				 *    | *E || E
				 *    | *symbol ( E )
				 *    | *V assign-operator E
				 *    | *++ V
				 *    | *-- V
				 *    | *V ++
				 *    | *V --
				 *    | *V
				 *    | *number
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(11040);
				} else if(gt == BcNonterminal.VAR) {
					shift(10072);
				} else if(eqchar('(')) {
					shift(10010);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10040);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10050);
				} else if(eqchar('-')) {
					shift(10060);
				} else if(isSymbol()) {
					shift(10070);
				} else if(eqchar('!')) {
					shift(10115);
				} else if(isNumber()) {
					shift(10125);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 11040:
				/*
				 * L -> L, E*
				 *    | E *^ E
				 *    | E *'/' E
				 *    | E *'*' E
				 *    | E *% E
				 *    | E *mod E
				 *    | E *+ E
				 *    | E *- E
				 *    | E *relation-operator E
				 *    | E *&& E
				 *    | E *|| E
				 */
				if(eqchar('^')) {
					shift(10140);
				} else if(eqchar('/')) {
					shift(10150);
				} else if(eqchar('*')) {
					shift(10160);
				} else if(eqchar('%')) {
					shift(10170);
				} else if(isSymbol("mod")) {
					shift(13000);
				} else if(eqchar('+')) {
					shift(10180);
				} else if(eqchar('-')) {
					shift(10190);
				} else if(isRelop()) {
					shift(10200);
				} else if(equalTo(BcLogical.AND)) {
					shift(10210);
				} else if(equalTo(BcLogical.OR)) {
					shift(10220);
				} else {
					pop();  pop();  pop();
					i1 = ((Integer)sem.get(sem.size() - 1)).intValue();
					sem.set(sem.size() - 1, i1 + 1);
					setGoto(BcNonterminal.LIST);
				}
				break;
			case 10100:
				/*
				 * V -> symbol [ *E ]
				 * E -> *( E )
				 *    | *- E
				 *    | *E ^ E
				 *    | *E / E
				 *    | *E * E
				 *    | *E % E
				 *    | *E mod E
				 *    | *E + E
				 *    | *E - E
				 *    | *E relation-operator E
				 *    | *! E
				 *    | *E && E
				 *    | *E || E
				 *    | *symbol ( E )
				 *    | *V assign-operator E
				 *    | *++ V
				 *    | *-- V
				 *    | *V ++
				 *    | *V --
				 *    | *V
				 *    | *number
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(10105);
				} else if(gt == BcNonterminal.VAR) {
					shift(10072);
				} else if(eqchar('(')) {
					shift(10010);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10040);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10050);
				} else if(eqchar('-')) {
					shift(10060);
				} else if(isSymbol()) {
					shift(10070);
				} else if(eqchar('!')) {
					shift(10115);
				} else if(isNumber()) {
					shift(10125);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10105:
				/*
				 * V -> symbol [ E* ]
				 * E -> E *^ E
				 *    | E *'/' E
				 *    | E *'*' E
				 *    | E *% E
				 *    | E *mod E
				 *    | E *+ E
				 *    | E *- E
				 *    | E *relation-operator E
				 *    | E *&& E
				 *    | E *|| E
				 */
				if(eqchar(']')) {
					shift(10110);
				} else if(eqchar('^')) {
					shift(10140);
				} else if(eqchar('/')) {
					shift(10150);
				} else if(eqchar('*')) {
					shift(10160);
				} else if(eqchar('%')) {
					shift(10170);
				} else if(isSymbol("mod")) {
					shift(13000);
				} else if(eqchar('+')) {
					shift(10180);
				} else if(eqchar('-')) {
					shift(10190);
				} else if(isRelop()) {
					shift(10200);
				} else if(equalTo(BcLogical.AND)) {
					shift(10210);
				} else if(equalTo(BcLogical.OR)) {
					shift(10220);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10110:
				/*
				 * V -> symbol [ E ]*
				 */
				pop();  pop();  pop();
				sem.add(new VA(ns.getCharacter(
						((BcSymbol)pop()).toString())));
				setGoto(BcNonterminal.VAR);
				break;
			case 10115:
				/*
				 * E -> ! *E
				 *    | *( E )
				 *    | *- E
				 *    | *E ^ E
				 *    | *E / E
				 *    | *E * E
				 *    | *E % E
				 *    | *E mod E
				 *    | *E + E
				 *    | *E - E
				 *    | *E relation-operator E
				 *    | *! E
				 *    | *E && E
				 *    | *E || E
				 *    | *symbol ( E )
				 *    | *V assign-operator E
				 *    | *++ V
				 *    | *-- V
				 *    | *V ++
				 *    | *V --
				 *    | *V
				 *    | *number
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(10120);
				} else if(gt == BcNonterminal.VAR) {
					shift(10072);
				} else if(eqchar('(')) {
					shift(10010);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10040);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10050);
				} else if(eqchar('-')) {
					shift(10060);
				} else if(isSymbol()) {
					shift(10070);
				} else if(eqchar('!')) {
					shift(10115);
				} else if(isNumber()) {
					shift(10125);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10120:
				/*
				 * E -> ! E*
				 *    | E *^ E
				 *    | E *'/' E
				 *    | E *'*' E
				 *    | E *% E
				 *    | E *mod E
				 *    | E *+ E
				 *    | E *- E
				 *    | E *relation-operator E
				 *    | E *&& E
				 *    | E *|| E
				 */
				if(eqchar('^')) {
					shift(10140);
				} else if(eqchar('/')) {
					shift(10150);
				} else if(eqchar('*')) {
					shift(10160);
				} else if(eqchar('%')) {
					shift(10170);
				} else if(isSymbol("mod")) {
					shift(13000);
				} else if(eqchar('+')) {
					shift(10180);
				} else if(eqchar('-')) {
					shift(10190);
				} else if(isRelop()) {
					shift(10200);
				} else {
					pop();  pop();
					b.append("N");
					setGoto(BcNonterminal.EXPR);
				}
				break;
			case 10125:
				/*
				 * E -> number*
				 */
				n1 = (BcNumber)pop();
				b.append(n1.toString()).append(' ');
				setGoto(BcNonterminal.EXPR);
				break;
			case 10140:
				/*
				 * E -> E ^ *E
				 *    | *( E )
				 *    | *- E
				 *    | *E ^ E
				 *    | *E / E
				 *    | *E * E
				 *    | *E % E
				 *    | *E mod E
				 *    | *E + E
				 *    | *E - E
				 *    | *E relation-operator E
				 *    | *! E
				 *    | *E && E
				 *    | *E || E
				 *    | *symbol ( E )
				 *    | *V assign-operator E
				 *    | *++ V
				 *    | *-- V
				 *    | *V ++
				 *    | *V --
				 *    | *V
				 *    | *number
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(10145);
				} else if(gt == BcNonterminal.VAR) {
					shift(10072);
				} else if(eqchar('(')) {
					shift(10010);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10040);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10050);
				} else if(eqchar('-')) {
					shift(10060);
				} else if(isSymbol()) {
					shift(10070);
				} else if(eqchar('!')) {
					shift(10115);
				} else if(isNumber()) {
					shift(10125);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10145:
				/*
				 * E -> E ^ E*
				 *    | E *^ E
				 *    | E *'/' E
				 *    | E *'*' E
				 *    | E *% E
				 *    | E *mod E
				 *    | E *+ E
				 *    | E *- E
				 *    | E *relation-operator E
				 *    | E *&& E
				 *    | E *|| E
				 */
				if(eqchar('^')) {
					shift(10140);
				} else {
					pop();  pop();  pop();
					b.append("^");
					setGoto(BcNonterminal.EXPR);
				}
				break;
			case 10150:
				/*
				 * E -> E / *E
				 *    | *( E )
				 *    | *- E
				 *    | *E ^ E
				 *    | *E / E
				 *    | *E * E
				 *    | *E % E
				 *    | *E mod E
				 *    | *E + E
				 *    | *E - E
				 *    | *E relation-operator E
				 *    | *! E
				 *    | *E && E
				 *    | *E || E
				 *    | *symbol ( E )
				 *    | *V assign-operator E
				 *    | *++ V
				 *    | *-- V
				 *    | *V ++
				 *    | *V --
				 *    | *V
				 *    | *number
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(10155);
				} else if(gt == BcNonterminal.VAR) {
					shift(10072);
				} else if(eqchar('(')) {
					shift(10010);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10040);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10050);
				} else if(eqchar('-')) {
					shift(10060);
				} else if(isSymbol()) {
					shift(10070);
				} else if(eqchar('!')) {
					shift(10115);
				} else if(isNumber()) {
					shift(10125);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10155:
				/*
				 * E -> E / E*
				 *    | E *^ E
				 *    | E *'/' E
				 *    | E *'*' E
				 *    | E *% E
				 *    | E *mod E
				 *    | E *+ E
				 *    | E *- E
				 *    | E *relation-operator E
				 *    | E *&& E
				 *    | E *|| E
				 */
				if(eqchar('^')) {
					shift(10140);
				} else {
					pop();  pop();  pop();
					b.append("/");
					setGoto(BcNonterminal.EXPR);
				}
				break;
			case 10160:
				/*
				 * E -> E * *E
				 *    | *( E )
				 *    | *- E
				 *    | *E ^ E
				 *    | *E / E
				 *    | *E * E
				 *    | *E % E
				 *    | *E mod E
				 *    | *E + E
				 *    | *E - E
				 *    | *E relation-operator E
				 *    | *! E
				 *    | *E && E
				 *    | *E || E
				 *    | *symbol ( E )
				 *    | *V assign-operator E
				 *    | *++ V
				 *    | *-- V
				 *    | *V ++
				 *    | *V --
				 *    | *V
				 *    | *number
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(10165);
				} else if(gt == BcNonterminal.VAR) {
					shift(10072);
				} else if(eqchar('(')) {
					shift(10010);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10040);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10050);
				} else if(eqchar('-')) {
					shift(10060);
				} else if(isSymbol()) {
					shift(10070);
				} else if(eqchar('!')) {
					shift(10115);
				} else if(isNumber()) {
					shift(10125);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10165:
				/*
				 * E -> E * E*
				 *    | E *^ E
				 *    | E *'/' E
				 *    | E *'*' E
				 *    | E *% E
				 *    | E *mod E
				 *    | E *+ E
				 *    | E *- E
				 *    | E *relation-operator E
				 *    | E *&& E
				 *    | E *|| E
				 */
				if(eqchar('^')) {
					shift(10140);
				} else {
					pop();  pop();  pop();
					b.append("*");
					setGoto(BcNonterminal.EXPR);
				}
				break;
			case 10170:
				/*
				 * E -> E % *E
				 *    | *( E )
				 *    | *- E
				 *    | *E ^ E
				 *    | *E / E
				 *    | *E * E
				 *    | *E % E
				 *    | *E mod E
				 *    | *E + E
				 *    | *E - E
				 *    | *E relation-operator E
				 *    | *! E
				 *    | *E && E
				 *    | *E || E
				 *    | *symbol ( E )
				 *    | *V assign-operator E
				 *    | *++ V
				 *    | *-- V
				 *    | *V ++
				 *    | *V --
				 *    | *V
				 *    | *number
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(10175);
				} else if(gt == BcNonterminal.VAR) {
					shift(10072);
				} else if(eqchar('(')) {
					shift(10010);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10040);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10050);
				} else if(eqchar('-')) {
					shift(10060);
				} else if(isSymbol()) {
					shift(10070);
				} else if(eqchar('!')) {
					shift(10115);
				} else if(isNumber()) {
					shift(10125);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10175:
				/*
				 * E -> E % E*
				 *    | E *^ E
				 *    | E *'/' E
				 *    | E *'*' E
				 *    | E *% E
				 *    | E *mod E
				 *    | E *+ E
				 *    | E *- E
				 *    | E *relation-operator E
				 *    | E *&& E
				 *    | E *|| E
				 */
				if(eqchar('^')) {
					shift(10140);
				} else {
					pop();  pop();  pop();
					b.append("%");
					setGoto(BcNonterminal.EXPR);
				}
				break;
			case 13000:
				/*
				 * E -> E mod *E
				 *    | *( E )
				 *    | *- E
				 *    | *E ^ E
				 *    | *E / E
				 *    | *E * E
				 *    | *E % E
				 *    | *E mod E
				 *    | *E + E
				 *    | *E - E
				 *    | *E relation-operator E
				 *    | *! E
				 *    | *E && E
				 *    | *E || E
				 *    | *symbol ( E )
				 *    | *V assign-operator E
				 *    | *++ V
				 *    | *-- V
				 *    | *V ++
				 *    | *V --
				 *    | *V
				 *    | *number
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(13010);
				} else if(gt == BcNonterminal.VAR) {
					shift(10072);
				} else if(eqchar('(')) {
					shift(10010);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10040);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10050);
				} else if(eqchar('-')) {
					shift(10060);
				} else if(isSymbol()) {
					shift(10070);
				} else if(eqchar('!')) {
					shift(10115);
				} else if(isNumber()) {
					shift(10125);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 13010:
				/*
				 * E -> E mod E*
				 *    | E *^ E
				 *    | E *'/' E
				 *    | E *'*' E
				 *    | E *% E
				 *    | E *mod E
				 *    | E *+ E
				 *    | E *- E
				 *    | E *relation-operator E
				 *    | E *&& E
				 *    | E *|| E
				 */
				if(eqchar('^')) {
					shift(10140);
				} else {
					pop();  pop();  pop();
					b.append("法");
					setGoto(BcNonterminal.EXPR);
				}
				break;
			case 10180:
				/*
				 * E -> E + *E
				 *    | *( E )
				 *    | *- E
				 *    | *E ^ E
				 *    | *E / E
				 *    | *E * E
				 *    | *E % E
				 *    | *E mod E
				 *    | *E + E
				 *    | *E - E
				 *    | *E relation-operator E
				 *    | *! E
				 *    | *E && E
				 *    | *E || E
				 *    | *symbol ( E )
				 *    | *V assign-operator E
				 *    | *++ V
				 *    | *-- V
				 *    | *V ++
				 *    | *V --
				 *    | *V
				 *    | *number
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(10185);
				} else if(gt == BcNonterminal.VAR) {
					shift(10072);
				} else if(eqchar('(')) {
					shift(10010);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10040);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10050);
				} else if(eqchar('-')) {
					shift(10060);
				} else if(isSymbol()) {
					shift(10070);
				} else if(eqchar('!')) {
					shift(10115);
				} else if(isNumber()) {
					shift(10125);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10185:
				/*
				 * E -> E + E*
				 *    | E *^ E
				 *    | E *'/' E
				 *    | E *'*' E
				 *    | E *% E
				 *    | E *mod E
				 *    | E *+ E
				 *    | E *- E
				 *    | E *relation-operator E
				 *    | E *&& E
				 *    | E *|| E
				 */
				if(eqchar('^')) {
					shift(10140);
				} else if(eqchar('/')) {
					shift(10150);
				} else if(eqchar('*')) {
					shift(10160);
				} else if(eqchar('%')) {
					shift(10170);
				} else if(isSymbol("mod")) {
					shift(13000);
				} else {
					pop();  pop();  pop();
					b.append("+");
					setGoto(BcNonterminal.EXPR);
				}
				break;
			case 10190:
				/*
				 * E -> E - *E
				 *    | *( E )
				 *    | *- E
				 *    | *E ^ E
				 *    | *E / E
				 *    | *E * E
				 *    | *E % E
				 *    | *E mod E
				 *    | *E + E
				 *    | *E - E
				 *    | *E relation-operator E
				 *    | *! E
				 *    | *E && E
				 *    | *E || E
				 *    | *symbol ( E )
				 *    | *V assign-operator E
				 *    | *++ V
				 *    | *-- V
				 *    | *V ++
				 *    | *V --
				 *    | *V
				 *    | *number
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(10195);
				} else if(gt == BcNonterminal.VAR) {
					shift(10072);
				} else if(eqchar('(')) {
					shift(10010);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10040);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10050);
				} else if(eqchar('-')) {
					shift(10060);
				} else if(isSymbol()) {
					shift(10070);
				} else if(eqchar('!')) {
					shift(10115);
				} else if(isNumber()) {
					shift(10125);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10195:
				/*
				 * E -> E - E*
				 *    | E *^ E
				 *    | E *'/' E
				 *    | E *'*' E
				 *    | E *% E
				 *    | E *mod E
				 *    | E *+ E
				 *    | E *- E
				 *    | E *relation-operator E
				 *    | E *&& E
				 *    | E *|| E
				 */
				if(eqchar('^')) {
					shift(10140);
				} else if(eqchar('/')) {
					shift(10150);
				} else if(eqchar('*')) {
					shift(10160);
				} else if(eqchar('%')) {
					shift(10170);
				} else if(isSymbol("mod")) {
					shift(13000);
				} else {
					pop();  pop();  pop();
					b.append("-");
					setGoto(BcNonterminal.EXPR);
				}
				break;
			case 10200:
				/*
				 * E -> E relation-operator *E
				 *    | *( E )
				 *    | *- E
				 *    | *E ^ E
				 *    | *E / E
				 *    | *E * E
				 *    | *E % E
				 *    | *E mod E
				 *    | *E + E
				 *    | *E - E
				 *    | *E relation-operator E
				 *    | *! E
				 *    | *E && E
				 *    | *E || E
				 *    | *symbol ( E )
				 *    | *V assign-operator E
				 *    | *++ V
				 *    | *-- V
				 *    | *V ++
				 *    | *V --
				 *    | *V
				 *    | *number
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(10205);
				} else if(gt == BcNonterminal.VAR) {
					shift(10072);
				} else if(eqchar('(')) {
					shift(10010);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10040);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10050);
				} else if(eqchar('-')) {
					shift(10060);
				} else if(isSymbol()) {
					shift(10070);
				} else if(eqchar('!')) {
					shift(10115);
				} else if(isNumber()) {
					shift(10125);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10205:
				/*
				 * E -> E relation-operator E*
				 *    | E *^ E
				 *    | E *'/' E
				 *    | E *'*' E
				 *    | E *% E
				 *    | E *mod E
				 *    | E *+ E
				 *    | E *- E
				 *    | E *relation-operator E
				 *    | E *&& E
				 *    | E *|| E
				 */
				if(eqchar('^')) {
					shift(10140);
				} else if(eqchar('/')) {
					shift(10150);
				} else if(eqchar('*')) {
					shift(10160);
				} else if(eqchar('%')) {
					shift(10170);
				} else if(isSymbol("mod")) {
					shift(13000);
				} else if(eqchar('+')) {
					shift(10180);
				} else if(eqchar('-')) {
					shift(10190);
				} else {
					pop();
					b.append(((BcRelop)pop()).getCommand());
					pop();
					setGoto(BcNonterminal.EXPR);
				}
				break;
			case 10210:
				/*
				 * E -> E && *E
				 *    | *( E )
				 *    | *- E
				 *    | *E ^ E
				 *    | *E / E
				 *    | *E * E
				 *    | *E % E
				 *    | *E mod E
				 *    | *E + E
				 *    | *E - E
				 *    | *E relation-operator E
				 *    | *! E
				 *    | *E && E
				 *    | *E || E
				 *    | *symbol ( E )
				 *    | *V assign-operator E
				 *    | *++ V
				 *    | *-- V
				 *    | *V ++
				 *    | *V --
				 *    | *V
				 *    | *number
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(10215);
				} else if(gt == BcNonterminal.VAR) {
					shift(10072);
				} else if(eqchar('(')) {
					shift(10010);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10040);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10050);
				} else if(eqchar('-')) {
					shift(10060);
				} else if(isSymbol()) {
					shift(10070);
				} else if(eqchar('!')) {
					shift(10115);
				} else if(isNumber()) {
					shift(10125);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10215:
				/*
				 * E -> E && E*
				 *    | E *^ E
				 *    | E *'/' E
				 *    | E *'*' E
				 *    | E *% E
				 *    | E *mod E
				 *    | E *+ E
				 *    | E *- E
				 *    | E *relation-operator E
				 *    | E *&& E
				 *    | E *|| E
				 */
				if(eqchar('^')) {
					shift(10140);
				} else if(eqchar('/')) {
					shift(10150);
				} else if(eqchar('*')) {
					shift(10160);
				} else if(eqchar('%')) {
					shift(10170);
				} else if(isSymbol("mod")) {
					shift(13000);
				} else if(eqchar('+')) {
					shift(10180);
				} else if(eqchar('-')) {
					shift(10190);
				} else if(isRelop()) {
					shift(10200);
				} else {
					pop();  pop();  pop();
					b.append("＆");
					setGoto(BcNonterminal.EXPR);
				}
				break;
			case 10220:
				/*
				 * E -> E || *E
				 *    | *( E )
				 *    | *- E
				 *    | *E ^ E
				 *    | *E / E
				 *    | *E * E
				 *    | *E % E
				 *    | *E mod E
				 *    | *E + E
				 *    | *E - E
				 *    | *E relation-operator E
				 *    | *! E
				 *    | *E && E
				 *    | *E || E
				 *    | *symbol ( E )
				 *    | *V assign-operator E
				 *    | *++ V
				 *    | *-- V
				 *    | *V ++
				 *    | *V --
				 *    | *V
				 *    | *number
				 * V -> *symbol
				 *    | *symbol [ E ]
				 */
				if(gt == BcNonterminal.EXPR ||
						gt == BcNonterminal.EXPR2) {
					shift(10225);
				} else if(gt == BcNonterminal.VAR) {
					shift(10072);
				} else if(eqchar('(')) {
					shift(10010);
				} else if(equalTo(BcIncDec.INC)) {
					shift(10040);
				} else if(equalTo(BcIncDec.DEC)) {
					shift(10050);
				} else if(eqchar('-')) {
					shift(10060);
				} else if(isSymbol()) {
					shift(10070);
				} else if(eqchar('!')) {
					shift(10115);
				} else if(isNumber()) {
					shift(10125);
				} else {
					throw new BcSyntaxException();
				}
				break;
			case 10225:
				/*
				 * E -> E || E*
				 *    | E *^ E
				 *    | E *'/' E
				 *    | E *'*' E
				 *    | E *% E
				 *    | E *mod E
				 *    | E *+ E
				 *    | E *- E
				 *    | E *relation-operator E
				 *    | E *&& E
				 *    | E *|| E
				 */
				if(eqchar('^')) {
					shift(10140);
				} else if(eqchar('/')) {
					shift(10150);
				} else if(eqchar('*')) {
					shift(10160);
				} else if(eqchar('%')) {
					shift(10170);
				} else if(isSymbol("mod")) {
					shift(13000);
				} else if(eqchar('+')) {
					shift(10180);
				} else if(eqchar('-')) {
					shift(10190);
				} else if(isRelop()) {
					shift(10200);
				} else if(equalTo(BcLogical.AND)) {
					shift(10210);
				} else {
					pop();  pop();  pop();
					b.append("｜");
					setGoto(BcNonterminal.EXPR);
				}
				break;
			}
		}
	}

}
