#include "AScript.h"
#include "Parser.h"

namespace AScript {

//-----------------------------------------------------------------------------
// Parser
//-----------------------------------------------------------------------------
Parser::Parser() : _stat(STAT_Start),
		_blockParamFlag(false), _quoteFlag(false), _shiftFlag(false),
		_cntLine(0), _fieldDepthLevel(0), _commentNestLevel(0),
		_newlineAsSeparatorFlag(true)
{
	InitStack();
}

void Parser::InitStack()
{
	_elemStack.Clear();
	_elemStack.push_back(Element(ETYPE_Begin));
}

Expr *Parser::ParseChar(Environment &env, Signal sig, int ch)
{
	bool continueFlag;
	Expr *pExpr = NULL;
	do {
		continueFlag = false;
		if (_stat == STAT_Start) {
			if (ch == _T('0')) {
				_token = ch;
				_stat = STAT_NumberPre;
			} else if (IsDigit(ch)) {
				_token = ch;
				_stat = STAT_Number;
			} else if (ch == _T('.')) {
				_token = ch;
				_stat = STAT_NumberAfterDot;
			} else if (IsWhite(ch)) {
				// nothing to do
			} else if (ch == _T('r') || ch == _T('R')) {
				// must be checked before IsSymbolFirstChar(ch)
				_token = ch;
				_stat = STAT_StringPre;
			} else if (IsSymbolFirstChar(ch)) {
				_token = ch;
				_stat = STAT_Symbol;
			} else if (ch == _T('"') || ch == _T('\'')) {
				_stringInfo.chBorder = ch;
				_stringInfo.escapeEnableFlag = true;
				_token.clear();
				_stat = STAT_StringFirst;
			} else if (ch == _T('\\') && !_shiftFlag) {
				_stat = STAT_Escape;
			} else if (ch == _T('\n')) {
				if (_newlineAsSeparatorFlag) {
					pExpr = FeedElement(env, sig, Element(ETYPE_EOL));
					if (sig.IsSignalled()) _stat = STAT_Error;
				}
			} else if (ch == _T('#')) {
				if (_newlineAsSeparatorFlag) {
					pExpr = FeedElement(env, sig, Element(ETYPE_EOL));
					_stat = sig.IsSignalled()? STAT_Error : STAT_CommentLine;
				} else {
					_stat = STAT_CommentLine;
				}
			} else if (ch == _T('{')) {
				pExpr = FeedElement(env, sig, Element(ETYPE_LBrace));
				_stat = sig.IsSignalled()? STAT_Error : STAT_AfterLBrace;
			} else if (ch == _T('|') && _blockParamFlag) {
				_blockParamFlag = false;
				pExpr = FeedElement(env, sig, Element(ETYPE_RBlockParam));
				if (sig.IsSignalled()) _stat = STAT_Error;
			} else if (ch == _T('`')) {
				_stat = STAT_Quote;
			} else if (ch == _T(':')) {
				_stat = STAT_Colon;
			//} else if (ch == _T('%') || ch == _T('&')) {
			//	if (_elemStack.back().IsStrongReducer()) {
			//		_token = ch;
			//		_stat = STAT_DoubleChars;
			//	} else {
			//		_token = ch;
			//		pExpr = FeedElement(env, sig, Element(ETYPE_Symbol, _token));
			//		_stat = sig.IsSignalled()? STAT_Error : STAT_Start;
			//	}
			} else {
				int i;
				static const struct {
					int ch;
					ElemType elemType;
				} tbl[] = {
					{ _T('?'),	ETYPE_Question,		},
					{ _T('+'),	ETYPE_DoubleChars,	},
					{ _T('-'),	ETYPE_DoubleChars,	},
					{ _T('*'),	ETYPE_DoubleChars,	},
					{ _T('/'),	ETYPE_DoubleChars,	},
					{ _T('%'),	ETYPE_DoubleChars,	},
					{ _T('='),	ETYPE_DoubleChars,	},
					{ _T('<'),	ETYPE_DoubleChars,	},
					{ _T('>'),	ETYPE_DoubleChars,	},
					{ _T('!'),	ETYPE_DoubleChars,	}, // see also STAT_Symbol
					{ _T('|'),	ETYPE_DoubleChars,	},
					{ _T('&'),	ETYPE_DoubleChars,	},
					{ _T('^'),	ETYPE_DoubleChars,	},
					{ _T('~'),	ETYPE_Invert,		},
					{ _T(','),	ETYPE_Comma,		},
					{ _T(';'),	ETYPE_Semicolon,	},
					{ _T('('),	ETYPE_LParenthesis,	},
					{ _T(')'),	ETYPE_RParenthesis,	},
					{ _T('}'),	ETYPE_RBrace,		},
					{ _T('['),	ETYPE_LBracket,		},
					{ _T(']'),	ETYPE_RBracket,		},
					{ _T('\0'),	ETYPE_EOF,			},
					{ -1,		ETYPE_EOF,			},
				};
				for (i = 0; i < NUMBEROF(tbl); i++) {
					if (tbl[i].ch == ch) break;
				}
				if (i >= NUMBEROF(tbl)) {
					SetError(sig, _T("unexpected character '%c' (%d)"), ch, ch);
					_stat = STAT_Error;
				} else if (tbl[i].elemType == ETYPE_DoubleChars) {
					_token = ch;
					_stat = STAT_DoubleChars;
				} else if (_quoteFlag) {
					_quoteFlag = false;
					_token = _T('`');
					_token.push_back(ch);
					pExpr = FeedElement(env, sig, Element(ETYPE_Symbol, _token));
					if (sig.IsSignalled()) _stat = STAT_Error;
				} else {
					pExpr = FeedElement(env, sig, Element(tbl[i].elemType));
					if (sig.IsSignalled()) _stat = STAT_Error;
				}
			}
		} else if (_stat == STAT_DoubleChars) {
			// this state comes from STAT_Start and STAT_Symbol
			static const struct {
				int chFirst;
				ElemType elemType;
				struct {
					int chSecond;
					ElemType elemType;
				} tblCand[5];
			} tbl[] = {
				{ _T('+'), ETYPE_Plus, {
							{ _T('='), ETYPE_AssignPlus		},
							{ _T('\0'), ETYPE_Unknown		}, } },
				{ _T('-'), ETYPE_Minus, {
							{ _T('='), ETYPE_AssignMinus	},
							{ _T('\0'), ETYPE_Unknown		}, } },
				{ _T('*'), ETYPE_Multiply, {
							{ _T('='), ETYPE_AssignMultiply	},
							{ _T('*'), ETYPE_TripleChars	},
							{ _T('\0'), ETYPE_Unknown		}, } },
				{ _T('/'), ETYPE_Divide, {
							{ _T('='), ETYPE_AssignDivide	},
							{ _T('\0'), ETYPE_Unknown		}, } },
				{ _T('%'), ETYPE_Modulo, {
							{ _T('='), ETYPE_AssignModulo	},
							{ _T('\0'), ETYPE_Unknown		}, } },
				{ _T('='), ETYPE_Assign, {
							{ _T('='), ETYPE_Equal 			},
							{ _T('>'), ETYPE_DictAssign		},
							{ _T('\0'), ETYPE_Unknown		}, } },
				{ _T('<'), ETYPE_Less, {
							{ _T('='), ETYPE_TripleChars	},
							{ _T('\0'), ETYPE_Unknown		}, } },
				{ _T('>'), ETYPE_Greater, {
							{ _T('='), ETYPE_GreaterEq		},
							{ _T('\0'), ETYPE_Unknown		}, } },
				{ _T('!'), ETYPE_Not, {
							{ _T('='), ETYPE_NotEqual		},
							{ _T('!'), ETYPE_Force			},
							{ _T('\0'), ETYPE_Unknown		}, } },
				{ _T('|'), ETYPE_Or, {
							{ _T('='), ETYPE_AssignBitOr },
							{ _T('|'), ETYPE_OrOr },
							{ _T('\0'), ETYPE_Unknown		}, } },
				{ _T('&'), ETYPE_And, {
							{ _T('='), ETYPE_AssignBitAnd },
							{ _T('&'), ETYPE_AndAnd },
							{ _T('\0'), ETYPE_Unknown		}, } },
				{ _T('^'), ETYPE_Xor, {
							{ _T('='), ETYPE_AssignBitXor	},
							{ _T('\0'), ETYPE_Unknown		}, } },
			};
			int chFirst = _token[0];
			if (chFirst == _T('/') && ch == _T('*')) {
				_commentNestLevel = 1;
				_stat = STAT_CommentBlock;
			} else if (chFirst == _T('/') && ch == _T('/')) {
				if (_newlineAsSeparatorFlag) {
					pExpr = FeedElement(env, sig, Element(ETYPE_EOL));
				}
				_stat = STAT_CommentLine;
			} else if (chFirst == _T('*') && ch == _T('/')) {
				SetError(sig, _T("unmatching comment description"));
				_stat = STAT_Error;
			} else {
				_stat = STAT_Start;
				continueFlag = true;
				for (int i = 0; i < NUMBEROF(tbl); i++) {
					if (tbl[i].chFirst != chFirst) continue;
					ElemType elemType = tbl[i].elemType;
					for (int j = 0; j < NUMBEROF(tbl[i].tblCand); j++) {
						if (tbl[i].tblCand[j].chSecond == _T('\0')) break;
						if (tbl[i].tblCand[j].chSecond != ch) continue;
						_token.push_back(ch);
						elemType = tbl[i].tblCand[j].elemType;
						continueFlag = false;
						break;
					}
					if (elemType == ETYPE_TripleChars) {
						_stat = STAT_TripleChars;
					} else if (_quoteFlag) {
						_quoteFlag = false;
						_token.insert(0, _T("`"));
						pExpr = FeedElement(env, sig, Element(ETYPE_Symbol, _token));
						if (sig.IsSignalled()) _stat = STAT_Error;
					} else {
						pExpr = FeedElement(env, sig, Element(elemType));
						if (sig.IsSignalled()) _stat = STAT_Error;
					}
					break;
				}
				// tables have a bug if i reaches at NUMBEROF(tbl)
			}
		} else if (_stat == STAT_TripleChars) {
			static const struct {
				const TCHAR *strFirst;
				ElemType elemType;
				struct {
					int chThird;
					ElemType elemType;
				} tblCand[5];
			} tbl[] = {
				{ _T("**"), ETYPE_Power, {
							{ _T('='), ETYPE_AssignPower	},
							{ _T('\0'), ETYPE_Unknown		}, } },
				{ _T("<="), ETYPE_LessEq, {
							{ _T('>'), ETYPE_Compare		},
							{ _T('\0'), ETYPE_Unknown		}, } },
			};
			_stat = STAT_Start;
			continueFlag = true;
			for (int i = 0; i < NUMBEROF(tbl); i++) {
				if (_token.compare(tbl[i].strFirst) != 0) continue;
				ElemType elemType = tbl[i].elemType;
				for (int j = 0; j < NUMBEROF(tbl[i].tblCand); j++) {
					if (tbl[i].tblCand[j].chThird == _T('\0')) break;
					if (tbl[i].tblCand[j].chThird != ch) continue;
					_token.push_back(ch);
					elemType = tbl[i].tblCand[j].elemType;
					continueFlag = false;
					break;
				}
				if (_quoteFlag) {
					_quoteFlag = false;
					_token.insert(0, _T("`"));
					pExpr = FeedElement(env, sig, Element(ETYPE_Symbol, _token));
					if (sig.IsSignalled()) _stat = STAT_Error;
				} else {
					pExpr = FeedElement(env, sig, Element(elemType));
					if (sig.IsSignalled()) _stat = STAT_Error;
				}
				break;
			}
			// tables have a bug if i reaches at NUMBEROF(tbl)
		} else if (_stat == STAT_Escape) {
			if (ch == _T('\0') || ch == -1) {
				continueFlag = true;
				_stat = STAT_Start;
			} else if (ch == _T('\n')) {
				_stat = STAT_Start;
			} else if (IsWhite(ch)) {
				// nothing to do
			} else {
				SetError(sig, _T("invalid escape character"));
				_stat = STAT_Error;
			}
		} else if (_stat == STAT_Quote) {
			// the following characters must be contained in the table in STAT_Start
			static const TCHAR chTbl[] = {
				_T('+'), _T('-'), _T('*'), _T('/'),
				_T('%'), _T('='), _T('<'), _T('>'),
				_T('!'), _T('|'), _T('&'), _T('^'),
				_T('~'),
			};
			int i = 0;
			for (i = 0; i < NUMBEROF(chTbl); i++) {
				if (chTbl[i] == ch) break;
			}
			if (i < NUMBEROF(chTbl)) {
				_quoteFlag = true;
				continueFlag = true;
				_stat = STAT_Start;
			} else {
				pExpr = FeedElement(env, sig, Element(ETYPE_Quote));
				continueFlag = true;
				_stat = sig.IsSignalled()? STAT_Error : STAT_Start;
			}
		} else if (_stat == STAT_Colon) {
			if (ch == _T(':')) {
				_fieldDepthLevel = 1;
				_stat = STAT_ColonColon;
			} else {
				pExpr = FeedElement(env, sig, Element(ETYPE_Colon));
				continueFlag = true;
				_stat = sig.IsSignalled()? STAT_Error : STAT_Start;
			}
		} else if (_stat == STAT_ColonColon) {
			if (ch == _T(':')) {
				_fieldDepthLevel++;
			} else {
				pExpr = FeedElement(env, sig, Element(ETYPE_ColonColon, _fieldDepthLevel));
				continueFlag = true;
				_stat = sig.IsSignalled()? STAT_Error : STAT_Start;
			}
		} else if (_stat == STAT_Error) {
			_elemStack.Clear();
			_elemStack.push_back(Element(ETYPE_Begin));
			_blockParamFlag = false;
			continueFlag = true;
			_stat = STAT_ErrorRecovery;
		} else if (_stat == STAT_ErrorRecovery) {
			if (ch == _T('\n') || ch == _T('\0') || ch == -1) {
				continueFlag = true;
				_stat = STAT_Start;
			} else {
				// nothing to do
			}
		} else if (_stat == STAT_AfterLBrace) {
			if (ch == _T('|')) {
				pExpr = FeedElement(env, sig, ETYPE_LBlockParam);
				if (sig.IsSignalled()) {
					_stat = STAT_Error;
				} else {
					_blockParamFlag = true;
					_stat = STAT_Start;
				}
			} else if (IsWhite(ch)) {
				// nothing to do
			} else {
				continueFlag = true;
				_stat = STAT_Start;
			}
		} else if (_stat == STAT_NumberPre) {
			if (ch == _T('x') || ch == _T('X')) {
				_token.push_back(ch);
				_stat = STAT_NumberHex;
			} else if(IsOctDigit(ch)) {
				_token.push_back(ch);
				_stat = STAT_NumberOct;
			} else {
				continueFlag = true;
				_stat = STAT_Number;
			}
		} else if (_stat == STAT_NumberHex) {
			if (IsHexDigit(ch)) {
				_token.push_back(ch);
			} else if (_token.size() > 2) {
				pExpr = FeedElement(env, sig, Element(ETYPE_Number, _token));
				continueFlag = true;
				_stat = sig.IsSignalled()? STAT_Error : STAT_Start;
			} else {
				SetError(sig, _T("wrong format of hexadecimal number"));
				continueFlag = true;
				_stat = STAT_Error;
			}
		} else if (_stat == STAT_NumberOct) {
			if (IsOctDigit(ch)) {
				_token.push_back(ch);
			} else {
				pExpr = FeedElement(env, sig, Element(ETYPE_Number, _token));
				continueFlag = true;
				_stat = sig.IsSignalled()? STAT_Error : STAT_Start;
			}
		} else if (_stat == STAT_NumberAfterDot) {
			if (ch == _T('.')) {
				pExpr = FeedElement(env, sig, Element(ETYPE_Sequence));
				_stat = sig.IsSignalled()? STAT_Error : STAT_Start;
			} else if (IsDigit(ch)) {
				_token.push_back(ch);
				_stat = STAT_Number;
			} else {
				pExpr = FeedElement(env, sig, Element(ETYPE_Dot));
				continueFlag = true;
				_stat = sig.IsSignalled()? STAT_Error : STAT_Start;
			}
		} else if (_stat == STAT_Number) {
			if (IsDigit(ch)) {
				_token.push_back(ch);
			} else if (ch == _T('.')) {
				size_t pos = _token.find(_T('.'));
				if (pos == _token.length() - 1) {
					_token.resize(pos);
					pExpr = FeedElement(env, sig, Element(ETYPE_Number, _token));
					if (!sig.IsSignalled()) {
						pExpr = FeedElement(env, sig, Element(ETYPE_Sequence));
					}
					_stat = sig.IsSignalled()? STAT_Error : STAT_Start;
				} else if (pos == String::npos) {
					_token.push_back(ch);
				} else {
					SetError(sig, _T("dot has already been scanned"));
					_stat = STAT_Error;
				}
			} else if (ch == _T('e') || ch == _T('E')) {
				_token.push_back(ch);
				_stat = STAT_NumberExpAfterE;
			} else if (ch == _T('j')) {
				_stat = STAT_ImagNumber;
			} else {
				pExpr = FeedElement(env, sig, Element(ETYPE_Number, _token));
				continueFlag = true;
				_stat = sig.IsSignalled()? STAT_Error : STAT_Start;
			}
		} else if (_stat == STAT_NumberExpAfterE) {
			if (IsDigit(ch)) {
				_token.push_back(ch);
				_stat = STAT_NumberExp;
			} else if (ch == _T('+') || ch == _T('-')) {
				_token.push_back(ch);
				_stat = STAT_NumberExpAfterSign;
			} else {
				SetError(sig, _T("wrong exponential expression"));
				_stat = STAT_Error;
			}
		} else if (_stat == STAT_NumberExpAfterSign) {
			if (IsDigit(ch)) {
				_token.push_back(ch);
				_stat = STAT_NumberExp;
			} else {
				SetError(sig, _T("wrong exponential expression"));
				_stat = STAT_Error;
			}
		} else if (_stat == STAT_NumberExp) {
			if (IsDigit(ch)) {
				_token.push_back(ch);
			} else if (ch == _T('j')) {
				_stat = STAT_ImagNumber;
			} else {
				pExpr = FeedElement(env, sig, Element(ETYPE_Number, _token));
				continueFlag = true;
				_stat = sig.IsSignalled()? STAT_Error : STAT_Start;
			}
		} else if (_stat == STAT_ImagNumber) {
			if (IsSymbolChar(ch)) {
				SetError(sig, _T("wrong format of number"));
				_stat = STAT_Error;
			} else {
				pExpr = FeedElement(env, sig, Element(ETYPE_ImagNumber, _token));
				continueFlag = true;
				_stat = STAT_Start;
			}
		} else if (_stat == STAT_Symbol) {
			if (IsSymbolChar(ch)) {
				_token.push_back(ch);
			} else if (IsSJISFirst(ch) && !_shiftFlag) {
				_token.push_back(ch);
			} else if (IsSJISSecond(ch) && _shiftFlag) {
				_token.push_back(ch);
			} else if (ch == _T('!')) {
				_stat = STAT_SymbolExclamation;
			} else {
				if (_token == _T("in")) {
					pExpr = FeedElement(env, sig, Element(ETYPE_ContainCheck));
				} else {
					pExpr = FeedElement(env, sig, Element(ETYPE_Symbol, _token));
				}
				continueFlag = true;
				_stat = sig.IsSignalled()? STAT_Error : STAT_Start;
			}
		} else if (_stat == STAT_SymbolExclamation) {
			if (ch == _T('=') || ch == _T('!')) {
				pExpr = FeedElement(env, sig, Element(ETYPE_Symbol, _token));
				if (sig.IsSignalled()) {
					_stat = STAT_Error;
				} else {
					_token = _T('!');
					_stat = STAT_DoubleChars;
				}
			} else {
				_token.push_back(_T('!'));
				continueFlag = true;
				_stat = STAT_Symbol;
			}
		} else if (_stat == STAT_CommentLine) {
			if (ch == _T('\n') || ch == _T('\0') || ch == -1) {
				_stat = STAT_Start;
			} else {
				// nothing to do
			}
		} else if (_stat == STAT_CommentBlock) {
			if (ch == _T('*')) {
				_stat = STAT_CommentBlockEnd;
			} else if (ch == _T('/')) {
				_stat = STAT_CommentBlockNest;
			} else if (ch == _T('"') || ch == _T('\'')) {
				_stringInfo.chBorder = ch;
				_stat = STAT_StringInCommentBlock;
			} else {
				// nothing to do
			}
		} else if (_stat == STAT_CommentBlockEnd) {
			if (ch == _T('/')) {
				_commentNestLevel--;
				if (_commentNestLevel > 0) {
					_stat = STAT_CommentBlock;
				} else {
					_stat = STAT_Start;
				}
			} else {
				continueFlag = true;
				_stat = STAT_CommentBlock;
			}
		} else if (_stat == STAT_CommentBlockNest) {
			if (ch == _T('*')) {
				_commentNestLevel++;
				_stat = STAT_CommentBlock;
			} else {
				continueFlag = true;
				_stat = STAT_CommentBlock;
			}
		} else if (_stat == STAT_StringPre) {
			if (ch == _T('"') || ch == _T('\'')) {
				_stringInfo.chBorder = ch;
				_stringInfo.escapeEnableFlag = false;
				_token.clear();
				_stat = STAT_StringFirst;
			} else {
				continueFlag = true;
				_stat = STAT_Symbol;
			}
		} else if (_stat == STAT_StringFirst) {
			if (ch == _stringInfo.chBorder) {
				_stat = STAT_StringSecond;
			} else {
				continueFlag = true;
				_stat = STAT_String;
			}
		} else if (_stat == STAT_StringSecond) {
			if (ch == _stringInfo.chBorder) {
				_stat = STAT_MString;
			} else {
				pExpr = FeedElement(env, sig, Element(ETYPE_String, _token));
				continueFlag = true;
				_stat = sig.IsSignalled()? STAT_Error : STAT_Start;
			}
		} else if (_stat == STAT_String) {
			if (ch == _stringInfo.chBorder) {
				pExpr = FeedElement(env, sig, Element(ETYPE_String, _token));
				_stat = sig.IsSignalled()? STAT_Error : STAT_Start;
			} else if (ch == _T('\\') && !_shiftFlag) {
				_stringInfo.statRtn = STAT_String;
				_stat = STAT_StringEsc;
			} else if (ch == _T('\0') || ch == -1 || ch == _T('\n')) {
				SetError(sig, _T("string is not terminated correctly"));
				_stat = STAT_Error;
			} else {
				_token.push_back(ch);
			}
		} else if (_stat == STAT_MString) {
			if (ch == _stringInfo.chBorder) {
				_stat = STAT_MStringFirst;
			} else if (ch == _T('\\') && !_shiftFlag) {
				_stringInfo.statRtn = STAT_MString;
				_stat = STAT_StringEsc;
			} else if (ch == _T('\0') || ch == -1) {
				SetError(sig, _T("string is not terminated correctly"));
				_stat = STAT_Error;
			} else {
				_token.push_back(ch);
			}
		} else if (_stat == STAT_StringEsc) {
			if (_stringInfo.escapeEnableFlag) {
				if (ch == _T('\n')) {
					_stat = _stringInfo.statRtn;
				} else if (ch == _T('x')) {
					_stringInfo.accum = 0x00;
					_stringInfo.cntRest = 2;
					_stat = STAT_StringEscHex;
				} else if (IsOctDigit(ch)) {
					_stringInfo.accum = ConvOctDigit(ch);
					_stringInfo.cntRest = 2;
					_stat = STAT_StringEscOct;
				} else {
					_token.push_back(GetEscaped(ch));
					_stat = _stringInfo.statRtn;
				}
			} else {
				_token.push_back(_T('\\'));
				_token.push_back(ch);
				_stat = _stringInfo.statRtn;
			}
		} else if (_stat == STAT_StringEscHex) {
			if (IsHexDigit(ch)) {
				_stringInfo.accum = (_stringInfo.accum << 4) + ConvHexDigit(ch);
				_stringInfo.cntRest--;
				if (_stringInfo.cntRest <= 0) {
					_token.push_back(static_cast<TCHAR>(_stringInfo.accum));
					_stat = _stringInfo.statRtn;
				}
			} else {
				SetError(sig, _T("invalid hex expression in string"));
				_stat = STAT_Error;
			}
		} else if (_stat == STAT_StringEscOct) {
			if (IsOctDigit(ch)) {
				_stringInfo.accum = (_stringInfo.accum << 3) + ConvOctDigit(ch);
				_stringInfo.cntRest--;
				if (_stringInfo.cntRest <= 0) {
					_token.push_back(static_cast<TCHAR>(_stringInfo.accum));
					_stat = _stringInfo.statRtn;
				}
			} else {
				SetError(sig, _T("invalid oct expression in string"));
				_stat = STAT_Error;
			}
		} else if (_stat == STAT_StringInCommentBlock) {
			if (ch == _stringInfo.chBorder) {
				_stat = STAT_CommentBlock;
			} else if (ch == _T('\\') && !_shiftFlag) {
				_stat = STAT_StringEscInCommentBlock;
			} else {
				// nothing to do
			}
		} else if (_stat == STAT_StringEscInCommentBlock) {
			_stat = STAT_StringInCommentBlock;
		} else if (_stat == STAT_MStringFirst) {
			if (ch == _stringInfo.chBorder) {
				_stat = STAT_MStringSecond;
			} else {
				_token.push_back(_stringInfo.chBorder);
				continueFlag = true;
				_stat = STAT_MString;
			}
		} else if (_stat == STAT_MStringSecond) {
			if (ch == _stringInfo.chBorder) {
				pExpr = FeedElement(env, sig, Element(ETYPE_String, _token));
				_stat = sig.IsSignalled()? STAT_Error : STAT_Start;
			} else {
				_token.push_back(_stringInfo.chBorder);
				_token.push_back(_stringInfo.chBorder);
				continueFlag = true;
				_stat = STAT_MString;
			}
		}
	} while (continueFlag);
	_shiftFlag = _shiftFlag? false : IsSJISFirst(ch);
	if (ch == _T('\n')) _cntLine++;
	return pExpr;
}

Expr *Parser::Parse(Environment &env, Signal sig, const TCHAR *str)
{
	Expr *pExprRtn = NULL;
	Expr_Block *pExprBlock = NULL;
	for ( ; ; str++) {
		int ch = *str;
		Expr *pExpr = ParseChar(env, sig, ch);
		if (sig.IsSignalled()) {
			delete pExprRtn;
			return NULL;
		} else if (pExpr == NULL) {
			// nothing to do
		} else if (pExprRtn == NULL) {
			pExprRtn = pExpr;
		} else {
			if (pExprBlock == NULL) {
				pExprBlock = new Expr_Block();
				pExprBlock->AddExpr(pExprRtn);
				pExprRtn = pExprBlock;
			}
			pExprBlock->AddExpr(pExpr);
		}
		if (ch == _T('\0')) break;
	}
	
	return pExprRtn;
}

Value Parser::Exec(Environment &env, Signal sig, const TCHAR *str)
{
	Value result;
	for ( ; ; str++) {
		int ch = *str;
		Expr *pExpr = ParseChar(env, sig, ch);
		if (sig.IsSignalled()) {
			return Value::Null;
		} else if (pExpr != NULL) {
			result = pExpr->Exec(env, sig);
			if (sig.IsSignalled()) {
				return Value::Null;
			} else if (!env.GetEchoFlag()) {
				// nothing to do
			} else if (result.IsValid()) {
				env.PutString(result.ToString(sig).c_str());
				env.PutString(_T("\n"));
			}
			delete pExpr;
		}
		if (ch == _T('\0')) break;
	}
	return result;
}

Value Parser::Exec(Environment &env, Signal sig, File &file, bool skipErrorFlag)
{
	Value result;
	for (;;) {
		int ch = file.GetChar();
		Expr *pExpr = ParseChar(env, sig, ch);
		if (sig.IsSignalled()) {
			return Value::Null;
		} else if (pExpr != NULL) {
			result = pExpr->Exec(env, sig);
			if (sig.IsError()) {
				if (skipErrorFlag) {
					env.PutString(sig.GetErrString().c_str());
					env.PutString(_T("\n"));
					sig.ClearSignal();
				} else {
					return Value::Null;
				}
			} else if (sig.IsSignalled()) {
				env.PutString(sig.GetSignalName());
				env.PutString(_T("\n"));
				sig.ClearSignal();
			} else if (!env.GetEchoFlag()) {
				// nothing to do
			} else if (result.IsValid()) {
				env.PutString(result.ToString(sig).c_str());
				env.PutString(_T("\n"));
			}
			delete pExpr;
		}
		if (ch < 0) break;
	}
	return result;
}

Parser::Precedence Parser::LookupPrec(const Element &elemLeft, const Element &elemRight)
{
	const Precedence LT = PREC_LT, EQ = PREC_EQ, GT = PREC_GT, xx = PREC_Error;
	const static struct {
		ElemType elemType;
		int index;
	} indexTbl[] = {
		{ ETYPE_Begin,			 1 },	// B
		{ ETYPE_Assign,			 2 },	// =
		{ ETYPE_AssignPlus,		 2 },
		{ ETYPE_AssignMinus,	 2 },
		{ ETYPE_AssignMultiply,	 2 },
		{ ETYPE_AssignDivide,	 2 },
		{ ETYPE_AssignModulo,	 2 },
		{ ETYPE_AssignPower,	 2 },
		{ ETYPE_AssignBitOr,	 2 },
		{ ETYPE_AssignBitAnd,	 2 },
		{ ETYPE_ContainCheck,	 2 },
		{ ETYPE_DictAssign,		 2 },
		{ ETYPE_Sequence,		 3 },	// ..
		{ ETYPE_OrOr,			 4 },	// ||
		{ ETYPE_AndAnd,			 5 },	// &&
		{ ETYPE_Not,			 6 },	// !
		{ ETYPE_Equal,			 7 },	// <
		{ ETYPE_NotEqual,		 7 },
		{ ETYPE_Less,			 7 },
		{ ETYPE_Greater,		 7 },
		{ ETYPE_LessEq,	 		 7 },
		{ ETYPE_GreaterEq,		 7 },
		{ ETYPE_Compare,		 7 },
		{ ETYPE_Or,				 8 },	// |
		{ ETYPE_And,			 9 },	// &
		{ ETYPE_Xor,			 9 },			// t.b.d
		{ ETYPE_Invert,			10 },	// ~
		{ ETYPE_Plus,			11 },	// +
		{ ETYPE_Minus,			11 },
		{ ETYPE_Multiply,		12 },	// *
		{ ETYPE_Divide,			12 },
		{ ETYPE_Modulo,			12 },
		{ ETYPE_Question,		12 },
		{ ETYPE_Power,			13 },	// **
		{ ETYPE_Quote,			14 },	// `
		{ ETYPE_Force,			14 },
		{ ETYPE_Colon,			15 },	// :
		{ ETYPE_Dot,			16 },	// .
		{ ETYPE_ColonColon,		16 },
		{ ETYPE_LParenthesis,	17 },	// (
		{ ETYPE_RParenthesis,	18 },	// )
		{ ETYPE_LBrace,			17 },
		{ ETYPE_RBrace,			18 },
		{ ETYPE_LBlockParam,	17 },
		{ ETYPE_RBlockParam,	18 },
		{ ETYPE_LBracket,		19 },	// [
		{ ETYPE_RBracket,		20 },	// ]
		{ ETYPE_Comma,			21 },	// ,
		{ ETYPE_Semicolon,		21 },
		{ ETYPE_EOL,			22 },	// \n
		{ ETYPE_Number,			23 },	// V
		{ ETYPE_ImagNumber,		23 },
		{ ETYPE_String,			23 },
		{ ETYPE_Symbol,			24 },	// S
		{ ETYPE_EOF,			25 },	// E
	};
	const static Precedence precTbl[][26] = {
		/*         B   =  ..  ||  &&   !   <   |   &   ~   +   *  **   `   :   .   (   )   [   ]   ,  \n   V   S   E */
		/* e */ { xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx },
		/* B */ { xx, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, xx, LT, xx, EQ, EQ, LT, LT, EQ },
		/* = */ { xx, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, GT, LT, GT, GT, GT, LT, LT, GT },
		/* ..*/ { xx, GT, GT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, GT, LT, GT, GT, GT, LT, LT, GT },
		/* ||*/ { xx, GT, GT, GT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, GT, LT, GT, GT, GT, LT, LT, GT },
		/* &&*/ { xx, GT, GT, GT, GT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, GT, LT, GT, GT, GT, LT, LT, GT },
		/* ! */ { xx, GT, GT, GT, GT, GT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, GT, LT, GT, GT, GT, LT, LT, GT },
		/* < */ { xx, LT, GT, GT, GT, GT, GT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, GT, LT, GT, GT, GT, LT, LT, GT },
		/* | */ { xx, GT, GT, GT, GT, GT, GT, GT, LT, LT, LT, LT, LT, LT, LT, LT, LT, GT, LT, GT, GT, GT, LT, LT, GT },
		/* & */ { xx, GT, GT, GT, GT, GT, GT, GT, GT, LT, LT, LT, LT, LT, LT, LT, LT, GT, LT, GT, GT, GT, LT, LT, GT },
		/* ~ */ { xx, GT, GT, GT, GT, GT, GT, GT, GT, GT, LT, LT, LT, LT, LT, LT, LT, GT, LT, GT, GT, GT, LT, LT, GT },
		/* + */ { xx, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, LT, LT, LT, GT, LT, LT, GT, LT, GT, GT, GT, LT, LT, GT },
		/* * */ { xx, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, LT, LT, GT, LT, LT, GT, LT, GT, GT, GT, LT, LT, GT },
		/* ***/ { xx, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, LT, LT, LT, LT, GT, LT, GT, GT, GT, LT, LT, GT },
		/* ` */ { xx, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, LT, LT, LT, GT, LT, GT, GT, GT, LT, LT, GT },
		/* : */ { xx, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, LT, GT, GT, GT, LT, LT, GT },
		/* . */ { xx, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, LT, LT, GT },
		/* ( */ { xx, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, EQ, LT, EQ, EQ, EQ, LT, LT, xx },
		/* ) */ { xx, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT },
		/* [ */ { xx, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, LT, EQ, LT, EQ, EQ, EQ, LT, LT, xx },
		/* ] */ { xx, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT },
		/* , */ { xx, LT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, xx, GT, GT, GT, GT },
		/* \n*/ { xx, LT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT },
		/* V */ { xx, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, LT, xx, GT },
		/* S */ { xx, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, GT, xx, xx, GT },
	};
	int indexLeft = 0, indexRight = 1;
	for (int i = 0; i < NUMBEROF(indexTbl); i++) {
		if (elemLeft.IsType(indexTbl[i].elemType)) {
			indexLeft = indexTbl[i].index;
			break;
		}
	}
	for (int i = 0; i < NUMBEROF(indexTbl); i++) {
		if (elemRight.IsType(indexTbl[i].elemType)) {
			indexRight = indexTbl[i].index;
			break;
		}
	}
	Precedence prec = precTbl[indexLeft][indexRight - 1];
	DBGPARSER(::_tprintf(_T("%-8s %s %8s\n"),
				elemLeft.GetTypeName(),
				(prec == LT)? _T("<") : (prec == EQ)? _T("=") :
				(prec == GT)? _T(">") : _T("X"),
				elemRight.GetTypeName()));
	return prec;
}

Expr *Parser::FeedElement(Environment &env, Signal sig, const Element &elem)
{
	//::_tprintf(_T("FeedElement(%s)\n"), elem.GetTypeName());
	Expr *pExpr = NULL;
	for (;;) {
		ElementStack::reverse_iterator pElemTop =
								_elemStack.SeekTerminal(_elemStack.rbegin());
		//::_tprintf(_T("%s  << %s\n"),
		//				_elemStack.ToString().c_str(), elem.GetTypeSymbol());
		DBGPARSER(::_tprintf(_T("%s  << %s\n"),
						_elemStack.ToString().c_str(), elem.GetTypeSymbol()));
		Precedence prec = LookupPrec(*pElemTop, elem);
		if (pElemTop->IsType(ETYPE_Begin) && elem.IsSeparatorElement()) {
			size_t cntElem = _elemStack.size();
			if (cntElem == 1) {
				// nothing to do
			} else if (cntElem == 2 && _elemStack[1].IsType(ETYPE_Expr)) {
				pExpr = _elemStack[1].GetExpr();
				_elemStack.pop_back();
			} else {
				// something's wrong
				InitStack();
			}
			break;
		} else if (prec == PREC_LT || prec == PREC_EQ) {
			Element &elemLast = _elemStack.back();
			if (elemLast.IsType(ETYPE_String) && elem.IsType(ETYPE_String)) {
				elemLast.AddString(elem.GetString());
			} else {
				_elemStack.push_back(elem);
			}
			break;
		} else if (prec == PREC_GT) {
			ElementStack::reverse_iterator pElemLeft;
			ElementStack::reverse_iterator pElemRight = pElemTop;
			while (1) {
				pElemLeft = _elemStack.SeekTerminal(pElemRight + 1);
				if (LookupPrec(*pElemLeft, *pElemRight) == PREC_LT) {
					pElemLeft--;
					break;
				}
				pElemRight = pElemLeft;
			}
			size_t cntElem = std::distance(_elemStack.rbegin(), pElemLeft) + 1;
			bool rtn;
			if (cntElem == 1) {
				rtn = ReduceOneElem(env, sig);
			} else if (cntElem == 2) {
				rtn = ReduceTwoElems(env, sig);
			} else if (cntElem == 3) {
				rtn = ReduceThreeElems(env, sig);
			} else if (cntElem == 4) {
				rtn = ReduceFourElems(env, sig);
			} else if (cntElem == 5) {
				rtn = ReduceFiveElems(env, sig);
			} else {
				SetError_InvalidElement(sig, __LINE__);
				rtn = false;
			}
			if (!rtn) {
				InitStack();
				break;
			}
		} else {
			SetError_InvalidElement(sig, __LINE__);
			InitStack();
			break;
		}
	}
	return pExpr;
}

bool Parser::ReduceOneElem(Environment &env, Signal sig)
{
	Expr *pExpr;
	Element &elem1 = _elemStack.Peek(0);
	if (elem1.IsType(ETYPE_Number)) {
		DBGPARSER(::_tprintf(_T("Reduce: Expr -> Number\n")));
		pExpr = new Expr_Value(elem1.GetNumber());
	} else if (elem1.IsType(ETYPE_ImagNumber)) {
		DBGPARSER(::_tprintf(_T("Reduce: Expr -> ImagNumber\n")));
		pExpr = new Expr_Value(Complex(0, elem1.GetNumber()));
	} else if (elem1.IsType(ETYPE_String)) {
		DBGPARSER(::_tprintf(_T("Reduce: Expr -> String\n")));
		pExpr = new Expr_Value(Value(env, elem1.GetString()));
	} else if (elem1.IsType(ETYPE_Symbol)) {
		DBGPARSER(::_tprintf(_T("Reduce: Expr -> Symbol\n")));
		const Symbol *pSymbol = Symbol::Add(elem1.GetString());
		pExpr = new Expr_Symbol(pSymbol);
	} else {
		SetError_InvalidElement(sig, __LINE__);
		return false;
	}
	_elemStack.pop_back();
	pExpr->SetLineNo(GetLineNo());
	_elemStack.push_back(Element(ETYPE_Expr, pExpr));
	return true;
}

bool Parser::ReduceTwoElems(Environment &env, Signal sig)
{
	Expr *pExpr;
	Element &elem1 = _elemStack.Peek(1);
	Element &elem2 = _elemStack.Peek(0);
	if (elem1.IsType(ETYPE_LParenthesis)) {
		if (elem2.IsType(ETYPE_RParenthesis)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> '(' ')'\n")));
			Expr_Lister *pExprLister =
						dynamic_cast<Expr_Lister *>(elem1.GetExpr());
			if (pExprLister == NULL) {
				pExprLister = new Expr_Lister();
			}
			pExpr = pExprLister;
		} else if (elem2.IsType(ETYPE_EOL)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("Reduce: '(' -> '(' EOL\n")));
			_elemStack.pop_back();
			return true;
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else if (elem1.IsType(ETYPE_LBracket)) {
		if (elem2.IsType(ETYPE_RBracket)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> '[' ']'\n")));
			Expr_Lister *pExprLister =
						dynamic_cast<Expr_Lister *>(elem1.GetExpr());
			if (pExprLister == NULL) {
				pExprLister = new Expr_Lister();
			}
			pExpr = pExprLister;
		} else if (elem2.IsType(ETYPE_EOL)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("Reduce: '[' -> '[' EOL\n")));
			_elemStack.pop_back();
			return true;
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else if (elem1.IsType(ETYPE_LBrace)) {
		if (elem2.IsType(ETYPE_RBrace)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> '{' '}'\n")));
			Expr_Block *pExprBlock =
						dynamic_cast<Expr_Block *>(elem1.GetExpr());
			if (pExprBlock == NULL) {
				pExprBlock = new Expr_Block();
			}
			pExpr = pExprBlock;
		} else if (elem2.IsType(ETYPE_EOL)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("Reduce: '{' -> '{' EOL\n")));
			_elemStack.pop_back();
			return true;
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else if (elem1.IsType(ETYPE_LBlockParam)) {
		if (elem2.IsType(ETYPE_RBlockParam)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("do (Reduce: Expr -> '|' '|') ")
					_T("and then attach the Expr to the preceeding LBrace\n")));
			Expr_BlockParam *pExprBlockParam =
						dynamic_cast<Expr_BlockParam *>(elem1.GetExpr());
			if (pExprBlockParam == NULL) {
				pExprBlockParam = new Expr_BlockParam();
			}
			_elemStack.pop_back();
			_elemStack.pop_back();
			Element &elemPrev = _elemStack.Peek(0);
			if (elemPrev.IsType(ETYPE_LBrace)) {
				Expr_Block *pExprBlock =
							dynamic_cast<Expr_Block *>(elemPrev.GetExpr());
				if (pExprBlock == NULL) {
					pExprBlock = new Expr_Block();
					elemPrev.SetExpr(pExprBlock);
				}
				pExprBlock->SetParam(pExprBlockParam);
			} else {
				delete pExprBlockParam;
				SetError(sig, _T("invalid placement of block parameter"));
				return false;
			}
			return true;
		} else if (elem2.IsType(ETYPE_EOL)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("Reduce: '|' -> '|' EOL\n")));
			_elemStack.pop_back();
			return true;
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else if (elem1.IsType(ETYPE_Expr) && elem2.IsType(ETYPE_Symbol)) {
		// this is a special case of reducing
		DBGPARSER(::_tprintf(_T("Reduce: Expr Expr -> Expr Symbol\n")));
		const Symbol *pSymbol = Symbol::Add(elem2.GetString());
		pExpr = new Expr_Symbol(pSymbol);
		_elemStack.pop_back();
		pExpr->SetLineNo(GetLineNo());
		_elemStack.push_back(Element(ETYPE_Expr, pExpr));
		return true;
	} else if (elem2.IsType(ETYPE_Expr)) {
		if (elem1.IsType(ETYPE_Quote)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> ''' Expr\n")));
			pExpr = new Expr_Quote(elem2.GetExpr());
		} else if (elem1.IsType(ETYPE_Force)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> '!!' Expr\n")));
			pExpr = new Expr_Force(elem2.GetExpr());
		} else if (elem1.IsType(ETYPE_Plus)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> '+' Expr\n")));
			pExpr = elem2.GetExpr();
		} else if (elem1.IsType(ETYPE_Minus)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> '-' Expr\n")));
			pExpr = new Expr_UnaryOp(env.GetFunc_Neg(), elem2.GetExpr());
		} else if (elem1.IsType(ETYPE_Invert)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> '~' Expr\n")));
			pExpr = new Expr_UnaryOp(env.GetFunc_Invert(), elem2.GetExpr());
		} else if (elem1.IsType(ETYPE_Not)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> '!' Expr\n")));
			pExpr = new Expr_UnaryOp(env.GetFunc_Not(), elem2.GetExpr());
		} else if (elem1.IsType(ETYPE_Modulo)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> '%' Expr\n")));
			if (elem2.GetExpr()->IsBlock()) {
				Expr *pExprCar = new Expr_Symbol(AScript_Symbol(Char_Modulo));
				Expr_Block *pExprBlock = dynamic_cast<Expr_Block *>(elem2.GetExpr());
				Expr_Function *pExprFunc =
								new Expr_Function(pExprCar, NULL, pExprBlock);
				pExpr = pExprFunc;
			} else if (elem2.GetExpr()->IsSymbol()) {
				pExpr = new Expr_Prefix(elem2.GetExpr(), AScript_Symbol(Char_Modulo));
			} else {
				SetError_InvalidElement(sig, __LINE__);
				return false;
			}
		} else if (elem1.IsType(ETYPE_And)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> '&' Expr\n")));
			if (elem2.GetExpr()->IsBlock()) {
				Expr *pExprCar = new Expr_Symbol(AScript_Symbol(Char_And));
				Expr_Block *pExprBlock = dynamic_cast<Expr_Block *>(elem2.GetExpr());
				Expr_Function *pExprFunc =
								new Expr_Function(pExprCar, NULL, pExprBlock);
				pExpr = pExprFunc;
			} else if (elem2.GetExpr()->IsSymbol()) {
				pExpr = new Expr_Prefix(elem2.GetExpr(), AScript_Symbol(Char_And));
			} else {
				SetError_InvalidElement(sig, __LINE__);
				return false;
			}
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else if (elem1.IsType(ETYPE_Expr)) {
		if (elem2.IsType(ETYPE_Plus)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr '+'\n")));
			pExpr = new Expr_Suffix(elem1.GetExpr(), AScript_Symbol(Char_Plus));
		} else if (elem2.IsType(ETYPE_Multiply)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr '*'\n")));
			pExpr = new Expr_Suffix(elem1.GetExpr(), AScript_Symbol(Char_Multiply));
		} else if (elem2.IsType(ETYPE_Question)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr '?'\n")));
			pExpr = new Expr_Suffix(elem1.GetExpr(), AScript_Symbol(Char_Question));
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else {
		SetError_InvalidElement(sig, __LINE__);
		return false;
	}
	_elemStack.pop_back();
	_elemStack.pop_back();
	pExpr->SetLineNo(GetLineNo());
	_elemStack.push_back(Element(ETYPE_Expr, pExpr));
	return true;
}

bool Parser::ReduceThreeElems(Environment &env, Signal sig)
{
	Expr *pExpr;
	Element &elem1 = _elemStack.Peek(2);
	Element &elem2 = _elemStack.Peek(1);
	Element &elem3 = _elemStack.Peek(0);
	if (elem1.IsType(ETYPE_LParenthesis) && elem2.IsType(ETYPE_Expr)) {
		Expr_Lister *pExprLister = dynamic_cast<Expr_Lister *>(elem1.GetExpr());
		if (elem3.IsType(ETYPE_RParenthesis)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> '(' Expr ')'\n")));
			if (pExprLister == NULL) {
				pExpr = elem2.GetExpr();	// treat expr as non-list
			} else {
				pExprLister->AddExpr(elem2.GetExpr());
				pExpr = pExprLister;
			}
		} else if (elem3.IsType(ETYPE_Comma) || elem3.IsType(ETYPE_EOL)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("Reduce: '(' -> '(' Expr ','\n")));
			if (pExprLister == NULL) {
				pExprLister = new Expr_Lister();
				elem1.SetExpr(pExprLister);
			}
			pExprLister->AddExpr(elem2.GetExpr());
			_elemStack.pop_back();
			_elemStack.pop_back();
			return true;
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else if (elem1.IsType(ETYPE_LBracket) && elem2.IsType(ETYPE_Expr)) {
		Expr_Lister *pExprLister = dynamic_cast<Expr_Lister *>(elem1.GetExpr());
		if (elem3.IsType(ETYPE_RBracket)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> '[' Expr ']'\n")));
			if (pExprLister == NULL) {
				pExprLister = new Expr_Lister();
			}
			pExprLister->AddExpr(elem2.GetExpr());
			pExpr = pExprLister;
		} else if (elem3.IsType(ETYPE_Comma) || elem3.IsType(ETYPE_EOL)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("Reduce: '[' -> '[' Expr ','\n")));
			if (pExprLister == NULL) {
				pExprLister = new Expr_Lister();
				elem1.SetExpr(pExprLister);
			}
			pExprLister->AddExpr(elem2.GetExpr());
			_elemStack.pop_back();
			_elemStack.pop_back();
			return true;
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else if (elem1.IsType(ETYPE_Expr) && elem2.IsType(ETYPE_LParenthesis)) {
		if (elem3.IsType(ETYPE_RParenthesis)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr '(' ')'\n")));
			Expr_Lister *pExprLister = dynamic_cast<Expr_Lister *>(elem2.GetExpr());
			if (pExprLister == NULL) {
				pExprLister = new Expr_Lister();
			}
			Expr_Function *pExprFunc = 
						new Expr_Function(elem1.GetExpr(), pExprLister, NULL);
			pExpr = pExprFunc;
		} else if (elem3.IsType(ETYPE_EOL)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("Reduce: Expr '(' -> Expr '(' EOL\n")));
			_elemStack.pop_back();
			return true;
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else if (elem1.IsType(ETYPE_Expr) && elem2.IsType(ETYPE_LBrace)) {
		if (elem3.IsType(ETYPE_RBrace)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr '{' '}'\n")));
			Expr_Block *pExprBlock = dynamic_cast<Expr_Block *>(elem2.GetExpr());
			if (elem1.GetExpr()->IsFunction()) {
				Expr_Function *pExprFunc =
								dynamic_cast<Expr_Function *>(elem1.GetExpr());
				if (pExprBlock == NULL) {
					pExprBlock = new Expr_Block();
				}
				pExprFunc->GetLastSucceeding()->SetBlock(pExprBlock);
				pExpr = pExprFunc;
			} else {
				if (pExprBlock == NULL) {
					pExprBlock = new Expr_Block();
				}
				Expr_Function *pExprFunc =
							new Expr_Function(elem1.GetExpr(), NULL, pExprBlock);
				pExpr = pExprFunc;
			}
		} else if (elem3.IsType(ETYPE_EOL)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("Reduce: Expr '{' -> Expr '{' EOL\n")));
			_elemStack.pop_back();
			return true;
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else if (elem1.IsType(ETYPE_Expr) && elem2.IsType(ETYPE_LBracket)) {
		if (elem3.IsType(ETYPE_RBracket)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr '[' ']'\n")));
			Expr *pExprTgt = elem1.GetExpr();
			Expr_Lister *pExprLister = dynamic_cast<Expr_Lister *>(elem2.GetExpr());
			if (pExprLister == NULL) {
				pExprLister = new Expr_Lister();
			}
			pExpr = new Expr_Indexer(pExprTgt, pExprLister);
		} else if (elem3.IsType(ETYPE_EOL)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("Reduce: Expr '[' -> Expr '[' EOL\n")));
			_elemStack.pop_back();
			return true;
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else if (elem1.IsType(ETYPE_LBrace) && elem2.IsType(ETYPE_Expr)) {
		Expr_Block *pExprBlock = dynamic_cast<Expr_Block *>(elem1.GetExpr());
		if (elem3.IsType(ETYPE_RBrace)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> '{' Expr '}'\n")));
			if (pExprBlock == NULL) {
				pExprBlock = new Expr_Block();
			}
			pExprBlock->AddExpr(elem2.GetExpr());
			pExpr = pExprBlock;
		} else if (elem3.IsType(ETYPE_Comma) ||
					elem3.IsType(ETYPE_Semicolon) || elem3.IsType(ETYPE_EOL)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("Reduce: '{' -> '{' Expr ','\n")));
			if (pExprBlock == NULL) {
				pExprBlock = new Expr_Block();
				elem1.SetExpr(pExprBlock);
			}
			pExprBlock->AddExpr(elem2.GetExpr());
			_elemStack.pop_back();
			_elemStack.pop_back();
			return true;
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else if (elem1.IsType(ETYPE_LBlockParam) && elem2.IsType(ETYPE_Expr)) {
		Expr_BlockParam *pExprBlockParam = dynamic_cast<Expr_BlockParam *>(elem1.GetExpr());
		if (elem3.IsType(ETYPE_RBlockParam)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("do (Reduce: Expr -> '|' Expr '|') ")
					_T("and then attach the Expr to the preceeding LBrace\n")));
			if (pExprBlockParam == NULL) {
				pExprBlockParam = new Expr_BlockParam();
			}
			pExprBlockParam->AddExpr(elem2.GetExpr());
			_elemStack.pop_back();
			_elemStack.pop_back();
			_elemStack.pop_back();
			Element &elemPrev = _elemStack.Peek(0);
			if (elemPrev.IsType(ETYPE_LBrace)) {
				Expr_Block *pExprBlock =
							dynamic_cast<Expr_Block *>(elemPrev.GetExpr());
				if (pExprBlock == NULL) {
					pExprBlock = new Expr_Block();
					elemPrev.SetExpr(pExprBlock);
				}
				pExprBlock->SetParam(pExprBlockParam);
			} else {
				delete pExprBlockParam;
				SetError(sig, _T("invalid placement of block parameter"));
				return false;
			}
			return true;
		} else if (elem3.IsType(ETYPE_Comma) ||
					elem3.IsType(ETYPE_Semicolon) || elem3.IsType(ETYPE_EOL)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("Reduce: '|' -> '|' Expr ','\n")));
			if (pExprBlockParam == NULL) {
				pExprBlockParam = new Expr_BlockParam();
				elem1.SetExpr(pExprBlockParam);
			}
			pExprBlockParam->AddExpr(elem2.GetExpr());
			_elemStack.pop_back();
			_elemStack.pop_back();
			return true;
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else if (elem1.IsType(ETYPE_Expr) && elem3.IsType(ETYPE_Expr)) {
		Expr *pExprLeft = elem1.GetExpr();
		Expr *pExprRight = elem3.GetExpr();
		if (elem2.IsType(ETYPE_Plus)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr + Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_Plus(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_Minus)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr - Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_Minus(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_Multiply)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr * Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_Multiply(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_Divide)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr / Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_Divide(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_Modulo)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr % Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_Modulo(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_Power)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr ** Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_Power(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_Equal)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr == Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_Equal(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_NotEqual)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr != Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_NotEqual(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_Less)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr < Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_Less(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_Greater)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr > Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_Greater(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_LessEq)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr <= Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_LessEq(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_GreaterEq)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr >= Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_GreaterEq(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_Compare)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr <=> Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_Compare(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_ContainCheck)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr in Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_ContainCheck(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_Assign)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr = Expr\n")));
			pExpr = new Expr_Assign(pExprLeft, pExprRight, NULL);
		} else if (elem2.IsType(ETYPE_AssignPlus)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr += Expr\n")));
			pExpr = new Expr_Assign(pExprLeft, pExprRight, &env.GetFunc_Plus());
		} else if (elem2.IsType(ETYPE_AssignMinus)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr -= Expr\n")));
			pExpr = new Expr_Assign(pExprLeft, pExprRight, &env.GetFunc_Minus());
		} else if (elem2.IsType(ETYPE_AssignMultiply)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr *= Expr\n")));
			pExpr = new Expr_Assign(pExprLeft, pExprRight, &env.GetFunc_Multiply());
		} else if (elem2.IsType(ETYPE_AssignDivide)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr /= Expr\n")));
			pExpr = new Expr_Assign(pExprLeft, pExprRight, &env.GetFunc_Divide());
		} else if (elem2.IsType(ETYPE_AssignModulo)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr %= Expr\n")));
			pExpr = new Expr_Assign(pExprLeft, pExprRight, &env.GetFunc_Modulo());
		} else if (elem2.IsType(ETYPE_AssignPower)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr **= Expr\n")));
			pExpr = new Expr_Assign(pExprLeft, pExprRight, &env.GetFunc_Power());
		} else if (elem2.IsType(ETYPE_AssignBitOr)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr |= Expr\n")));
			pExpr = new Expr_Assign(pExprLeft, pExprRight, &env.GetFunc_Or());
		} else if (elem2.IsType(ETYPE_AssignBitAnd)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr &= Expr\n")));
			pExpr = new Expr_Assign(pExprLeft, pExprRight, &env.GetFunc_And());
		} else if (elem2.IsType(ETYPE_DictAssign)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr => Expr\n")));
			pExpr = new Expr_DictAssign(pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_Colon)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr : Expr\n")));
			if (pExprRight->IsSymbol()) {
				const Symbol *pSymbol =
						dynamic_cast<Expr_Symbol *>(pExprRight)->GetSymbol();
				Expr *pExprDst = pExprLeft;
				if (pExprDst->IsSuffix()) {
					pExprDst = dynamic_cast<Expr_Suffix *>(pExprDst)->GetExprChild();
				}
				if (pExprDst->IsIndexer()) {
					pExprDst = dynamic_cast<Expr_Indexer *>(pExprDst)->GetExprCar();
				}
				if (pExprDst->IsSymbol()) {
					dynamic_cast<Expr_Symbol *>(pExprDst)->AddAttr(pSymbol);
				} else if (pExprDst->IsFunction()) {
					Expr_Function *pExprFunc =
									dynamic_cast<Expr_Function *>(pExprDst);
					pExprFunc->GetLastSucceeding()->AddAttr(pSymbol);
				} else {
					SetError_InvalidElement(sig, __LINE__);
					return false;
				}
				pExpr = pExprLeft;
				delete pExprRight;
			} else if (pExprRight->IsLister()) {
				Expr *pExprDst = pExprLeft;
				ExprList &exprList =
							dynamic_cast<Expr_Lister *>(pExprRight)->GetExprList();
				if (pExprDst->IsSuffix()) {
					pExprDst = dynamic_cast<Expr_Suffix *>(pExprDst)->GetExprChild();
				}
				if (pExprDst->IsIndexer()) {
					pExprDst = dynamic_cast<Expr_Indexer *>(pExprDst)->GetExprCar();
				}
				if (pExprDst->IsSymbol()) {
					//dynamic_cast<Expr_Symbol *>(pExprDst)->AddAttr(pSymbol);
				} else if (pExprDst->IsFunction()) {
					Expr_Function *pExprFunc =
									dynamic_cast<Expr_Function *>(pExprDst);
					pExprFunc = pExprFunc->GetLastSucceeding();
					foreach (ExprList, ppExpr, exprList) {
						Expr *pExpr = *ppExpr;
						if (!pExpr->IsSymbol()) {
							SetError_InvalidElement(sig, __LINE__);
							return false;
						}
						const Symbol *pSymbol =
								dynamic_cast<Expr_Symbol *>(pExpr)->GetSymbol();
						pExprFunc->AddAttrOpt(pSymbol);
					}
				} else {
					SetError_InvalidElement(sig, __LINE__);
					return false;
				}
				pExpr = pExprLeft;
				delete pExprRight;
			} else {
				SetError_InvalidElement(sig, __LINE__);
				return false;
			}
		} else if (elem2.IsType(ETYPE_Dot)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr . Expr\n")));
			pExpr = new Expr_Field(pExprLeft, pExprRight, 0);
		} else if (elem2.IsType(ETYPE_ColonColon)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr :: Expr\n")));
			pExpr = new Expr_Field(pExprLeft, pExprRight, elem2.GetNum());
		} else if (elem2.IsType(ETYPE_OrOr)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr || Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_OrOr(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_AndAnd)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr && Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_AndAnd(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_Or)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr | Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_Or(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_And)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr & Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_And(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_Xor)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr ^ Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_Xor(), pExprLeft, pExprRight);
		} else if (elem2.IsType(ETYPE_Sequence)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr .. Expr\n")));
			pExpr = new Expr_BinaryOp(env.GetFunc_Sequence(), pExprLeft, pExprRight);
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else {
		SetError_InvalidElement(sig, __LINE__);
		return false;
	}
	_elemStack.pop_back();
	_elemStack.pop_back();
	_elemStack.pop_back();
	pExpr->SetLineNo(GetLineNo());
	_elemStack.push_back(Element(ETYPE_Expr, pExpr));
	return true;
}

bool Parser::ReduceFourElems(Environment &env, Signal sig)
{
	Expr *pExpr;
	Element &elem1 = _elemStack.Peek(3);
	Element &elem2 = _elemStack.Peek(2);
	Element &elem3 = _elemStack.Peek(1);
	Element &elem4 = _elemStack.Peek(0);
	if (elem1.IsType(ETYPE_Expr) && elem2.IsType(ETYPE_Expr) &&
											elem3.IsType(ETYPE_LParenthesis)) {
		if (elem4.IsType(ETYPE_RParenthesis)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr Expr '(' ')'\n")));
			Expr_Lister *pExprLister = dynamic_cast<Expr_Lister *>(elem3.GetExpr());
			if (pExprLister == NULL) {
				pExprLister = new Expr_Lister();
			}
			Expr_Function *pExprFunc = 
						new Expr_Function(elem2.GetExpr(), pExprLister, NULL);
			if (!elem1.GetExpr()->IsFunction()) {
				SetError_InvalidElement(sig, __LINE__);
				return false;
			}
			Expr_Function *pExprFuncPrev =
							dynamic_cast<Expr_Function *>(elem1.GetExpr());
			pExprFuncPrev->GetLastSucceeding()->SetSucceeding(pExprFunc);
			pExpr = pExprFuncPrev;
		} else if (elem4.IsType(ETYPE_EOL)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("Reduce: Expr Expr '(' -> Expr Expr '(' EOL\n")));
			_elemStack.pop_back();
			return true;
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else if (elem1.IsType(ETYPE_Expr) && elem2.IsType(ETYPE_Expr) &&
												elem3.IsType(ETYPE_LBrace)) {
		if (elem4.IsType(ETYPE_RBrace)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr Expr '{' '}'\n")));
			Expr_Block *pExprBlock = dynamic_cast<Expr_Block *>(elem3.GetExpr());
			if (pExprBlock == NULL) {
				pExprBlock = new Expr_Block();
			}
			Expr_Function *pExprFunc;
			if (elem2.GetExpr()->IsFunction()) {
				pExprFunc = dynamic_cast<Expr_Function *>(elem2.GetExpr());
				pExprFunc->GetLastSucceeding()->SetBlock(pExprBlock);
			} else {
				pExprFunc = new Expr_Function(elem2.GetExpr(), NULL, pExprBlock);
			}
			if (!elem1.GetExpr()->IsFunction()) {
				SetError_InvalidElement(sig, __LINE__);
				return false;
			}
			Expr_Function *pExprFuncPrev =
							dynamic_cast<Expr_Function *>(elem1.GetExpr());
			pExprFuncPrev->GetLastSucceeding()->SetSucceeding(pExprFunc);
			pExpr = pExprFuncPrev;
		} else if (elem4.IsType(ETYPE_EOL)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("Reduce: Expr Expr '{' -> Expr Expr '{' EOL\n")));
			_elemStack.pop_back();
			return true;
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else if (elem1.IsType(ETYPE_Expr) &&
				elem2.IsType(ETYPE_LParenthesis) && elem3.IsType(ETYPE_Expr)) {
		Expr_Lister *pExprLister = dynamic_cast<Expr_Lister *>(elem2.GetExpr());
		if (elem4.IsType(ETYPE_RParenthesis)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr '(' Expr ')'\n")));
			if (pExprLister == NULL) {
				pExprLister = new Expr_Lister();
			}
			pExprLister->AddExpr(elem3.GetExpr());
			Expr_Function *pExprFunc =
						new Expr_Function(elem1.GetExpr(), pExprLister, NULL);
			pExpr = pExprFunc;
		} else if (elem4.IsType(ETYPE_Comma) || elem4.IsType(ETYPE_EOL)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("Reduce: Expr '(' -> Expr '(' Expr ','\n")));
			if (pExprLister == NULL) {
				pExprLister = new Expr_Lister();
				elem2.SetExpr(pExprLister);
			}
			pExprLister->AddExpr(elem3.GetExpr());
			_elemStack.pop_back();
			_elemStack.pop_back();
			return true;
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else if (elem1.IsType(ETYPE_Expr) &&
				elem2.IsType(ETYPE_LBrace) && elem3.IsType(ETYPE_Expr)) {
		Expr_Block *pExprBlock = dynamic_cast<Expr_Block *>(elem2.GetExpr());
		if (elem4.IsType(ETYPE_RBrace)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr '{' Expr '}'\n")));
			if (pExprBlock == NULL) {
				pExprBlock = new Expr_Block();
			}
			pExprBlock->AddExpr(elem3.GetExpr());
			if (elem1.GetExpr()->IsFunction()) {
				Expr_Function *pExprFunc =
								dynamic_cast<Expr_Function *>(elem1.GetExpr());
				pExprFunc->GetLastSucceeding()->SetBlock(pExprBlock);
				pExpr = pExprFunc;
			} else {
				Expr_Function *pExprFunc =
							new Expr_Function(elem1.GetExpr(), NULL, pExprBlock);
				pExpr = pExprFunc;
			}
		} else if (elem4.IsType(ETYPE_Comma) ||
					elem4.IsType(ETYPE_Semicolon) || elem4.IsType(ETYPE_EOL)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("Reduce: Expr '{' -> Expr '{' Expr ','\n")));
			if (pExprBlock == NULL) {
				pExprBlock = new Expr_Block();
				elem2.SetExpr(pExprBlock);
			}
			pExprBlock->AddExpr(elem3.GetExpr());
			_elemStack.pop_back();
			_elemStack.pop_back();
			return true;
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else if (elem1.IsType(ETYPE_Expr) &&
				elem2.IsType(ETYPE_LBracket) && elem3.IsType(ETYPE_Expr)) {
		Expr_Lister *pExprLister = dynamic_cast<Expr_Lister *>(elem2.GetExpr());
		if (elem4.IsType(ETYPE_RBracket)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr '[' Expr ']'\n")));
			Expr *pExprTgt = elem1.GetExpr();
			if (pExprLister == NULL) {
				pExprLister = new Expr_Lister();
			}
			pExprLister->AddExpr(elem3.GetExpr());
			pExpr = new Expr_Indexer(pExprTgt, pExprLister);
		} else if (elem4.IsType(ETYPE_Comma) || elem4.IsType(ETYPE_EOL)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("Reduce: Expr '[' -> Expr '[' Expr ','\n")));
			if (pExprLister == NULL) {
				pExprLister = new Expr_Lister();
				elem2.SetExpr(pExprLister);
			}
			pExprLister->AddExpr(elem3.GetExpr());
			_elemStack.pop_back();
			_elemStack.pop_back();
			return true;
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else {
		SetError_InvalidElement(sig, __LINE__);
		return false;
	}
	_elemStack.pop_back();
	_elemStack.pop_back();
	_elemStack.pop_back();
	_elemStack.pop_back();
	pExpr->SetLineNo(GetLineNo());
	_elemStack.push_back(Element(ETYPE_Expr, pExpr));
	return true;
}

bool Parser::ReduceFiveElems(Environment &env, Signal sig)
{
	Expr *pExpr;
	Element &elem1 = _elemStack.Peek(4);
	Element &elem2 = _elemStack.Peek(3);
	Element &elem3 = _elemStack.Peek(2);
	Element &elem4 = _elemStack.Peek(1);
	Element &elem5 = _elemStack.Peek(0);
	if (elem1.IsType(ETYPE_Expr) && elem2.IsType(ETYPE_Expr) &&
				elem3.IsType(ETYPE_LParenthesis) && elem4.IsType(ETYPE_Expr)) {
		Expr_Lister *pExprLister = dynamic_cast<Expr_Lister *>(elem3.GetExpr());
		if (elem5.IsType(ETYPE_RParenthesis)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr Expr '(' Expr ')'\n")));
			if (pExprLister == NULL) {
				pExprLister = new Expr_Lister();
			}
			pExprLister->AddExpr(elem4.GetExpr());
			Expr_Function *pExprFunc =
						new Expr_Function(elem2.GetExpr(), pExprLister, NULL);
			if (!elem1.GetExpr()->IsFunction()) {
				SetError_InvalidElement(sig, __LINE__);
				return false;
			}
			Expr_Function *pExprFuncPrev =
							dynamic_cast<Expr_Function *>(elem1.GetExpr());
			pExprFuncPrev->GetLastSucceeding()->SetSucceeding(pExprFunc);
			pExpr = pExprFuncPrev;
		} else if (elem5.IsType(ETYPE_Comma) || elem5.IsType(ETYPE_EOL)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("Reduce: Expr Expr '(' -> Expr Expr '(' Expr ','\n")));
			if (pExprLister == NULL) {
				pExprLister = new Expr_Lister();
				elem3.SetExpr(pExprLister);
			}
			pExprLister->AddExpr(elem4.GetExpr());
			_elemStack.pop_back();
			_elemStack.pop_back();
			return true;
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else if (elem1.IsType(ETYPE_Expr) && elem2.IsType(ETYPE_Expr) &&
				elem3.IsType(ETYPE_LBrace) && elem4.IsType(ETYPE_Expr)) {
		Expr_Block *pExprBlock = dynamic_cast<Expr_Block *>(elem3.GetExpr());
		if (elem5.IsType(ETYPE_RBrace)) {
			DBGPARSER(::_tprintf(_T("Reduce: Expr -> Expr Expr '{' Expr '}'\n")));
			if (pExprBlock == NULL) {
				pExprBlock = new Expr_Block();
			}
			pExprBlock->AddExpr(elem4.GetExpr());
			Expr_Function *pExprFunc;
			if (elem2.GetExpr()->IsFunction()) {
				pExprFunc = dynamic_cast<Expr_Function *>(elem2.GetExpr());
				pExprFunc->GetLastSucceeding()->SetBlock(pExprBlock);
			} else {
				pExprFunc = new Expr_Function(elem2.GetExpr(), NULL, pExprBlock);
			}
			if (!elem1.GetExpr()->IsFunction()) {
				SetError_InvalidElement(sig, __LINE__);
				return false;
			}
			Expr_Function *pExprFuncPrev =
							dynamic_cast<Expr_Function *>(elem1.GetExpr());
			pExprFuncPrev->GetLastSucceeding()->SetSucceeding(pExprFunc);
			pExpr = pExprFuncPrev;
		} else if (elem5.IsType(ETYPE_Comma) ||
					elem5.IsType(ETYPE_Semicolon) || elem5.IsType(ETYPE_EOL)) {
			// this is a special case of reducing
			DBGPARSER(::_tprintf(_T("Reduce: Expr Expr '{' -> Expr Expr '{' Expr ','\n")));
			if (pExprBlock == NULL) {
				pExprBlock = new Expr_Block();
				elem3.SetExpr(pExprBlock);
			}
			pExprBlock->AddExpr(elem4.GetExpr());
			_elemStack.pop_back();
			_elemStack.pop_back();
			return true;
		} else {
			SetError_InvalidElement(sig, __LINE__);
			return false;
		}
	} else {
		SetError_InvalidElement(sig, __LINE__);
		return false;
	}
	_elemStack.pop_back();
	_elemStack.pop_back();
	_elemStack.pop_back();
	_elemStack.pop_back();
	_elemStack.pop_back();
	pExpr->SetLineNo(GetLineNo());
	_elemStack.push_back(Element(ETYPE_Expr, pExpr));
	return true;
}

void Parser::SetError(Signal sig, const TCHAR *format, ...)
{
	TCHAR textPre[256];
	::_stprintf(textPre, _T("%d:"), GetLineNo());
	va_list list;
	va_start(list, format);
	sig.SetErrorV(ERR_SyntaxError, format, list, textPre);
	va_end(list);
}

void Parser::SetError_InvalidElement(Signal sig)
{
	SetError(sig, _T("invalid element"));
}

void Parser::SetError_InvalidElement(Signal sig, int lineno)
{
	SetError(sig, _T("invalid element (%d) .. %s"), lineno,
										_elemStack.ToString().c_str());
}

//-----------------------------------------------------------------------------
// Parser::ElementStack
//-----------------------------------------------------------------------------
Parser::ElementStack::reverse_iterator
					Parser::ElementStack::SeekTerminal(reverse_iterator p)
{
	for ( ; p->IsType(ETYPE_Expr); p++) ;
	return p;
}

void Parser::ElementStack::Clear()
{
	foreach (ElementStack, pElem, *this) {
		Expr::Delete(pElem->GetExpr());
	}
	clear();
}

String Parser::ElementStack::ToString() const
{
	String rtn;
	foreach_const (ElementStack, pElement, *this) {
		if (pElement != begin()) rtn.append(_T(" "));
		rtn.append(pElement->GetTypeSymbol());
	}
	return rtn;
}

//-----------------------------------------------------------------------------
// Parser::Element
//-----------------------------------------------------------------------------
const Parser::ElemTypeInfo Parser::Element::_elemTypeInfoTbl[] = {
	{ ETYPE_Begin,			_T("Begin"),			_T("[Bgn]")	},
	{ ETYPE_Number,			_T("Number"),			_T("[Num]")	},
	{ ETYPE_ImagNumber,		_T("ImagNumber"),		_T("j")		},
	{ ETYPE_Quote,			_T("Quote"),			_T("`")		},
	{ ETYPE_Force,			_T("Force"),			_T("!!")	},
	{ ETYPE_Question,		_T("Question"),			_T("?")		},
	{ ETYPE_Plus,			_T("Plus"),				_T("+")		},
	{ ETYPE_Minus,			_T("Minus"),			_T("-")		},
	{ ETYPE_Multiply,		_T("Multiply"),			_T("*")		},
	{ ETYPE_Divide,			_T("Divide"),			_T("/")		},
	{ ETYPE_Modulo,			_T("Modulo"),			_T("%")		},
	{ ETYPE_Power,			_T("Power"),			_T("**")	},
	{ ETYPE_Or,				_T("Or"),				_T("|")		},
	{ ETYPE_And,			_T("And"),				_T("&")		},
	{ ETYPE_Xor,			_T("Xor"),				_T("^")		},
	{ ETYPE_Invert,			_T("Invert"),			_T("~")		},
	{ ETYPE_Equal,			_T("Equal"),			_T("==")	},
	{ ETYPE_NotEqual,		_T("NotEqual"),			_T("!=")	},
	{ ETYPE_Less,			_T("Less"),				_T("<")		},
	{ ETYPE_Greater,		_T("Greater"),			_T(">")		},
	{ ETYPE_LessEq,			_T("LessEq"),			_T(">=")	},
	{ ETYPE_GreaterEq,		_T("GreaterEq"),		_T("<=")	},
	{ ETYPE_Compare,		_T("Compare"),			_T("<=>")	},
	{ ETYPE_ContainCheck,	_T("ContainCheck"),		_T("in")	},
	{ ETYPE_Assign,			_T("Assign"),			_T("=")		},
	{ ETYPE_AssignPlus,		_T("AssignPlus"),		_T("+=")	},
	{ ETYPE_AssignMinus,	_T("AssignMinus"),		_T("-=")	},
	{ ETYPE_AssignMultiply,	_T("AssignMultiply"),	_T("*=")	},
	{ ETYPE_AssignDivide,	_T("AssignDivide"),		_T("/=")	},
	{ ETYPE_AssignModulo,	_T("AssignModulo"),		_T("%=")	},
	{ ETYPE_AssignPower,	_T("AssignPower"),		_T("**=")	},
	{ ETYPE_AssignBitOr,	_T("AssignBitOr"),		_T("|=")	},
	{ ETYPE_AssignBitAnd,	_T("AssignBitAnd"),		_T("&=")	},
	{ ETYPE_AssignBitXor,	_T("AssignBitXor"),		_T("^=")	},
	{ ETYPE_DictAssign,		_T("DictAssign"),		_T("=>")	},
	{ ETYPE_OrOr,			_T("OrOr"),				_T("||")	},
	{ ETYPE_AndAnd,			_T("AndAnd"),			_T("&&")	},
	{ ETYPE_Not,			_T("Not"),				_T("!")		},
	{ ETYPE_Colon,			_T("Colon"),			_T(":")		},
	{ ETYPE_ColonColon,		_T("ColonColon"),		_T("::")	},
	{ ETYPE_Sequence,		_T("Sequence"),			_T("..")	},
	{ ETYPE_Comma,			_T("Comma"),			_T(",")		},
	{ ETYPE_Semicolon,		_T("Semicolon"),		_T(";")		},
	{ ETYPE_Dot,			_T("Dot"),				_T(".")		},
	{ ETYPE_LParenthesis,	_T("LParenthesis"),		_T("(")		},
	{ ETYPE_RParenthesis,	_T("RParenthesis"),		_T(")")		},
	{ ETYPE_LBrace,			_T("LBrace"),			_T("{")		},
	{ ETYPE_RBrace,			_T("RBrace"),			_T("}")		},
	{ ETYPE_LBracket,		_T("LBracket"),			_T("[")		},
	{ ETYPE_RBracket,		_T("RBracket"),			_T("]")		},
	{ ETYPE_LBlockParam,	_T("LBlockParam"),		_T("|")		},
	{ ETYPE_RBlockParam,	_T("RBlockParam"),		_T("|")		},
	{ ETYPE_EOL,			_T("EOL"),				_T("[EOL]")	},
	{ ETYPE_EOF,			_T("EOF"),				_T("[EOF]")	},
	{ ETYPE_Symbol,			_T("Symbol"),			_T("[Sym]")	},
	{ ETYPE_String,			_T("String"),			_T("[Str]")	},
	{ ETYPE_Expr,			_T("Expr"),				_T("[Expr]")},
};

Number Parser::Element::GetNumber() const
{
	if (_str.size() > 2 && _str[0] == _T('0') &&
			(_str[1] == _T('x') || _str[1] == _T('X') || IsOctDigit(_str[1]))) {
		return ::_tcstoul(_str.c_str(), NULL, 0);
	} else {
		return ::_tcstod(_str.c_str(), NULL);
	}
}

const TCHAR *Parser::Element::GetTypeName() const
{
	for (int i = 0; i < NUMBEROF(_elemTypeInfoTbl); i++) {
		if (_elemTypeInfoTbl[i].elemType == _elemType) {
			return _elemTypeInfoTbl[i].name;
		}
	}
	return _T("unknown");
}

const TCHAR *Parser::Element::GetTypeSymbol() const
{
	for (int i = 0; i < NUMBEROF(_elemTypeInfoTbl); i++) {
		if (_elemTypeInfoTbl[i].elemType == _elemType) {
			return _elemTypeInfoTbl[i].symbol;
		}
	}
	return _T("unknown");
}

}
