package jp.kirikiri.tjs2;

import java.util.ArrayList;
import java.util.Stack;

// a class for managing the script block
public class ScriptBlock {
	private static final boolean D_IS_DISASSEMBLE = false;
	private static final boolean LOGD = false;
	private static final String TAG = "ScriptBlock";

	private static final String ERROR_TAG = "Syntax error";

	private boolean mUsingPreProcessor;
	private int mCompileErrorCount;
	private Lexer mLexicalAnalyzer;
	private InterCodeContext mInterCodeContext;
	private InterCodeContext mTopLevelContext;
	private Stack<InterCodeContext> mContextStack;
	private TJS mOwner;
	private ArrayList<InterCodeContext> mInterCodeContextList;

	public void notifyUsingPreProcessror() { mUsingPreProcessor = true; }

	public InterCodeContext getCurrentContext() { return mInterCodeContext; }
	public void pushContextStack( String name, int type) throws TJSException, VariantException {
		InterCodeContext ctx = new InterCodeContext(mInterCodeContext,name,this,type);
		if( mInterCodeContext == null ) {
			if( mTopLevelContext != null ) throw new TJSException(Error.InternalError);
			mTopLevelContext = ctx;
		}
		mContextStack.push(ctx);
		mInterCodeContext = ctx;
	}
	public void popContextStack() throws VariantException, TJSException {
		mInterCodeContext.commit();
		mContextStack.pop();
		if( mContextStack.size() >= 1 )
			mInterCodeContext = mContextStack.peek();
		else
			mInterCodeContext = null;
	}

	private boolean mIsUnlex;
	private int mUnlexToken;
	private int mUnlexValue;
	private int mToken;
	private int mValue;
	private ExprNode mNode;
	private String mName;
	private int mLineOffset;
	private String mScript;

	private String mFirstError;
	private int mFirstErrorPos;

	public ScriptBlock( TJS owner ) {
		mOwner = owner;

		mScript = null;
		mName = null;

		mInterCodeContext = null;
		mTopLevelContext = null;
		mLexicalAnalyzer = null;

		mUsingPreProcessor = false;

		mLineOffset = 0;

		mOwner.addScriptBlock(this);

		mContextStack = new Stack<InterCodeContext>();
		mInterCodeContextList = new ArrayList<InterCodeContext>();

		mCompileErrorCount = 0;
		mNode = null;
	}
	protected void finalize() {

		if( mTopLevelContext != null ) mTopLevelContext = null;
		while( mContextStack.size() > 0 ) {
			//mContextStack.top()->Release();
			mContextStack.pop();
		}

		mOwner.removeScriptBlock(this);

		if( mLexicalAnalyzer != null ) mLexicalAnalyzer = null;

		if( mScript != null ) mScript = null;
		if( mName != null ) mName = null;;

		try {
			super.finalize();
		} catch (Throwable e) {
		}
	}

	public Lexer getLexicalAnalyzer() {
		return mLexicalAnalyzer;
	}
	public int srcPosToLine( int pos ) {
		return mLexicalAnalyzer.srcPosToLine(pos);
	}

	private void unlex( int token, int value ) {
		mIsUnlex = true;
		mUnlexToken = token;
		mUnlexValue = value;
	}
	private void unlex() {
		mIsUnlex = true;
		mUnlexToken = mToken;
		mUnlexValue = mValue;
	}
	private int lex() throws CompileException {
		if( mIsUnlex ) {
			mIsUnlex = false;
			mToken = mUnlexToken;
			mValue = mUnlexValue;
			return mUnlexToken;
		} else {
			mToken = mLexicalAnalyzer.getNext();
			mValue = mLexicalAnalyzer.getValue();
			return mToken;
		}
	}
	public void parse( String script, boolean isexpr, boolean resultneeded ) throws VariantException, CompileException, TJSException {
		mCompileErrorCount = 0;
		mLexicalAnalyzer = new Lexer(this,script,isexpr,resultneeded);

		program();

		// mLexicalAnalyzer = null;
		// TODO 上記解放できるように StringStream をこのクラスのメンバにする必要がある

		if( mCompileErrorCount > 0 ) {
			throw new TJSScriptError( mFirstError, this, mFirstErrorPos);
		}
	}
	public void error( final String msg ) throws CompileException {
		if( mCompileErrorCount == 0 ) {
			mFirstError = msg;
			mFirstErrorPos = mLexicalAnalyzer.getCurrentPosition();
		}
		mCompileErrorCount++;

		String str = Error.SyntaxError.replace( "%1", msg );
		int line = 1+mLexicalAnalyzer.getCurrentLine();
		String message = "Line (" + line + ") : " + str;

		Logger.log( ERROR_TAG, message );
		if( mCompileErrorCount > 20 ) throw new CompileException( Error.TooManyErrors );
	}
	// ----------------------------- parser
	// const_dic_elm
	private ExprNode exprConstDicElm() throws VariantException, CompileException, TJSException {
		int token = lex();
		Variant var;
		if( token == Token.T_CONSTVAL ) {
			String name = mLexicalAnalyzer.getString(mValue);
			token = lex();
			if( token != Token.T_COMMA ) {
				error( Error.ConstDicDelimiterError );
				unlex(); // syntax error
				return null;
			}
			token = lex();
			switch( token ) {
			case Token.T_MINUS:
				token = lex();
				if( token != Token.T_CONSTVAL ) {
					error( Error.ConstDicValueError );
					unlex(); // syntax error
					return null;
				}
				var = mLexicalAnalyzer.getValue(mValue);
				var.changeSign();
				mInterCodeContext.getCurrentNode().addDictionaryElement( name, var );
				return null;
			case Token.T_PLUS:
				token = lex();
				if( token != Token.T_CONSTVAL ) {
					error( Error.ConstDicValueError );
					unlex(); // syntax error
					return null;
				}
				var = mLexicalAnalyzer.getValue(mValue);
				var.toNumber();
				mInterCodeContext.getCurrentNode().addDictionaryElement( name, var );
				return null;
			case Token.T_CONSTVAL:
				mInterCodeContext.getCurrentNode().addDictionaryElement( name, mLexicalAnalyzer.getValue(mValue) );
				return null;
			case Token.T_VOID:
				mInterCodeContext.getCurrentNode().addDictionaryElement( name, new Variant() );
				return null;
			case Token.T_LPARENTHESIS: {
				unlex();
				ExprNode node = exprConstInlineArrayOrDic();
				mInterCodeContext.getCurrentNode().addDictionaryElement( name, node.getValue() );
				return null;
			}
			default:
				error( Error.ConstDicValueError );
				unlex();
				break;
			}
		}
		unlex();
		return null;
	}
	// const_dic_elm_list
	private ExprNode exprConstDicElmList() throws VariantException, CompileException, TJSException {
		int token;
		do {
			exprConstDicElm();
			token = lex();
		} while( token == Token.T_COMMA );
		unlex();
		return null;
	}
	// const_inline_dic
	private ExprNode exprConstInlineDic() throws VariantException, CompileException, TJSException {
		ExprNode node = mInterCodeContext.makeNP0( Token.T_CONSTVAL );
		Dispatch2 dsp = TJS.createDictionaryObject();
		node.setValue( new Variant(dsp,dsp) );
		mInterCodeContext.pushCurrentNode( node );
		exprConstDicElmList();
		node = mInterCodeContext.getCurrentNode();
		mInterCodeContext.popCurrentNode();
		int token = lex();
		if( token == Token.T_RBRACKET ) {
			return node;
		} else {
			error( Error.DicRBRACKETError );
			unlex(); // error
		}
		return null;
	}
	// const_array_elm
	private ExprNode exprConstArrayElm() throws VariantException, CompileException, TJSException {
		int token = lex();
		Variant var;
		switch( token ) {
		case Token.T_MINUS:
			token = lex();
			if( token != Token.T_CONSTVAL ) {
				error( Error.ConstArrayValueError );
				unlex(); // syntax error
				return null;
			}
			var = mLexicalAnalyzer.getValue(mValue);
			var.changeSign();
			mInterCodeContext.getCurrentNode().addArrayElement( var );
			return null;
		case Token.T_PLUS:
			token = lex();
			if( token != Token.T_CONSTVAL ) {
				error( Error.ConstArrayValueError );
				unlex(); // syntax error
				return null;
			}
			var = mLexicalAnalyzer.getValue(mValue);
			var.toNumber();
			mInterCodeContext.getCurrentNode().addArrayElement( var );
			return null;
		case Token.T_CONSTVAL:
			mInterCodeContext.getCurrentNode().addArrayElement( mLexicalAnalyzer.getValue(mValue) );
			return null;
		case Token.T_VOID:
			mInterCodeContext.getCurrentNode().addArrayElement( new Variant() );
			return null;
		case Token.T_LPARENTHESIS: {
			unlex();
			ExprNode node = exprConstInlineArrayOrDic();
			mInterCodeContext.getCurrentNode().addArrayElement( node.getValue() );
			return null;
			}
		}
		unlex();
		return null;
	}
	// const_array_elm_list, const_array_elm_list_opt
	private ExprNode exprConstArrayElmList() throws VariantException, CompileException, TJSException {
		int token;
		do {
			exprConstArrayElm();
			token = lex();
		} while( token == Token.T_COMMA );
		unlex();
		return null;
	}
	// const_inline_array
	private ExprNode exprConstInlineArray() throws VariantException, CompileException, TJSException {
		ExprNode node = mInterCodeContext.makeNP0( Token.T_CONSTVAL );
		Dispatch2 dsp = TJS.createArrayObject();
		node.setValue( new Variant(dsp,dsp) );
		mInterCodeContext.pushCurrentNode( node );
		exprConstArrayElmList();
		node = mInterCodeContext.getCurrentNode();
		mInterCodeContext.popCurrentNode();
		int token = lex();
		if( token == Token.T_RBRACKET ) {
			return node;
		} else {
			error( Error.ArrayRBRACKETError );
			unlex(); // error
		}
		return null;
	}
	private ExprNode exprConstInlineArrayOrDic() throws CompileException, VariantException, TJSException {
		int token = lex();
		if( token == Token.T_LPARENTHESIS ) {
			token = lex();
			if( token != Token.T_CONST ) {
				error( Error.ConstDicArrayStringError );
				unlex();
			}
			token = lex();
			if( token != Token.T_RPARENTHESIS ) {
				error( Error.ConstDicArrayStringError );
				unlex();
			}
			token = lex();
			if( token == Token.T_PERCENT ) { // may be dic
				token = lex();
				if( token == Token.T_LBRACKET ) {
					return exprConstInlineDic();
				} else {
					error( Error.ConstDicLBRACKETError );
					unlex();
				}
			} else if( token == Token.T_LBRACKET ) { // may be array
				return exprConstInlineArray();
			} else {
				error( Error.ConstArrayLBRACKETError );
				unlex();
			}
		} else if( token == Token.T_CAST_CONST ) {
			token = lex();
			if( token == Token.T_PERCENT ) { // may be dic
				token = lex();
				if( token == Token.T_LBRACKET ) {
					return exprConstInlineDic();
				} else {
					error( Error.ConstDicLBRACKETError );
					unlex();
				}
			} else if( token == Token.T_LBRACKET ) { // may be array
				return exprConstInlineArray();
			} else {
				error( Error.ConstArrayLBRACKETError );
				unlex();
			}
		}
		return null;
	}
	// dic_dummy_elm_opt
	private ExprNode exprDicDummyElmOpt() throws CompileException {
		int token = lex();
		if( token == Token.T_RBRACKET ) {
			unlex();
		} else if( token != Token.T_COMMA ) {
			unlex();	// syntax error
			throw new CompileException();
		}
		return null;
	}
	// dic_elm
	private ExprNode exprDicElm() throws VariantException, CompileException, TJSException {
		ExprNode node = null;
		int nodeCount = mInterCodeContext.getNodeToDeleteVectorCount();
		ExprNode node0 = exprExprNoComma();
		int token = lex();
		if( token == Token.T_COMMA ) {
			node = exprExprNoComma();
			return mInterCodeContext.makeNP2(Token.T_DICELM,node0,node);
		} else if( token == Token.T_COLON ) {
			int curNodeCount = mInterCodeContext.getNodeToDeleteVectorCount();
			if( nodeCount == (curNodeCount-1) ) {
				if( node0.getOpecode() == Token.T_SYMBOL ) {
					node0.setOpecode(Token.T_CONSTVAL);
					node = exprExprNoComma();
					return mInterCodeContext.makeNP2(Token.T_DICELM,node0,node);
				}
			}
			error( Error.DicError );
			unlex(); // error
		} else {
			error( Error.DicDelimiterError );
			unlex(); // error
		}
		return null;
	}
	// dic_elm_list
	private ExprNode exprDicElmList() throws VariantException, CompileException, TJSException {
		int token = lex();
		if( token == Token.T_RBRACKET ) {
			unlex();
		} else {
			unlex();
			ExprNode node = exprDicElm();
			mInterCodeContext.getCurrentNode().add( node );
			token = lex();
			while( token == Token.T_COMMA ) {
				token = lex();
				if( token == Token.T_RBRACKET ) {
					break;
				}
				unlex();
				node = exprDicElm();
				mInterCodeContext.getCurrentNode().add( node );
				token = lex();
			}
			unlex();
		}
		return null;
	}
	// inline_dic
	private ExprNode exprInlineDic() throws CompileException, VariantException, TJSException {
		int token = lex();
		if( token == Token.T_PERCENT ) {
			token = lex();
			if( token == Token.T_LBRACKET ) {
				ExprNode node = mInterCodeContext.makeNP0(Token.T_INLINEDIC);
				mInterCodeContext.pushCurrentNode(node);
				exprDicElmList();
//				exprDicDummyElmOpt();
				token = lex();
				if( token == Token.T_RBRACKET ) {
					node = mInterCodeContext.getCurrentNode();
					mInterCodeContext.popCurrentNode();
					return node;
				} else {
					error( Error.DicRBRACKETError );
					unlex(); // error
				}
			} else {
				error( Error.DicLBRACKETError );
				unlex();
			}
		} else {
			unlex();
		}
		return null;
	}
	// array_elm
	private ExprNode exprArrayElm() throws VariantException, CompileException, TJSException {
		int token = lex();
		if( token == Token.T_COMMA || token == Token.T_RBRACKET ) {
			unlex();
			return mInterCodeContext.makeNP1(Token.T_ARRAYARG,null);
		} else {
			unlex();
			ExprNode node = exprExprNoComma();
			return mInterCodeContext.makeNP1(Token.T_ARRAYARG,node);
		}
	}
	// array_elm_list
	private ExprNode exprArrayElmList() throws VariantException, CompileException, TJSException {
		int token;
		do {
			ExprNode node = exprArrayElm();
			mInterCodeContext.getCurrentNode().add( node );
			token = lex();
		} while( token == Token.T_COMMA );
		unlex();
		return null;
	}
	// inline_array
	private ExprNode exprInlineArray() throws CompileException, VariantException, TJSException {
		int token = lex();
		if( token == Token.T_LBRACKET ) {
			ExprNode node = mInterCodeContext.makeNP0(Token.T_INLINEARRAY);
			mInterCodeContext.pushCurrentNode(node);
			exprArrayElmList();
			token = lex();
			if( token == Token.T_RBRACKET ) {
				node = mInterCodeContext.getCurrentNode();
				mInterCodeContext.popCurrentNode();
				return node;
			} else {
				error( Error.ArrayRBRACKETError );
				unlex(); // error
			}
		} else {
			unlex();
		}
		return null;
	}
	// call_arg
	private ExprNode exprCallArg() throws VariantException, CompileException, TJSException {
		int token = lex();
		if( token == Token.T_RPARENTHESIS ) {
			unlex(); // empty
			return null;
//		} else if( token == Token.T_ASTERISK ) {
//			return mInterCodeContext.makeNP1( Token.T_EXPANDARG, null );
		} else {
			unlex();
			ExprNode node = exprExprNoComma();
			if( node != null ) {
				token = lex();
				if( token == Token.T_ASTERISK ) {
					return mInterCodeContext.makeNP1( Token.T_EXPANDARG, node );
				} else if( token == Token.T_ASTERISK_RPARENTHESIS ) {
					unlex( Token.T_RPARENTHESIS, 0 );
					return mInterCodeContext.makeNP1( Token.T_EXPANDARG, node );
				} else if( token == Token.T_ASTERISK_COMMA ) {
					unlex( Token.T_COMMA, 0 );
					return mInterCodeContext.makeNP1( Token.T_EXPANDARG, node );
				} else {
					unlex();
				}
			} else {
				token = lex();
				if( token == Token.T_ASTERISK ) {
					return mInterCodeContext.makeNP1( Token.T_EXPANDARG, null );
				} else if( token == Token.T_ASTERISK_RPARENTHESIS ) {
					unlex( Token.T_RPARENTHESIS, 0 );
					return mInterCodeContext.makeNP1( Token.T_EXPANDARG, null );
				} else {
					unlex();
				}
			}
			return node;
			/*
			ExprNode node = exprMulDivExpr();
			if( node != null ) {
				token = lex();
				if( token == Token.T_ASTERISK ) {
					return mInterCodeContext.makeNP1( Token.T_EXPANDARG, node );
				} else {
					unlex();
				}
			}
			return exprExprNoComma();
			*/
		}
	}
	private ExprNode exprCallArgList2( ExprNode node ) throws VariantException, CompileException, TJSException {
		int token;
		node = mInterCodeContext.makeNP1( Token.T_ARG, node );
		do {
			ExprNode n2 = exprCallArg();
			node = mInterCodeContext.makeNP2( Token.T_ARG, n2, node );
			token = lex();
		} while( token == Token.T_COMMA );
		unlex();
		return node;
	}
	// call_arg_list
	private ExprNode exprCallArgList() throws VariantException, CompileException, TJSException {
		int token = lex();
		if( token == Token.T_OMIT ) {
			return mInterCodeContext.makeNP0( Token.T_OMIT );
		} else {
			unlex();
			ExprNode node = exprCallArg();
			token = lex();
			if( token == Token.T_COMMA ) {
				return exprCallArgList2( node );
			} else {
				unlex();
				return mInterCodeContext.makeNP1( Token.T_ARG, node );
			}
		}
	}
	// func_call_expr
	private ExprNode exprFuncCallExpr( ExprNode node ) throws VariantException, CompileException, TJSException {
		boolean newExpression = false;
		if( node  == null ) {
			node = exprPriorityExpr();
			newExpression = true;
		}
		if( node != null && newExpression == false ) {
			int token = lex();
			if( token != Token.T_LPARENTHESIS ) {
				error( Error.NotFoundFuncCallLPARENTHESISError );
				unlex();
			}
			ExprNode n2 = exprCallArgList();
			token = lex();
			if( token != Token.T_RPARENTHESIS ) {
				error( Error.NotFoundFuncCallRPARENTHESISError );
				unlex();
			}
			node = mInterCodeContext.makeNP2( Token.T_LPARENTHESIS, node, n2 );
		}
		return node;
	}
	// factor_expr
	private ExprNode exprFactorExpr() throws CompileException, VariantException, TJSException {
		int token = lex();
		ExprNode node = null;
		switch( token ) {
		case Token.T_CONSTVAL:
			node = mInterCodeContext.makeNP0(Token.T_CONSTVAL);
			node.setValue( mLexicalAnalyzer.getValue(mValue) );
			return node;
		case Token.T_SYMBOL:
			node = mInterCodeContext.makeNP0(Token.T_SYMBOL );
			node.setValue( new Variant(mLexicalAnalyzer.getString(mValue)) );
			return node;
		case Token.T_THIS:
			return mInterCodeContext.makeNP0( Token.T_THIS );
		case Token.T_SUPER:
			return mInterCodeContext.makeNP0( Token.T_SUPER );
		case Token.T_FUNCTION:
			unlex();
			return exprFuncExprDef();
		case Token.T_GLOBAL:
			return mInterCodeContext.makeNP0( Token.T_GLOBAL );
		case Token.T_VOID:
			return mInterCodeContext.makeNP0( Token.T_VOID );
		case Token.T_LBRACKET: // [
			unlex();
			return exprInlineArray();
		case Token.T_PERCENT: // %
			unlex();
			return exprInlineDic();
		case Token.T_CAST_CONST: // (const)
		case Token.T_LPARENTHESIS: // (
			unlex();
			return exprConstInlineArrayOrDic();
		case Token.T_SLASHEQUAL:	// /=
			mLexicalAnalyzer.setStartOfRegExp();
			token = lex();
			if( token == Token.T_REGEXP ) {
				node = mInterCodeContext.makeNP0( Token.T_REGEXP );
				node.setValue( mLexicalAnalyzer.getValue(mValue) );
				return node;
			} else {
				// 正規表現がない
				error( Error.NotFoundRegexError );
				unlex();
			}
		case Token.T_SLASH:	// /
			mLexicalAnalyzer.setStartOfRegExp();
			token = lex();
			if( token == Token.T_REGEXP ) {
				node = mInterCodeContext.makeNP0( Token.T_REGEXP );
				node.setValue( mLexicalAnalyzer.getValue(mValue) );
				return node;
			} else {
				// 正規表現がない
				error( Error.NotFoundRegexError );
				unlex();
			}
		}
		unlex();
		return null;
	}
	// priority_expr'
	private ExprNode exprPriorityExpr1() throws CompileException, VariantException, TJSException {
		ExprNode node = exprFactorExpr();
		if( node == null ) {
			int token = lex();
			if( token == Token.T_CAST_EXPR ) { // (expr)
				node = mNode;
				mNode = null;
				return node;
			} else if( token == Token.T_DOT ) {
				mLexicalAnalyzer.setNextIsBareWord();
				token = lex();
				if( token == Token.T_SYMBOL ) {
					ExprNode n2 = mInterCodeContext.makeNP0(Token.T_CONSTVAL);
					n2.setValue( mLexicalAnalyzer.getValue(mValue) );
					return mInterCodeContext.makeNP1( Token.T_WITHDOT, n2 );
				} else {
					error( Error.NotFoundSymbolAfterDotError );
					unlex();
				}
			} else {
				unlex();
			}
		}
		return node;
	}
	// priority_expr
	private ExprNode exprPriorityExpr() throws CompileException, VariantException, TJSException {
		ExprNode node = exprPriorityExpr1();
		//if( node != null ) {
		if( node != null ) {
			int token = lex();
			while( token == Token.T_LBRACKET || token == Token.T_DOT || token == Token.T_INCREMENT || token == Token.T_DECREMENT ||
					token == Token.T_EXCRAMATION || token == Token.T_LPARENTHESIS ) {
				switch(token) {
				case Token.T_LBRACKET: { // [
					ExprNode n2 = expr();
					token = lex();
					if( token == Token.T_RBRACKET ) { // ]
						node = mInterCodeContext.makeNP2( Token.T_LBRACKET, node, n2 );
					} else {
						// ] がない
						error( Error.NotFoundDicOrArrayRBRACKETError );
						unlex();
					}
					break;
				}
				case Token.T_DOT: // .
					mLexicalAnalyzer.setNextIsBareWord();
					token = lex();
					if( token == Token.T_SYMBOL ) {
						ExprNode n2 = mInterCodeContext.makeNP0( Token.T_CONSTVAL );
						n2.setValue( mLexicalAnalyzer.getValue(mValue) );
						node = mInterCodeContext.makeNP2( Token.T_DOT, node, n2 );
					} else {
						error( Error.NotFoundSymbolAfterDotError );
						unlex();
					}
					break;
				case Token.T_INCREMENT: // ++
					node = mInterCodeContext.makeNP1( Token.T_POSTINCREMENT, node );
					break;
				case Token.T_DECREMENT:
					node = mInterCodeContext.makeNP1( Token.T_POSTDECREMENT, node );
					break;
				case Token.T_EXCRAMATION: // !
					node = mInterCodeContext.makeNP1( Token.T_EVAL, node );
					break;
				case Token.T_LPARENTHESIS: // (
					unlex();
					node = exprFuncCallExpr( node );
					break;
				}
				token = lex();
			}
			unlex();
			/*
			token = lex();
			if( token == Token.T_DOT ) {
				ExprNode tmp = exprPriorityExpr();
				if( tmp != null ) node = tmp;
			} else if( token == Token.T_LPARENTHESIS ) {
				unlex();
				node = exprFuncCallExpr( node );
			} else {
				unlex();
			}
			*/
		}
		return node;
	}
	// incontextof_expr
	private ExprNode exprIncontextOfExpr() throws CompileException, VariantException, TJSException {
		ExprNode node = exprPriorityExpr();
		int token = lex();
		if( token == Token.T_INCONTEXTOF ) {
			ExprNode n2 = exprIncontextOfExpr();
			return mInterCodeContext.makeNP2( Token.T_INCONTEXTOF, node, n2 );
		} else {
			unlex();
			return node;
		}
	}
	// unary_expr
	private ExprNode exprUnaryExpr() throws VariantException, CompileException, TJSException {
		int token = lex();
		if( token == Token.T_LPARENTHESIS ) { // ( の時、先読みしてトークンを切り替える
			token = lex();
			switch( token ) {
			case Token.T_INT:
				token = lex();
				if( token != Token.T_RPARENTHESIS ) {
					unlex();
					ExprNode n1 = exprUnaryExpr();
					ExprNode retnode = mInterCodeContext.makeNP1( Token.T_INT, n1 );
					token = lex();
					if( token != Token.T_RPARENTHESIS ) {
						error( Error.NotFoundRPARENTHESISError );
						unlex(); // syntax error
					}
					return retnode;
				} else {
					unlex( Token.T_CAST_INT, 0 );
				}
				break;
			case Token.T_REAL:
				token = lex();
				if( token != Token.T_RPARENTHESIS ) {
					unlex();
					ExprNode n1 = exprUnaryExpr();
					ExprNode retnode = mInterCodeContext.makeNP1( Token.T_REAL, n1 );
					token = lex();
					if( token != Token.T_RPARENTHESIS ) {
						error( Error.NotFoundRPARENTHESISError );
						unlex(); // syntax error
					}
					return retnode;
				} else {
					unlex( Token.T_CAST_REAL, 0 );
				}
				break;
			case Token.T_STRING:
				token = lex();
				if( token != Token.T_RPARENTHESIS ) {
					unlex();
					ExprNode n1 = exprUnaryExpr();
					ExprNode retnode = mInterCodeContext.makeNP1( Token.T_STRING, n1 );
					token = lex();
					if( token != Token.T_RPARENTHESIS ) {
						error( Error.NotFoundRPARENTHESISError );
						unlex(); // syntax error
					}
					return retnode;
				} else {
					unlex( Token.T_CAST_STRING, 0 );
				}
				break;
			case Token.T_CONST:
				token = lex();
				if( token != Token.T_RPARENTHESIS ) {
					error( Error.NotFoundRPARENTHESISError );
					unlex(); // syntax error
				}
				unlex( Token.T_CAST_CONST, 0 );
				break;
			default:
				unlex();
				mNode = expr();
				token = lex();
				if( token != Token.T_RPARENTHESIS ) {
					error( Error.NotFoundRPARENTHESISError );
					unlex(); // syntax error
				}
				unlex( Token.T_CAST_EXPR, 0 );
				break;
			}
		} else {
			unlex();
		}
		ExprNode node = exprIncontextOfExpr();
		if( node == null ) {
			token = lex();
			switch( token ) {
			case Token.T_EXCRAMATION: // !
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_EXCRAMATION, node );
			case Token.T_TILDE: // ~
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_TILDE, node );
			case Token.T_DECREMENT: // --
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_DECREMENT, node );
			case Token.T_INCREMENT: // ++
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_INCREMENT, node );
			case Token.T_NEW:
				node = exprFuncCallExpr(null);
				if( node != null ) node.setOpecode( Token.T_NEW );
				return node;
			case Token.T_INVALIDATE:
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_INVALIDATE, node );
			case Token.T_ISVALID:
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_ISVALID, node );
			case Token.T_DELETE:
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_DELETE, node );
			case Token.T_TYPEOF:
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_TYPEOF, node );
			case Token.T_SHARP: // #
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_SHARP, node );
			case Token.T_DOLLAR: // $
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_DOLLAR, node );
			case Token.T_PLUS: // +
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_UPLUS, node );
			case Token.T_MINUS: // -
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_UMINUS, node );
			case Token.T_AMPERSAND: // &
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_IGNOREPROP, node );
			case Token.T_ASTERISK: // *
				node = exprUnaryExpr();
				if( node == null ) {
					unlex( Token.T_ASTERISK_RPARENTHESIS, 0 );
					return null;
				} else {
					return mInterCodeContext.makeNP1( Token.T_PROPACCESS, node );
				}
			case Token.T_CAST_INT: // (int)
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_INT, node );
			case Token.T_CAST_REAL: // (real)
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_REAL, node );
			case Token.T_CAST_STRING: // (string)
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_STRING, node );
			case Token.T_INT:
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_INT, node );
			case Token.T_REAL:
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_REAL, node );
			case Token.T_STRING:
				node = exprUnaryExpr();
				return mInterCodeContext.makeNP1( Token.T_STRING, node );
			default:
				unlex();
				break;
			}
		} else {
			token = lex();
			switch( token ) {
			case Token.T_ISVALID:
				return mInterCodeContext.makeNP1( Token.T_ISVALID, node );
			case Token.T_INSTANCEOF: {
				ExprNode n2 = exprUnaryExpr();
				return mInterCodeContext.makeNP2( Token.T_INSTANCEOF, node, n2 );
			}
			default:
				unlex();
				break;
			}
		}
		return node;
	}
	// mul_div_expr, mul_div_expr_and_asterisk
	private ExprNode exprMulDivExpr() throws VariantException, CompileException, TJSException {
		ExprNode node = exprUnaryExpr();
		if( node != null ) {
			int token = lex();
			while( token == Token.T_PERCENT || token == Token.T_SLASH || token == Token.T_BACKSLASH || token == Token.T_ASTERISK ) {
				ExprNode n2 = exprUnaryExpr();
				if( n2 == null ) {
					token = lex();
					if( token == Token.T_RPARENTHESIS ) {
						unlex( Token.T_ASTERISK_RPARENTHESIS, 0 );
						return node;
					} else if( token == Token.T_COMMA ) {
						unlex( Token.T_ASTERISK_COMMA, 0 );
						return node;
					} else {
						error( Error.NotFoundAsteriskAfterError );
					}
					break;
				}
				node = mInterCodeContext.makeNP2( token, node, n2 );
				token = lex();
			}
			unlex();
		}
		return node;
	}
	// add_sub_expr
	private ExprNode exprAddSubExpr() throws VariantException, CompileException, TJSException {
		ExprNode node = exprMulDivExpr();
		if( node != null ) {
			int token = lex();
			while( token == Token.T_PLUS || token == Token.T_MINUS ) {
				ExprNode n2 = exprMulDivExpr();
				node = mInterCodeContext.makeNP2( token, node, n2 );
				token = lex();
			}
			unlex();
		}
		return node;
	}
	// shift_expr
	private ExprNode exprShiftExpr() throws VariantException, CompileException, TJSException {
		ExprNode node = exprAddSubExpr();
		if( node != null ) {
			int token = lex();
			ExprNode n2;
			while( token == Token.T_RARITHSHIFT || token == Token.T_LARITHSHIFT || token == Token.T_RBITSHIFT ) {
				n2 = exprAddSubExpr();
				node = mInterCodeContext.makeNP2( token, node, n2 );
				token = lex();
			}
			unlex();
		}
		return node;
	}
	// compare_expr
	private ExprNode exprCompareExpr() throws VariantException, CompileException, TJSException {
		ExprNode node = exprShiftExpr();
		if( node != null ) {
			int token = lex();
			while( token == Token.T_LT || token == Token.T_GT || token == Token.T_LTOREQUAL || token == Token.T_GTOREQUAL ) {
				ExprNode n2 = exprShiftExpr();
				node = mInterCodeContext.makeNP2( token, node, n2 );
				token = lex();
			}
			unlex();
		}
		return node;
	}
	// identical_expr
	private ExprNode exprIdenticalExpr() throws VariantException, CompileException, TJSException {
		ExprNode node = exprCompareExpr();
		if( node != null ) {
			int token = lex();
			while( token == Token.T_NOTEQUAL || token == Token.T_EQUALEQUAL || token == Token.T_DISCNOTEQUAL | token == Token.T_DISCEQUAL ) {
				ExprNode n2 = exprCompareExpr();
				node = mInterCodeContext.makeNP2( token, node, n2 );
				token = lex();
			}
			unlex();
		}
		return node;
	}
	// and_expr
	private ExprNode exprAndExpr() throws VariantException, CompileException, TJSException {
		ExprNode node = exprIdenticalExpr();
		if( node != null ) {
			int token = lex();
			ExprNode n2;
			while( token == Token.T_AMPERSAND ) { // &
				n2 = exprIdenticalExpr();
				node = mInterCodeContext.makeNP2( Token.T_AMPERSAND, node, n2 );
				token = lex();
			}
			unlex();
		}
		return node;
	}
	// exclusive_or_expr
	private ExprNode exprExclusiveOrExpr() throws VariantException, CompileException, TJSException {
		ExprNode node = exprAndExpr();
		if( node != null ) {
			int token = lex();
			ExprNode n2;
			while( token == Token.T_CHEVRON ) { // ^
				n2 = exprAndExpr();
				node = mInterCodeContext.makeNP2( Token.T_CHEVRON, node, n2 );
				token = lex();
			}
			unlex();
		}
		return node;
	}
	// inclusive_or_expr
	private ExprNode exprInclusiveOrExpr() throws VariantException, CompileException, TJSException {
		ExprNode node = exprExclusiveOrExpr();
		if( node != null ) {
			int token = lex();
			ExprNode n2;
			while( token == Token.T_VERTLINE ) { // |
				n2 = exprExclusiveOrExpr();
				node = mInterCodeContext.makeNP2( Token.T_VERTLINE, node, n2 );
				token = lex();
			}
			unlex();
		}
		return node;
	}
	// logical_and_expr
	private ExprNode exprLogicalAndExpr() throws VariantException, CompileException, TJSException {
		ExprNode node = exprInclusiveOrExpr();
		if( node != null ) {
			int token = lex();
			ExprNode n2;
			while( token == Token.T_LOGICALAND ) { // &&
				n2 = exprInclusiveOrExpr();
				node = mInterCodeContext.makeNP2( Token.T_LOGICALAND, node, n2 );
				token = lex();
			}
			unlex();
		}
		return node;
	}
	// logical_or_expr
	private ExprNode exprLogicalOrExpr() throws VariantException, CompileException, TJSException {
		ExprNode node = exprLogicalAndExpr();
		if( node != null ) {
			int token = lex();
			ExprNode n2;
			while( token == Token.T_LOGICALOR ) { // ||
				n2 = exprLogicalAndExpr();
				node = mInterCodeContext.makeNP2( Token.T_LOGICALOR, node, n2 );
				token = lex();
			}
			unlex();
		}
		return node;
	}
	// cond_expr
	private ExprNode exprCondExpr() throws VariantException, CompileException, TJSException {
		ExprNode node = exprLogicalOrExpr();
		if( node != null ) {
			int token = lex();
			while( token == Token.T_QUESTION ) { // ?
				ExprNode n2 = exprCondExpr();
				token = lex();
				if( token != Token.T_COLON ) {
					error( Error.NotFound3ColonError );
					unlex();
				}
				ExprNode n3 = exprCondExpr();
				node = mInterCodeContext.makeNP3( Token.T_QUESTION, node, n2, n3 );
				token = lex();
			}
			unlex();
		}
		return node;
	}
	// assign_expr
	private ExprNode exprAssignExpr() throws VariantException, CompileException, TJSException {
		ExprNode node = exprCondExpr();
		if( node != null ) {
			int token = lex();
			while( token == Token.T_SWAP || token == Token.T_EQUAL || token == Token.T_AMPERSANDEQUAL
				|| token == Token.T_VERTLINEEQUAL || token == Token.T_CHEVRONEQUAL || token == Token.T_MINUSEQUAL
				|| token == Token.T_PLUSEQUAL || token == Token.T_PERCENTEQUAL || token == Token.T_SLASHEQUAL
				|| token == Token.T_BACKSLASHEQUAL || token == Token.T_ASTERISKEQUAL || token == Token.T_LOGICALOREQUAL
				|| token == Token.T_LOGICALANDEQUAL || token == Token.T_RARITHSHIFTEQUAL || token == Token.T_LARITHSHIFTEQUAL
				|| token == Token.T_RBITSHIFTEQUAL ) {
				ExprNode n2 = exprAssignExpr();
				node = mInterCodeContext.makeNP2( token, node, n2 );
				token = lex();
			}
			unlex();
		}
		return node;
	}
	//  comma_expr
	private ExprNode exprCommaExpr() throws VariantException, CompileException, TJSException {
		ExprNode node = exprAssignExpr();
		if( node != null ) {
			int token = lex();
			while( token == Token.T_COMMA ) {
				ExprNode n2 = exprAssignExpr();
				node = mInterCodeContext.makeNP2( token, node, n2 );
				token = lex();
			}
			unlex();
		}
		return node;
	}
	// expr
	private ExprNode expr() throws VariantException, CompileException, TJSException {
		ExprNode node = exprCommaExpr();
		if( node != null ) {
			int token = lex();
			while( token == Token.T_IF ) {
				ExprNode n2 = expr();
				node = mInterCodeContext.makeNP2( token, node, n2 );
				token = lex();
			}
			unlex();
		}
		return node;
/*
		int token = lex();
		if( token == Token.T_IF ) {
			ExprNode n2 = expr();
			return mInterCodeContext.makeNP2( Token.T_IF, node, n2 );
		} else {
			unlex();
			return node;
		}
*/
	}
	// expr_no_comma
	private ExprNode exprExprNoComma() throws VariantException, CompileException, TJSException {
		return exprAssignExpr();
	}
	// throw
	private ExprNode exprThrow() throws VariantException, CompileException, TJSException {
		if( LOGD ) Logger.log("throw");
		// throw は消化済み
		ExprNode node = expr();
		int token = lex();
		if( token == Token.T_SEMICOLON ) {
			mInterCodeContext.processThrowCode( node );
		} else {
			error( Error.NotFoundSemicolonAfterThrowError );
			unlex();
		}
		return null;
	}
	// catch
	private ExprNode exprCatch() throws CompileException, VariantException {
		if( LOGD ) Logger.log("catch");
		int token = lex();
		if( token == Token.T_CATCH ) {
			token = lex();
			if( token == Token.T_LPARENTHESIS ) {	// (
				token = lex();
				if( token == Token.T_RPARENTHESIS ) {	// )
					mInterCodeContext.enterCatchCode(null);
				} else if( token == Token.T_SYMBOL ) {
					int value = mValue;
					token = lex();
					if( token != Token.T_RPARENTHESIS ) {	// )
						error( Error.NotFoundRPARENTHESISAfterCatchError );
						unlex();
					}
					mInterCodeContext.enterCatchCode(mLexicalAnalyzer.getString(value));
				} else {
					error( Error.NotFoundRPARENTHESISAfterCatchError );
					unlex();
				}
			} else {
				unlex();
				mInterCodeContext.enterCatchCode(null);
			}
		} else {
			error( Error.NotFoundCatchError );
			unlex();
		}
		return null;
	}
	// try
	private ExprNode exprTry() throws CompileException, VariantException, TJSException {
		if( LOGD ) Logger.log("try");
		// try は消化済み
		mInterCodeContext.enterTryCode();
		exprBlockOrStatment();
		exprCatch();
		exprBlockOrStatment();
		mInterCodeContext.exitTryCode();
		return null;
	}
	// case
	private ExprNode exprCase() throws VariantException, CompileException, TJSException {
		if( LOGD ) Logger.log("case");
		int token = lex();
		if( token == Token.T_CASE ) {
			ExprNode node = expr();
			token = lex();
			if( token != Token.T_COLON ) {
				error( Error.NotFoundCaseColonError );
				unlex();
			}
			mInterCodeContext.processCaseCode(node);
		} else if( token == Token.T_DEFAULT ) {
			token = lex();
			if( token != Token.T_COLON ) {
				error( Error.NotFoundDefaultColonError );
				unlex();
			}
			mInterCodeContext.processCaseCode(null);
		} else {
			error( Error.NotFoundCaseOrDefaultError );
			unlex();	// ここに来ることはないはず
		}
		return null;
	}
	// with
	private ExprNode exprWith() throws VariantException, CompileException, TJSException {
		if( LOGD ) Logger.log("with");
		// with は消化済み
		int token = lex();
		if( token != Token.T_LPARENTHESIS ) {	// (
			error( Error.NotFoundWithLPARENTHESISError );
			unlex();
		}
		ExprNode node = expr();
		token = lex();
		if( token != Token.T_RPARENTHESIS ) {	// )
			error( Error.NotFoundWithRPARENTHESISError );
			unlex();
		}
		mInterCodeContext.enterWithCode(node);
		exprBlockOrStatment();
		mInterCodeContext.exitWidthCode();
		return null;
	}
	// switch
	private ExprNode exprSwitch() throws VariantException, CompileException, TJSException {
		if( LOGD ) Logger.log("switch");
		// switch は消化済み
		int token = lex();
		if( token != Token.T_LPARENTHESIS ) {	// (
			error( Error.NotFoundSwitchLPARENTHESISError );
			unlex();
		}
		ExprNode node = expr();
		token = lex();
		if( token != Token.T_RPARENTHESIS ) {	// )
			error( Error.NotFoundSwitchRPARENTHESISError );
			unlex();
		}
		mInterCodeContext.enterSwitchCode(node);
		exprBlock();
		mInterCodeContext.exitSwitchCode();
		return null;
	}
	// a return statement.
	private ExprNode exprReturn() throws VariantException, CompileException, TJSException {
		if( LOGD ) Logger.log("return");
		// return は消化済み
		int token = lex();
		if( token == Token.T_SEMICOLON ) {
			mInterCodeContext.returnFromFunc(null);
		} else {
			unlex();
			ExprNode node = expr();
			token = lex();
			if( token != Token.T_SEMICOLON ) {
				error( Error.NotFoundSemicolonAfterReturnError );
				unlex();
			}
			mInterCodeContext.returnFromFunc(node);
		}
		return null;
	}
	// extends_list, extends_name
	private ExprNode exprExtendsList() throws VariantException, CompileException, TJSException {
		if( LOGD ) Logger.log("extends");
		ExprNode node = exprExprNoComma();
		mInterCodeContext.createExtendsExprCode( node, false );
		int token = lex();
		if( token == Token.T_COMMA ) {
			exprExtendsList();
		} else {
			unlex();
		}
		return null;
	}
	// class_extender
	private ExprNode exprClassExtender() throws VariantException, CompileException, TJSException {
		ExprNode node = exprExprNoComma();
		int token = lex();
		if( token == Token.T_COMMA ) {
			mInterCodeContext.createExtendsExprCode(node,false);
			exprExtendsList();
		} else {
			mInterCodeContext.createExtendsExprCode(node,true);
			unlex();
		}
		return null;
	}
	// class_def
	private ExprNode exprClassDef() throws TJSException, CompileException, VariantException {
		int token = lex();
		if( token == Token.T_CLASS ) {
			token = lex();
			if( token != Token.T_SYMBOL ) {
				error( Error.NotFoundSymbolAfterClassError );
				unlex();
			}
			pushContextStack( mLexicalAnalyzer.getString(mValue), ContextType.CLASS );
			if( LOGD ) Logger.log(TAG, "Class:"+mLexicalAnalyzer.getString(mValue));
			token = lex();
			if( token == Token.T_EXTENDS ) {
				exprClassExtender();
			} else {
				unlex();
			}
			exprBlock();
			popContextStack();
		} else {
			unlex();
		}
		return null;
	}
	// property_handler_getter
	private ExprNode exprPropertyGetter() throws CompileException, TJSException, VariantException {
		int token = lex();
		if( token == Token.T_LPARENTHESIS ) {	// (
			token = lex();
			if( token != Token.T_RPARENTHESIS ) {	// )
				error( Error.NotFoundPropGetRPARENTHESISError );
				unlex();
			}
		} else {
			unlex();
		}
		pushContextStack( "getter", ContextType.PROPERTY_GETTER );
		mInterCodeContext.enterBlock();
		exprBlock();
		mInterCodeContext.exitBlock();
		popContextStack();
		return null;
	}
	// property_handler_setter
	private ExprNode exprPropertySetter() throws CompileException, TJSException, VariantException {
		int token = lex();
		if( token != Token.T_LPARENTHESIS ) {	// (
			error( Error.NotFoundPropSetLPARENTHESISError );
			unlex();
		}
		token = lex();
		if( token != Token.T_SYMBOL ) {
			error( Error.NotFoundPropSetSymbolError );
			unlex();
		}
		int value = mValue;

		token = lex();
		if( token != Token.T_RPARENTHESIS ) {	// )
			error( Error.NotFoundPropSetRPARENTHESISError );
			unlex();
		}
		pushContextStack( "setter", ContextType.PROPERTY_SETTER );
		mInterCodeContext.enterBlock();
		mInterCodeContext.setPropertyDeclArg( mLexicalAnalyzer.getString(value) );
		exprBlock();
		mInterCodeContext.exitBlock();
		popContextStack();
		return null;
	}

	// property_handler_def_list
	private ExprNode exprPropertyHandlerDefList() throws CompileException, TJSException, VariantException {
		int token = lex();
		if( token == Token.T_SETTER ) {
			exprPropertySetter();
			token = lex();
			if( token == Token.T_GETTER ) {
				exprPropertyGetter();
			} else {
				unlex();
			}
		} else if( token == Token.T_GETTER ) {
			exprPropertyGetter();
			token = lex();
			if( token == Token.T_SETTER ) {
				exprPropertySetter();
			} else {
				unlex();
			}
		} else {
			error( Error.NotFoundPropError );
			unlex();
		}
		return null;
	}

	// property_def
	private ExprNode exprPropertyDef() throws CompileException, TJSException, VariantException {
		int token = lex();
		if( token == Token.T_PROPERTY ) {
			token = lex();
			if( token != Token.T_SYMBOL ) {
				error( Error.NotFoundSymbolAfterPropError );
				unlex();
			}
			int value = mValue;
			token = lex();
			if( token != Token.T_LBRACE ) {
				error( Error.NotFoundLBRACEAfterPropError );
				unlex();
			}
			pushContextStack( mLexicalAnalyzer.getString(value), ContextType.PROPERTY );
			if( LOGD ) Logger.log("Property: " + mLexicalAnalyzer.getString(value) );
			exprPropertyHandlerDefList();
			token = lex();
			if( token != Token.T_RBRACE) {
				error( Error.NotFoundRBRACEAfterPropError );
				unlex();
			}
			popContextStack();
		} else {
			unlex();
		}
		return null;
	}

	// func_decl_arg_collapse, func_decl_arg, func_decl_arg_at_least_one, func_decl_arg_list
	// exprFuncDeclArgs にまとめてしまってる
	private ExprNode exprFuncDeclArg() throws VariantException, CompileException, TJSException {
		int token = lex();
		if( token == Token.T_SYMBOL ) {
			int value = mValue;
			token = lex();
			if( token == Token.T_EQUAL ) {
				ExprNode node = exprExprNoComma();
				mInterCodeContext.addFunctionDeclArg( mLexicalAnalyzer.getString(value), node );
			} else if( token == Token.T_ASTERISK ) {
				mInterCodeContext.addFunctionDeclArgCollapse( mLexicalAnalyzer.getString(value) );
			} else {
				unlex();
				mInterCodeContext.addFunctionDeclArg( mLexicalAnalyzer.getString(value), null );
			}
		} else {
			unlex();
		}
		return null;
	}
	// func_decl_arg_opt +
	private ExprNode exprFuncDeclArgs() throws VariantException, CompileException, TJSException {
		int token = lex();
		if( token == Token.T_SYMBOL ) {
			int value = mValue;
			token = lex();
			if( token == Token.T_EQUAL ) {	// symbol = ???
				ExprNode node = exprExprNoComma();
				mInterCodeContext.addFunctionDeclArg( mLexicalAnalyzer.getString(value), node );
				token = lex();
				if( token == Token.T_COMMA ) {
					exprFuncDeclArgs();
				} else {
					unlex();
				}
			} else if( token == Token.T_ASTERISK ) {	// symbol *
				mInterCodeContext.addFunctionDeclArgCollapse( mLexicalAnalyzer.getString(value) );
			} else {	// symbol
				mInterCodeContext.addFunctionDeclArg( mLexicalAnalyzer.getString(value), null );
				if( token == Token.T_COMMA ) {
					exprFuncDeclArgs();
				} else {
					unlex();
				}
			}
		} else if( token == Token.T_ASTERISK ) {
			mInterCodeContext.addFunctionDeclArgCollapse( null );
		} else {
			unlex();
		}
		return null;
	}
	// func_decl_arg_opt
	private ExprNode exprFuncDeclArgOpt() throws VariantException, CompileException, TJSException {
		int token = lex();
		if( token == Token.T_LPARENTHESIS ) {
			exprFuncDeclArgs();
			token = lex();
			if( token != Token.T_RPARENTHESIS ) {	// )
				error( Error.NotFoundFuncDeclRPARENTHESISError );
				unlex();
			}
		} else {	// empty
			unlex();
		}
		return null;
	}
	// func_def
	private ExprNode exprFunctionDef() throws CompileException, TJSException, VariantException {
		int token = lex();
		if( token == Token.T_FUNCTION ) {
			token = lex();
			if( token != Token.T_SYMBOL ) {
				error( Error.NotFoundFuncDeclSymbolError );
				unlex();
			}
			pushContextStack( mLexicalAnalyzer.getString(mValue), ContextType.FUNCTION );
			if( LOGD ) Logger.log(TAG, "Function:"+mLexicalAnalyzer.getString(mValue));
			mInterCodeContext.enterBlock();
			exprFuncDeclArgOpt();
			exprBlock();
			mInterCodeContext.exitBlock();
			popContextStack();
		} else {
			unlex(); // ここに来ることはないはず
			throw new TJSException( Error.InternalError );
		}
		return null;
	}
	// func_expr_def
	private ExprNode exprFuncExprDef() throws TJSException, VariantException, CompileException {
		ExprNode node = null;
		int token = lex();
		if( token == Token.T_FUNCTION ) {
			pushContextStack( "anonymous", ContextType.EXPR_FUNCTION );
			mInterCodeContext.enterBlock();
			exprFuncDeclArgOpt();
			exprBlock();
			mInterCodeContext.exitBlock();
			Variant v = new Variant(mInterCodeContext);
			popContextStack();
			node = mInterCodeContext.makeNP0( Token.T_CONSTVAL );
			node.setValue( v );
		} else {
			unlex();
			throw new TJSException( Error.InternalError );
		}
		return node;
	}
	// variable_id
	private ExprNode exprVariableId() throws VariantException, CompileException, TJSException {
		int token = lex();
		if( token == Token.T_SYMBOL ) {
			int value = mValue;
			token = lex();
			if( token == Token.T_EQUAL ) {
				ExprNode node = exprExprNoComma();
				mInterCodeContext.initLocalVariable( mLexicalAnalyzer.getString(value), node );
				if( LOGD ) Logger.log( "var name:"+mLexicalAnalyzer.getString(value) + "=xx");
			} else {
				unlex();
				mInterCodeContext.addLocalVariable( mLexicalAnalyzer.getString(value) );
				if( LOGD ) Logger.log( "var name:"+ mLexicalAnalyzer.getString(value) );
			}
		} else {
			error( Error.NotFoundSymbolAfterVarError );
			unlex();
		}
		return null;
	}
	// variable_id_list
	private ExprNode exprVariableIdList() throws VariantException, CompileException, TJSException {
		exprVariableId();
		int token = lex();
		if( token == Token.T_COMMA ) {
			exprVariableIdList();
		} else {
			unlex();
		}
		return null;
	}
	// variable_def_inner
	private ExprNode exprVariableDefInner() throws VariantException, CompileException, TJSException {	// 現在のバージョンではconstを明確に区別してない
		int token = lex();
		if( token == Token.T_VAR ) {
			if( LOGD ) Logger.log("var ");
			exprVariableIdList();
		} else if( token == Token.T_CONST ) {
			if( LOGD ) Logger.log("const ");
			exprVariableIdList();
		} else {
			unlex();
			throw new TJSException( Error.InternalError );
		}
		return null;
	}
	// variable_def
	private ExprNode exprVariableDef() throws VariantException, CompileException, TJSException {
		exprVariableDefInner();
		int token = lex();
		if( token != Token.T_SEMICOLON ) {
			error( Error.NotFoundVarSemicolonError );
			unlex();
		}
		return null;
	}
	// for_third_clause
	private ExprNode exprForThridClause() throws VariantException, CompileException, TJSException {
		int token = lex();
		if( token == Token.T_RPARENTHESIS ) {
			unlex();
			mInterCodeContext.setForThirdExprCode( null );
		} else {
			unlex();
			ExprNode node = expr();
			mInterCodeContext.setForThirdExprCode( node );
		}
		return null;
	}
	// for_second_clause
	private ExprNode exprForSecondClause() throws VariantException, CompileException, TJSException {
		int token = lex();
		if( token == Token.T_SEMICOLON ) {
			unlex();
			mInterCodeContext.createForExprCode(null);
		} else {
			unlex();
			ExprNode node = expr();
			mInterCodeContext.createForExprCode(node);
		}
		return null;
	}
	// for_first_clause
	private ExprNode exprForFirstClause() throws VariantException, CompileException, TJSException {
		int token = lex();
		if( token == Token.T_VAR || token == Token.T_CONST ) {
			unlex();
			mInterCodeContext.enterForCode( true );
			exprVariableDefInner();
		} else if( token == Token.T_SEMICOLON ) {
			unlex();
			mInterCodeContext.enterForCode( false );
		} else {
			unlex();
			ExprNode node = expr();
			mInterCodeContext.enterForCode( false );
			mInterCodeContext.createExprCode( node );
		}
		return null;
	}
	// for
	private ExprNode exprFor() throws VariantException, CompileException, TJSException {
		if( LOGD ) Logger.log("for");
		int token = lex();
		if( token != Token.T_LPARENTHESIS ) {	// (
			error( Error.NotFoundForLPARENTHESISError );
			unlex();
		}
		exprForFirstClause();
		token = lex();
		if( token != Token.T_SEMICOLON ) {
			error( Error.NotFoundForSemicolonError );
			unlex();
		}
		exprForSecondClause();
		token = lex();
		if( token != Token.T_SEMICOLON ) {
			error( Error.NotFoundForSemicolonError );
			unlex();
		}
		exprForThridClause();
		token = lex();
		if( token != Token.T_RPARENTHESIS ) {
			error( Error.NotFoundForRPARENTHESISError );
			unlex();
		}
		exprBlockOrStatment();
		mInterCodeContext.exitForCode();
		return null;
	}
	// if, if_else
	private ExprNode exprIf() throws VariantException, CompileException, TJSException {
		if( LOGD ) Logger.log("if");
		int token = lex();
		if( token != Token.T_LPARENTHESIS ) {	// (
			error( Error.NotFoundIfLPARENTHESISError );
			unlex();
		}
		mInterCodeContext.enterIfCode();
		ExprNode node = expr();
		mInterCodeContext.crateIfExprCode(node);
		token = lex();
		if( token != Token.T_RPARENTHESIS ) {	// )
			error( Error.NotFoundIfRPARENTHESISError );
			unlex();
		}
		exprBlockOrStatment();
		mInterCodeContext.exitIfCode();
		token = lex();
		if( token == Token.T_ELSE ) {
			mInterCodeContext.enterElseCode();
			exprBlockOrStatment();
			mInterCodeContext.exitElseCode();
		} else {
			unlex();
		}
		return null;
	}
	// do_while
	private ExprNode exprDo() throws CompileException, VariantException, TJSException {
		if( LOGD ) Logger.log("do-while");
		mInterCodeContext.enterWhileCode(true);
		exprBlockOrStatment();
		int token = lex();
		if( token != Token.T_WHILE ) {
			error( Error.NotFoundDoWhileError);
			unlex();
		}
		token = lex();
		if( token != Token.T_LPARENTHESIS ) {	// (
			error( Error.NotFoundDoWhileLPARENTHESISError );
			unlex();
		}
		ExprNode node = expr();
		token = lex();
		if( token != Token.T_RPARENTHESIS ) {	// )
			error( Error.NotFoundDoWhileRPARENTHESISError );
			unlex();
		}
		mInterCodeContext.createWhileExprCode(node,true);
		token = lex();
		if( token != Token.T_SEMICOLON ) {	// ;
			error( Error.NotFoundDoWhileSemicolonError );
			unlex();
		}
		mInterCodeContext.exitWhileCode(true);
		return null;
	}
	// while
	private ExprNode exprWhile() throws CompileException, VariantException, TJSException {
		if( LOGD ) Logger.log("while");
		mInterCodeContext.enterWhileCode(false);
		int token = lex();
		if( token != Token.T_LPARENTHESIS ) {	// (
			error( Error.NotFoundWhileLPARENTHESISError );
			unlex();
		}
		ExprNode node = expr();
		token = lex();
		if( token != Token.T_RPARENTHESIS ) {	// )
			error( Error.NotFoundWhileRPARENTHESISError );
			unlex();
		}
		mInterCodeContext.createWhileExprCode( node, false );
		exprBlockOrStatment();
		mInterCodeContext.exitWhileCode(false);
		return null;
	}
	// block
	private ExprNode exprBlock() throws VariantException, CompileException, TJSException {
		if( LOGD ) Logger.log("block{}");
		int token = lex();
		if( token != Token.T_LBRACE ) {
			error( Error.NotFoundLBRACEAfterBlockError );
			unlex(); // error
		}
		mInterCodeContext.enterBlock();
		exprDefList();
		mInterCodeContext.exitBlock();
		token = lex();
		if( token != Token.T_RBRACE ) {
			error( Error.NotFoundRBRACEAfterBlockError );
			unlex(); // error
		}
		return null;
	}
	// statement
	private ExprNode exprStatement() throws VariantException, CompileException, TJSException {
		int token = lex();
		ExprNode node = null;
		switch( token ) {
		case Token.T_IF:	// if or if else
			node = exprIf();
			break;
		case Token.T_WHILE:
			node = exprWhile();
			break;
		case Token.T_DO:
			node = exprDo();
			break;
		case Token.T_FOR:
			node = exprFor();
			break;
		case Token.T_BREAK:
			token = lex();
			if( token != Token.T_SEMICOLON ) {
				error( Error.NotFoundBreakSemicolonError );
				unlex();
			}
			mInterCodeContext.doBreak();
			break;
		case Token.T_CONTINUE:
			token = lex();
			if( token != Token.T_SEMICOLON ) {
				error( Error.NotFoundContinueSemicolonError );
				unlex();
			}
			mInterCodeContext.doContinue();
			break;
		case Token.T_DEBUGGER:
			token = lex();
			if( token != Token.T_SEMICOLON ) {
				error( Error.NotFoundBebuggerSemicolonError );
				unlex();
			}
			mInterCodeContext.doDebugger();
			break;
		case Token.T_VAR:
		case Token.T_CONST:
			unlex();
			node = exprVariableDef();
			break;
		case Token.T_FUNCTION:
			unlex();
			node = exprFunctionDef();
			break;
		case Token.T_PROPERTY:
			unlex();
			node = exprPropertyDef();
			break;
		case Token.T_CLASS:
			unlex();
			node = exprClassDef();
			break;
		case Token.T_RETURN:
			node = exprReturn();
			break;
		case Token.T_SWITCH:
			node = exprSwitch();
			break;
		case Token.T_WITH:
			node = exprWith();
			break;
		case Token.T_CASE:
		case Token.T_DEFAULT:
			unlex();
			node = exprCase();
			break;
		case Token.T_TRY:
			node = exprTry();
			break;
		case Token.T_THROW:
			node = exprThrow();
			break;
		case Token.T_SEMICOLON:
			// ignore
			break;
		default:
			unlex();
			node = expr();
			token = lex();
			if( token != Token.T_SEMICOLON ) {
				error( Error.NotFoundSemicolonOrTokenTypeError );
				unlex();
			}
			mInterCodeContext.createExprCode( node );
			break;
		}
		return node;
	}
	// block_or_statement
	private ExprNode exprBlockOrStatment() throws VariantException, CompileException, TJSException {
		int token = lex();
		if( token == Token.T_LBRACE ) {	// block expression
			mInterCodeContext.enterBlock();
			exprDefList();
			token = lex();
			if( token != Token.T_RBRACE ) {
				error( Error.NotFoundBlockRBRACEError );
				unlex();
			}
			mInterCodeContext.exitBlock();
		} else {
			unlex();
			exprStatement();
		}
		return null;
	}
	// def_list
	private ExprNode exprDefList() throws VariantException, CompileException, TJSException {
		int token = lex();
		while( token > 0 && token != Token.T_RBRACE ) {
			unlex();
			exprBlockOrStatment();
			token = lex();
		}
		unlex();
		return null;
	}
	// program, global_list
	private void program() throws VariantException, CompileException, TJSException {
		pushContextStack( "global", ContextType.TOP_LEVEL );
		int token;
		do {
			exprDefList();
			token = lex();
			if( token > 0 ) {
				error( Error.EndOfBlockError );
				unlex();
			}
		} while( token > 0 );
		popContextStack();
	}

	public TJS getTJS() {
		return mOwner;
	}

	public String getName() { return mName; }
	public void setName( String name, int lineofs ) {
		mName = null;
		if( name != null ) {
			mLineOffset = lineofs;
			mName = new String(name);
		}
	}
	public int getLineOffset() { return mLineOffset; }

	public void setText( Variant result, String text, Dispatch2 context, boolean isexpression ) throws VariantException, TJSException, CompileException {
		// compiles text and executes its global level scripts.
		// the script will be compiled as an expression if isexpressn is true.
		if( text == null ) return;
		if( text.length() == 0 ) return;

		mScript = text;
		// ラインリスト生成はここで行わない

		parse( text, isexpression, result != null );

		// 逆アセンブル
		if( D_IS_DISASSEMBLE ) {
			final int count = mInterCodeContextList.size();
			for( int i = 0; i < count; i++ ) {
				InterCodeContext v = mInterCodeContextList.get(i);
				TJS.outputToConsole( v.getName() );
				v.disassemble( this, 0, 0 );
			}
		}
		System.gc(); // TODO 本当にいるかどうか

		// execute global level script
		executeTopLevelScript(result, context);

		if( mInterCodeContextList.size() != 1 ) {
			// this is not a single-context script block
			// (may hook itself)
			// release all contexts and global at this time
			if( mTopLevelContext != null ) mTopLevelContext = null;
			while( mContextStack.size() > 0 ) {
				mContextStack.pop();
			}
		}
	}

	public void executeTopLevelScript(Variant result, Dispatch2 context) throws VariantException, TJSException {
		if( mTopLevelContext != null ) {
			mTopLevelContext.funcCall( 0, null, null, result, null, context );
		}
	}

	public String getLineDescriptionString(int pos) {
		// get short description, like "mainwindow.tjs(321)"
		// pos is in character count from the first of the script
		StringBuilder builer = new StringBuilder(512);
		int line = srcPosToLine(pos)+1;
		if( mName != null ) {
			builer.append( mName );
		} else {
			builer.append("anonymous@");
			builer.append( toString() );
		}
		builer.append('(');
		builer.append( String.valueOf(line) );
		builer.append(')');
		return builer.toString();
	}

	public int lineToSrcPos(int line) {
		// assumes line is added by LineOffset
		line -= mLineOffset;
		return mLexicalAnalyzer.lineToSrcPos(line);
	}

	public String getLine(int line ) {
		// note that this function DOES matter LineOffset
		line -= mLineOffset;
		return mLexicalAnalyzer.getLine(line);
	}

	public boolean isReusable() {
		return getContextCount() == 1 && mTopLevelContext != null && !mUsingPreProcessor;
	}

	public int getContextCount() {
		return mInterCodeContextList.size();
	}

	public void add( InterCodeContext ctx ) {
		mInterCodeContextList.add(ctx);
	}
	public void remove( InterCodeContext ctx ) {
		mInterCodeContextList.remove(ctx);
	}

	public String getNameInfo() {
		if( mLineOffset == 0 ) {
			return new String(mName);
		} else {
			return mName + "(line +" + String.valueOf(mLineOffset) + ")";
		}
	}

	public int getTotalVMCodeSize() {
		int size = 0;
		final int count = mInterCodeContextList.size();
		for( int i = 0; i < count; i++ ) {
			size += mInterCodeContextList.get(i).getCodeSize();
		}
		return size;
	}

	public int getTotalVMDataSize() {
		int size = 0;
		final int count = mInterCodeContextList.size();
		for( int i = 0; i < count; i++ ) {
			size += mInterCodeContextList.get(i).getDataSize();
		}
		return size;
	}

	static public void consoleOutput( final String msg, ScriptBlock blk  ) {
		TJS.outputToConsole(msg);
	}
	public void dump() throws VariantException {
		final int count = mInterCodeContextList.size();
		for( int i = 0; i < count; i++ ) {
			InterCodeContext v = mInterCodeContextList.get(i);
			consoleOutput( "", this );
			String ptr = String.format( " 0x%08X", v.hashCode() );
			consoleOutput( "(" + v.getContextTypeName() + ") " + v.getName() + ptr, this );
			v.disassemble( this, 0, 0 );
		}
	}

	public String getScript() {
		return mScript;
	}
	public final int getMaxLine() {
		return mLexicalAnalyzer.getMaxLine();
	}
}
