content: /*******************************************************************************
  * Copyright (c) 2009 Luaj.org. All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  * copies of the Software, and to permit persons to whom the Software is
  * furnished to do so, subject to the following conditions:
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  ******************************************************************************/
  package org.luaj.vm2.compiler;
  
  //TODO 与3.0不一样
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.Reader;
  import java.util.Hashtable;
  
  import org.luaj.vm2.LocVars;
  import org.luaj.vm2.Lua;
  import org.luaj.vm2.LuaError;
  import org.luaj.vm2.LuaInteger;
  import org.luaj.vm2.LuaString;
  import org.luaj.vm2.LuaValue;
  import org.luaj.vm2.Prototype;
  import org.luaj.vm2.compiler.FuncState.BlockCnt;
  import org.luaj.vm2.lib.MathLib;
  
  
  public class LexState {
  
  	protected static final String RESERVED_LOCAL_VAR_FOR_CONTROL = "(for control)";
      protected static final String RESERVED_LOCAL_VAR_FOR_STATE = "(for state)";
      protected static final String RESERVED_LOCAL_VAR_FOR_GENERATOR = "(for generator)";
      protected static final String RESERVED_LOCAL_VAR_FOR_STEP = "(for step)";
      protected static final String RESERVED_LOCAL_VAR_FOR_LIMIT = "(for limit)";
      protected static final String RESERVED_LOCAL_VAR_FOR_INDEX = "(for index)";
  
      // keywords array
      protected static final String[] RESERVED_LOCAL_VAR_KEYWORDS = new String[] {
          RESERVED_LOCAL_VAR_FOR_CONTROL,
          RESERVED_LOCAL_VAR_FOR_GENERATOR,
          RESERVED_LOCAL_VAR_FOR_INDEX,
          RESERVED_LOCAL_VAR_FOR_LIMIT,
          RESERVED_LOCAL_VAR_FOR_STATE,
          RESERVED_LOCAL_VAR_FOR_STEP
      };
      private static final Hashtable RESERVED_LOCAL_VAR_KEYWORDS_TABLE = new Hashtable();
      static {
      	for ( int i=0; i<RESERVED_LOCAL_VAR_KEYWORDS.length; i++ )
          	RESERVED_LOCAL_VAR_KEYWORDS_TABLE.put( RESERVED_LOCAL_VAR_KEYWORDS[i], Boolean.TRUE );
      }
  
      private static final int EOZ    = (-1);
  	private static final int MAX_INT = Integer.MAX_VALUE-2;
  	private static final int UCHAR_MAX = 255; // TODO, convert to unicode CHAR_MAX?
  	private static final int LUAI_MAXCCALLS = 200;
  
  	private static final String LUA_QS(String s) { return "'"+s+"'"; }
  	private static final String LUA_QL(Object o) { return LUA_QS(String.valueOf(o)); }
  
  	private static final int     LUA_COMPAT_LSTR   =    1; // 1 for compatibility, 2 for old behavior
  	private static final boolean LUA_COMPAT_VARARG = true;
  
      public static boolean isReservedKeyword(String varName) {
      	return RESERVED_LOCAL_VAR_KEYWORDS_TABLE.containsKey(varName);
      }
  
  	/*
  	** Marks the end of a patch list. It is an invalid value both as an absolute
  	** address, and as a list link (would link an element to itself).
  	*/
  	static final int NO_JUMP = (-1);
  
  	/*
  	** grep "ORDER OPR" if you change these enums
  	*/
  	static final int
  	  OPR_ADD=0, OPR_SUB=1, OPR_MUL=2, OPR_DIV=3, OPR_MOD=4, OPR_POW=5,
  	  OPR_CONCAT=6,
  	  OPR_NE=7, OPR_EQ=8,
  	  OPR_LT=9, OPR_LE=10, OPR_GT=11, OPR_GE=12,
  	  OPR_AND=13, OPR_OR=14,
  	  OPR_NOBINOPR=15;
  
  	static final int
  		OPR_MINUS=0, OPR_NOT=1, OPR_LEN=2, OPR_NOUNOPR=3;
  
  	/* exp kind */
  	static final int
  	  VVOID = 0,	/* no value */
  	  VNIL = 1,
  	  VTRUE = 2,
  	  VFALSE = 3,
  	  VK = 4,		/* info = index of constant in `k' */
  	  VKNUM = 5,	/* nval = numerical value */
  	  VNONRELOC = 6,	/* info = result register */
  	  VLOCAL = 7,	/* info = local register */
  	  VUPVAL = 8,       /* info = index of upvalue in `upvalues' */
  	  VINDEXED = 9,	/* info = table register, aux = index register (or `k') */
  	  VJMP = 10,		/* info = instruction pc */
  	  VRELOCABLE = 11,	/* info = instruction pc */
  	  VCALL = 12,	/* info = instruction pc */
  	  VVARARG = 13;	/* info = instruction pc */
  
  	/* semantics information */
  	private static class SemInfo {
  		LuaValue r;
  		LuaString ts;
  	};
  
  	private static class Token {
  		int token;
  		final SemInfo seminfo = new SemInfo();
  		public void set(Token other) {
  			this.token = other.token;
  			this.seminfo.r = other.seminfo.r;
  			this.seminfo.ts = other.seminfo.ts;
  		}
  	};
  
  	int current;  /* current character (charint) */
  	int linenumber;  /* input line counter */
  	int lastline;  /* line of last token `consumed' */
  	final Token t = new Token();  /* current token */
  	final Token lookahead = new Token();  /* look ahead token */
  	final Token lookahead2 = new Token();  /* look ahead token */
  	FuncState fs;  /* `FuncState' is private to the parser */
  	LuaC L;
  	InputStream z;  /* input stream */
  	char[] buff;  /* buffer for tokens */
  	int nbuff; /* length of buffer */
  	Dyndata dyd = new Dyndata();  /* dynamic structures used by the parser */
  	LuaString source;  /* current source name */
  	LuaString envn;  /* environment variable name */
  	byte decpoint;  /* locale decimal point */
  
  	/* ORDER RESERVED */
  	final static String luaX_tokens [] = {
  	    "and", "break", "do", "else", "elseif",
  	    "end", "false", "for", "function", "goto", "if",
  	    "in", "local", "nil", "not", "or", "repeat",
  	    "return", "then", "true", "until", "while",
  	    "..", "...", "==", ">=", "<=", "~=",
  	    "::", "<eos>", "<number>", "<name>", "<string>", "<eof>",
  	};
  
  	final static int
  		/* terminal symbols denoted by reserved words */
  		TK_AND=257,  TK_BREAK=258, TK_DO=259, TK_ELSE=260, TK_ELSEIF=261,
  		TK_END=262, TK_FALSE=263, TK_FOR=264, TK_FUNCTION=265, TK_GOTO=266, TK_IF=267,
  		TK_IN=268, TK_LOCAL=269, TK_NIL=270, TK_NOT=271, TK_OR=272, TK_REPEAT=273,
  		TK_RETURN=274, TK_THEN=275, TK_TRUE=276, TK_UNTIL=277, TK_WHILE=278,
  		/* other terminal symbols */
  		TK_CONCAT=279, TK_DOTS=280, TK_EQ=281, TK_GE=282, TK_LE=283, TK_NE=284,
  		TK_DBCOLON=285, TK_EOS=286, TK_NUMBER=287, TK_NAME=288, TK_STRING=289;
  
  	final static int FIRST_RESERVED = TK_AND;
  	final static int NUM_RESERVED = TK_WHILE+1-FIRST_RESERVED;
  
  	final static Hashtable RESERVED = new Hashtable();
  	static {
  		for ( int i=0; i<NUM_RESERVED; i++ ) {
  			LuaString ts = (LuaString) LuaValue.valueOf( luaX_tokens[i] );
  			RESERVED.put(ts, new Integer(FIRST_RESERVED+i));
  		}
  	}
  
  	private boolean isalnum(int c) {
  		return (c >= '0' && c <= '9')
  			|| (c >= 'a' && c <= 'z')
  			|| (c >= 'A' && c <= 'Z')
  			|| (c == '_');
  		// return Character.isLetterOrDigit(c);
  	}
  
  	private boolean isalpha(int c) {
  		return (c >= 'a' && c <= 'z')
  			|| (c >= 'A' && c <= 'Z');
  	}
  
  	private boolean isdigit(int c) {
  		return (c >= '0' && c <= '9');
  	}
  
  	private boolean isxdigit(int c) {
  		return (c >= '0' && c <= '9')
  				|| (c >= 'a' && c <= 'f')
  				|| (c >= 'A' && c <= 'F');
  	}
  
  	private boolean isspace(int c) {
  		return (c <= ' ');
  	}
  
      //是否标准语法
      private boolean standardSyntax = true;
  
  	public LexState(LuaC state, InputStream stream, boolean standardSyntax) {
  		this.z = stream;
  		this.buff = new char[32];
  		this.L = state;
          this.standardSyntax = standardSyntax;
  	}
  
  	void nextChar() {
  		try {
   			current = z.read();
  		} catch ( IOException e ) {
  			e.printStackTrace();
  			current = EOZ;
  		}
  	}
  
  	boolean currIsNewline() {
  		return current == '\n' || current == '\r';
  	}
  
  	void save_and_next() {
  		save( current );
  		nextChar();
  	}
  
  	void save(int c) {
  		if ( buff == null || nbuff + 1 > buff.length )
  			buff = LuaC.realloc( buff, nbuff*2+1 );
  		buff[nbuff++] = (char) c;
  	}
  
  
  	String token2str( int token ) {
  		if ( token < FIRST_RESERVED ) {
  			return iscntrl(token)?
  					L.pushfstring( "char("+((int)token)+")" ):
  					L.pushfstring( String.valueOf( (char) token ) );
  		} else {
  			return luaX_tokens[token-FIRST_RESERVED];
  		}
  	}
  
  	private static boolean iscntrl(int token) {
  		return token < ' ';
  	}
  
  	String txtToken(int token) {
  		switch ( token ) {
  		case TK_NAME:
  		case TK_STRING:
  		case TK_NUMBER:
  			return new String( buff, 0, nbuff );
  		default:
  			return token2str( token );
  		}
  	}
  
  	void lexerror( String msg, int token ) {
  		String cid = Lua.chunkid( source.tojstring() );
  		L.pushfstring( cid+":"+linenumber+": "+msg );
  		if ( token != 0 )
  			L.pushfstring( "syntax error: "+msg+" near "+txtToken(token) );
  //		throw new LuaError(cid+":"+linenumber+": "+msg);
  		throw new LuaError(cid+":"+linenumber+": "+msg+" near "+txtToken(token));//modified by song
  	}
  
  	void syntaxerror( String msg ) {
  		lexerror( msg, t.token );
  	}
  
  	// only called by new_localvarliteral() for var names.
  	LuaString newstring( String s ) {
  		return L.newTString(s);
  	}
  
  	LuaString newstring( char[] chars, int offset, int len ) {
  		return L.newTString(new String(chars, offset, len));
  	}
  
  	void inclinenumber() {
  		int old = current;
  		LuaC._assert( currIsNewline() );
  		nextChar(); /* skip '\n' or '\r' */
  		if ( currIsNewline() && current != old )
  			nextChar(); /* skip '\n\r' or '\r\n' */
  		if ( ++linenumber >= MAX_INT )
  			syntaxerror("chunk has too many lines");
  	}
  
  	void setinput( LuaC L, int firstByte, InputStream z, LuaString source ) {
  		this.decpoint = '.';
  		this.L = L;
  		this.lookahead.token = TK_EOS; /* no look-ahead token */
  		this.lookahead2.token = TK_EOS;
  		this.z = z;
  		this.fs = null;
  		this.linenumber = 1;
  		this.lastline = 1;
  		this.source = source;
  		this.envn = LuaValue.ENV;  /* environment variable name */
  		this.nbuff = 0;   /* initialize buffer */
  		this.current = firstByte; /* read first char */
  		this.skipShebang();
  	}
  
  	private void skipShebang() {
  		if ( current == '#' )
  			while (!currIsNewline() && current != EOZ)
  				nextChar();
  	}
  	
  
  
  	/*
  	** =======================================================
  	** LEXICAL ANALYZER
  	** =======================================================
  	*/
  
  
  	boolean check_next(String set) {
  		if (set.indexOf(current) < 0)
  			return false;
  		save_and_next();
  		return true;
  	}
  
  	void buffreplace(char from, char to) {
  		int n = nbuff;
  		char[] p = buff;
  		while ((--n) >= 0)
  			if (p[n] == from)
  				p[n] = to;
  	}
  
  	LuaValue strx2number(String str, SemInfo seminfo) {
  		char[] c = str.toCharArray();
  		int s = 0;
  		while ( s < c.length && isspace(c[s]))
  			++s;
  		// Check for negative sign
  		double sgn = 1.0;
  		if (s < c.length && c[s] == '-') {
  			sgn = -1.0;
  			++s;
  		}
  		/* Check for "0x" */
  		if (s + 2 >= c.length )
  			return LuaValue.ZERO;
  		if (c[s++] != '0')
  			return LuaValue.ZERO;
  		if (c[s] != 'x' && c[s] != 'X')
  			return LuaValue.ZERO;
  		++s;
  
  		// read integer part.
  		double m = 0;
  		int e = 0;
  		while (s < c.length && isxdigit(c[s]))
  			m = (m * 16) + hexvalue(c[s++]);
  		if (s < c.length && c[s] == '.') {
  			++s;  // skip dot
  			while (s < c.length && isxdigit(c[s])) {
  				m = (m * 16) + hexvalue(c[s++]);
  				e -= 4;  // Each fractional part shifts right by 2^4
  			}
  		}
  		if (s < c.length && (c[s] == 'p' || c[s] == 'P')) {
  			++s;
  			int exp1 = 0;
  			boolean neg1 = false;
  			if (s < c.length && c[s] == '-') {
  				neg1 = true;
  				++s;
  			}
  			while (s < c.length && isdigit(c[s]))
  				exp1 = exp1 * 10 + c[s++] - '0';
  			if (neg1)
  				exp1 = -exp1;
  			e += exp1;
  		}
  		return LuaValue.valueOf(sgn * m * MathLib.dpow_d(2.0, e));
  	}
  
  	boolean str2d(String str, SemInfo seminfo) {
  		if (str.indexOf('n')>=0 || str.indexOf('N')>=0)
  			seminfo.r = LuaValue.ZERO;
  		else if (str.indexOf('x')>=0 || str.indexOf('X')>=0)
  			seminfo.r = strx2number(str, seminfo);
  		else
  			seminfo.r = LuaValue.valueOf(Double.parseDouble(str.trim()));
  		return true;
  	}
  
  	void read_numeral(SemInfo seminfo) {
  		String expo = "Ee";
  		int first = current;
  		LuaC._assert (isdigit(current));
  		save_and_next();
  		if (first == '0' && check_next("Xx"))
  			expo = "Pp";
  		while (true) {
  			if (check_next(expo))
  				check_next("+-");
  			if(isxdigit(current) || current == '.')
  				save_and_next();
  			else
  				break;
  		}
  		save('\0');
  		String str = new String(buff, 0, nbuff);
  		str2d(str, seminfo);
  	}
  
  	int skip_sep() {
  		int count = 0;
  		int s = current;
  		LuaC._assert (s == '[' || s == ']');
  		save_and_next();
  		while (current == '=') {
  			save_and_next();
  			count++;
  		}
  		return (current == s) ? count : (-count) - 1;
  	}
  
  	void read_long_string(SemInfo seminfo, int sep) {
  		int cont = 0;
  		save_and_next(); /* skip 2nd `[' */
  		if (currIsNewline()) /* string starts with a newline? */
  			inclinenumber(); /* skip it */
  		for (boolean endloop = false; !endloop;) {
  			switch (current) {
  			case EOZ:
  				lexerror((seminfo != null) ? "unfinished long string"
  						: "unfinished long comment", TK_EOS);
  				break; /* to avoid warnings */
  			case '[': {
  				if (skip_sep() == sep) {
  					save_and_next(); /* skip 2nd `[' */
  					cont++;
  					if (LUA_COMPAT_LSTR == 1) {
  						if (sep == 0)
  							lexerror("nesting of [[...]] is deprecated", '[');
  					}
  				}
  				break;
  			}
  			case ']': {
  				if (skip_sep() == sep) {
  					save_and_next(); /* skip 2nd `]' */
  					if (LUA_COMPAT_LSTR == 2) {
  						cont--;
  						if (sep == 0 && cont >= 0)
  							break;
  					}
  					endloop = true;
  				}
  				break;
  			}
  			case '\n':
  			case '\r': {
  				save('\n');
  				inclinenumber();
  				if (seminfo == null)
  					nbuff = 0; /* avoid wasting space */
  				break;
  			}
  			default: {
  				if (seminfo != null)
  					save_and_next();
  				else
  					nextChar();
  			}
  			}
  		}
  		if (seminfo != null)
  			seminfo.ts =  L.newTString(LuaString.valueOf(buff, 2 + sep, nbuff - 2 * (2 + sep)));
  	}
  
  	int hexvalue(int c) {
  		return c <= '9'? c - '0': c <= 'F'? c + 10 - 'A': c + 10 - 'a';
  	}
  
  	int readhexaesc() {
  		nextChar();
  		int c1 = current;
  		nextChar();
  		int c2 = current;
  		if (!isxdigit(c1) || !isxdigit(c2))
  			lexerror("hexadecimal digit expected 'x"+((char)c1)+((char)c2), TK_STRING);
  		return (hexvalue(c1) << 4) + hexvalue(c2);
  	}
  
  	void read_string(int del, SemInfo seminfo) {
  		save_and_next();
  		while (current != del) {
  			switch (current) {
  			case EOZ:
  				lexerror("unfinished string", TK_EOS);
  				continue; /* to avoid warnings */
  			case '\n':
  			case '\r':
  				lexerror("unfinished string", TK_STRING);
  				continue; /* to avoid warnings */
  			case '\\': {
  				int c;
  				nextChar(); /* do not save the `\' */
  				switch (current) {
  				case 'a': /* bell */
  					c = '\u0007';
  					break;
  				case 'b': /* backspace */
  					c = '\b';
  					break;
  				case 'f': /* form feed */
  					c = '\f';
  					break;
  				case 'n': /* newline */
  					c = '\n';
  					break;
  				case 'r': /* carriage return */
  					c = '\r';
  					break;
  				case 't': /* tab */
  					c = '\t';
  					break;
  				case 'v': /* vertical tab */
  					c = '\u000B';
  					break;
  				case 'x':
  					c = readhexaesc();
  					break;
  				case '\n': /* go through */
  				case '\r':
  					save('\n');
  					inclinenumber();
  					continue;
  				case EOZ:
  					continue; /* will raise an error next loop */
  		        case 'z': {  /* zap following span of spaces */
  		              nextChar();  /* skip the 'z' */
  		              while (isspace(current)) {
  		            	  if (currIsNewline()) inclinenumber();
  		            	  else nextChar();
  		              }
  		              continue;
  		        }
  				default: {
  					if (!isdigit(current))
  						save_and_next(); /* handles \\, \", \', and \? */
  					else { /* \xxx */
  						int i = 0;
  						c = 0;
  						do {
  							c = 10 * c + (current - '0');
  							nextChar();
  						} while (++i < 3 && isdigit(current));
  						if (c > UCHAR_MAX)
  							lexerror("escape sequence too large", TK_STRING);
  						save(c);
  					}
  					continue;
  				}
  				}
  				save(c);
  				nextChar();
  				continue;
  			}
  			default:
  				save_and_next();
  			}
  		}
  		save_and_next(); /* skip delimiter */
  		seminfo.ts = L.newTString(LuaString.valueOf(buff, 1, nbuff-2));
  	}
  
  	int llex(SemInfo seminfo) {
  		nbuff = 0;
  		while (true) {
  			switch (current) {
  			case '\n':
  			case '\r': {
  				inclinenumber();
  				continue;
  			}
  			case '-': {
  				nextChar();
  				if (current != '-')
  					return '-';
  				/* else is a comment */
  				nextChar();
  				if (current == '[') {
  					int sep = skip_sep();
  					nbuff = 0; /* `skip_sep' may dirty the buffer */
  					if (sep >= 0) {
  						read_long_string(null, sep); /* long comment */
  						nbuff = 0;
  						continue;
  					}
  				}
  				/* else short comment */
  				while (!currIsNewline() && current != EOZ)
  					nextChar();
  				continue;
  			}
  			case '[': {
  				int sep = skip_sep();
  				if (sep >= 0) {
  					read_long_string(seminfo, sep);
  					return TK_STRING;
  				} else if (sep == -1)
  					return '[';
  				else
  					lexerror("invalid long string delimiter", TK_STRING);
  			}
  			case '=': {
  				nextChar();
  				if (current != '=')
  					return '=';
  				else {
  					nextChar();
  					return TK_EQ;
  				}
  			}
  			case '<': {
  				nextChar();
  				if (current != '=')
  					return '<';
  				else {
  					nextChar();
  					return TK_LE;
  				}
  			}
  			case '>': {
  				nextChar();
  				if (current != '=')
  					return '>';
  				else {
  					nextChar();
  					return TK_GE;
  				}
  			}
  			case '~': {
  				nextChar();
  				if (current != '=')
  					return '~';
  				else {
  					nextChar();
  					return TK_NE;
  				}
  			}
  			case ':': {
  				nextChar();
  				if (current != ':')
  					return ':';
  				else {
  					nextChar();
  					return TK_DBCOLON;
  				}
  			}
  			case '"':
  			case '\'': {
  				read_string(current, seminfo);
  				return TK_STRING;
  			}
  			case '.': {
  				save_and_next();
  				if (check_next(".")) {
  					if (check_next("."))
  						return TK_DOTS; /* ... */
  					else
  						return TK_CONCAT; /* .. */
  				} else if (!isdigit(current))
  					return '.';
  				else {
  					read_numeral(seminfo);
  					return TK_NUMBER;
  				}
  			}
  		    case '0': case '1': case '2': case '3': case '4':
  		    case '5': case '6': case '7': case '8': case '9': {
  		        read_numeral(seminfo);
  		        return TK_NUMBER;
  		    }
  		 	case EOZ: {
  				return TK_EOS;
  			}
  			default: {
  				if (isspace(current)) {
  					LuaC._assert (!currIsNewline());
  					nextChar();
  					continue;
  				} else if (isdigit(current)) {
  					read_numeral(seminfo);
  					return TK_NUMBER;
  				} else if (isalpha(current) || current == '_') {
  					/* identifier or reserved word */
  					LuaString ts;
  					do {
  						save_and_next();
  					} while (isalnum(current) || current == '_');
  					ts = newstring(buff, 0, nbuff);
  					if ( RESERVED.containsKey(ts) )
  						return ((Integer)RESERVED.get(ts)).intValue();
  					else {
  						seminfo.ts = ts;
  						return TK_NAME;
  					}
  				} else {
  					int c = current;
  					nextChar();
  					return c; /* single-char tokens (+ - / ...) */
  				}
  			}
  			}
  		}
  	}
  
  	void next() {
  		lastline = linenumber;
  		if (lookahead.token != TK_EOS) { /* is there a look-ahead token? */
  			t.set(lookahead); /* use this one */
  			lookahead.token = TK_EOS; /* and discharge it */
  
  			lookahead.set(lookahead2);
  			lookahead2.token = TK_EOS;
  		} else {
  			t.token = llex(t.seminfo); /* read next token */
  		}
  	}
  
  	void lookahead() {
  		if (lookahead.token == TK_EOS) {
  			lookahead.token = llex(lookahead.seminfo);
  		}
  		if (lookahead2.token == TK_EOS) {
  			lookahead2.token = llex(lookahead2.seminfo);
  		}
  	}
  
  	// =============================================================
  	// from lcode.h
  	// =============================================================
  
  
  	// =============================================================
  	// from lparser.c
  	// =============================================================
  
  	static final boolean vkisvar(final int k) {
  		return (VLOCAL <= (k) && (k) <= VINDEXED);
  	}
  
  	static final boolean vkisinreg(final int k) {
  		return ((k) == VNONRELOC || (k) == VLOCAL);
  	}
  
  	static class expdesc {
  		int k; // expkind, from enumerated list, above
  		static class U { // originally a union
  			short ind_idx; // index (R/K)
  			short ind_t; // table(register or upvalue)
  			short ind_vt; // whether 't' is register (VLOCAL) or (UPVALUE)
  			private LuaValue _nval;
  			int info;
  			public void setNval(LuaValue r) {
  				_nval = r;
  			}
  			public LuaValue nval() {
  				return (_nval == null? LuaInteger.valueOf(info): _nval);
  			}
  		};
  		final U u = new U();
  		final IntPtr t = new IntPtr(); /* patch list of `exit when true' */
  		final IntPtr f = new IntPtr(); /* patch list of `exit when false' */
  		void init( int k, int i ) {
  			this.f.i = NO_JUMP;
  			this.t.i = NO_JUMP;
  			this.k = k;
  			this.u.info = i;
  		}
  
  		boolean hasjumps() {
  			return (t.i != f.i);
  		}
  
  		boolean isnumeral() {
  			return (k == VKNUM && t.i == NO_JUMP && f.i == NO_JUMP);
  		}
  
  		public void setvalue(expdesc other) {
  			this.f.i = other.f.i;
  			this.k = other.k;
  			this.t.i = other.t.i;
  			this.u._nval = other.u._nval;
  			this.u.ind_idx = other.u.ind_idx;
  			this.u.ind_t = other.u.ind_t;
  			this.u.ind_vt = other.u.ind_vt;
  			this.u.info = other.u.info;
  		}
  	}
  
  
  	/* description of active local variable */
  	static class Vardesc {
  		final short idx;  /* variable index in stack */
  		Vardesc(int idx) {
  			this.idx = (short) idx;
  		}
  	};
  
  
  	/* description of pending goto statements and label statements */
  	static class Labeldesc {
  		LuaString name;  /* label identifier */
  		int pc;  /* position in code */
  		int line;  /* line where it appeared */
  		short nactvar;  /* local level where it appears in current block */
  		public Labeldesc(LuaString name, int pc, int line, short nactvar) {
  			this.name = name;
  			this.pc = pc;
  			this.line = line;
  			this.nactvar = nactvar;
  		}
  	};
  
  
  	/* dynamic structures used by the parser */
  	static class Dyndata {
  		Vardesc[] actvar;  /* list of active local variables */
  		int n_actvar = 0;
  		Labeldesc[] gt;  /* list of pending gotos */
  		int n_gt = 0;
  		Labeldesc[] label;   /* list of active labels */
  		int n_label = 0;
  	};
  
  
  	boolean hasmultret(int k) {
  		return ((k) == VCALL || (k) == VVARARG);
  	}
  
  	/*----------------------------------------------------------------------
  	name		args	description
  	------------------------------------------------------------------------*/
  
  	void anchor_token () {
  		/* last token from outer function must be EOS */
  		LuaC._assert(fs != null || t.token == TK_EOS);
  		if (t.token == TK_NAME || t.token == TK_STRING) {
  			LuaString ts = t.seminfo.ts;
  			// TODO: is this necessary?
  			L.cachedLuaString(t.seminfo.ts);
  		}
  	}
  
  	/* semantic error */
  	void semerror (String msg) {
  		t.token = 0;  /* remove 'near to' from final message */
  		syntaxerror(msg);
  	}
  
  	void error_expected(int token) {
  		syntaxerror(L.pushfstring(LUA_QS(token2str(token)) + " expected"));
  	}
  
  	boolean testnext(int c) {
  		if (t.token == c) {
  			next();
  			return true;
  		} else
  			return false;
  	}
  
  	void check(int c) {
  		if (t.token != c)
  			error_expected(c);
  	}
  
  	void checknext (int c) {
  	  check(c);
  	  next();
  	}
  
  	void check_condition(boolean c, String msg) {
  		if (!(c))
  			syntaxerror(msg);
  	}
  
  
  	void check_match(int what, int who, int where) {
  		if (!testnext(what)) {
  			if (where == linenumber)
  				error_expected(what);
  			else {
  				syntaxerror(L.pushfstring(LUA_QS(token2str(what))
  						+ " expected " + "(to close " + LUA_QS(token2str(who))
  						+ " at line " + where + ")"));
  			}
  		}
  	}
  
  	LuaString str_checkname() {
  		LuaString ts;
  		check(TK_NAME);
  		ts = t.seminfo.ts;
  		next();
  		return ts;
  	}
  
  	void codestring(expdesc e, LuaString s) {
  		e.init(VK, fs.stringK(s));
  	}
  
  	void checkname(expdesc e) {
  		codestring(e, str_checkname());
  	}
  
  
  	int registerlocalvar(LuaString varname) {
  		FuncState fs = this.fs;
  		Prototype f = fs.f;
  		if (f.locvars == null || fs.nlocvars + 1 > f.locvars.length)
  			f.locvars = LuaC.realloc( f.locvars, fs.nlocvars*2+1 );
  		f.locvars[fs.nlocvars] = new LocVars(varname,0,0);
  		return fs.nlocvars++;
  	}
  
  	void new_localvar(LuaString name) {
  		int reg = registerlocalvar(name);
  		fs.checklimit(dyd.n_actvar + 1, FuncState.LUAI_MAXVARS, "local variables");
  		if (dyd.actvar == null || dyd.n_actvar + 1 > dyd.actvar.length)
  			dyd.actvar = LuaC.realloc(dyd.actvar, Math.max(1, dyd.n_actvar * 2));
  		dyd.actvar[dyd.n_actvar++] = new Vardesc(reg);
  	}
  
  	void new_localvarliteral(String v) {
  		LuaString ts = newstring(v);
  		new_localvar(ts);
  	}
  
  	void adjustlocalvars(int nvars) {
  		FuncState fs = this.fs;
  		fs.nactvar = (short) (fs.nactvar + nvars);
  		for (; nvars > 0; nvars--) {
  			fs.getlocvar(fs.nactvar - nvars).startpc = fs.pc;
  		}
  	}
  
  	void removevars(int tolevel) {
  		FuncState fs = this.fs;
  		while (fs.nactvar > tolevel)
  			fs.getlocvar(--fs.nactvar).endpc = fs.pc;
  	}
  
  	void singlevar(expdesc var) {
  		LuaString varname = this.str_checkname();
  		FuncState fs = this.fs;
  		if (FuncState.singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */
  			expdesc key = new expdesc();
  		    FuncState.singlevaraux(fs, this.envn, var, 1);  /* get environment variable */
  		    LuaC._assert(var.k == VLOCAL || var.k == VUPVAL);
  		    this.codestring(key, varname);  /* key is variable name */
  		    fs.indexed(var, key);  /* env[varname] */
  		}
  	}
  
  	void adjust_assign(int nvars, int nexps, expdesc e) {
  		FuncState fs = this.fs;
  		int extra = nvars - nexps;
  		if (hasmultret(e.k)) {
  			/* includes call itself */
  			extra++;
  			if (extra < 0)
  				extra = 0;
  			/* last exp. provides the difference */
  			fs.setreturns(e, extra);
  			if (extra > 1)
  				fs.reserveregs(extra - 1);
  		} else {
  			/* close last expression */
  			if (e.k != VVOID)
  				fs.exp2nextreg(e);
  			if (extra > 0) {
  				int reg = fs.freereg;
  				fs.reserveregs(extra);
  				fs.nil(reg, extra);
  			}
  		}
  	}
  
  	void enterlevel() {
  		if (++L.nCcalls > LUAI_MAXCCALLS)
  			lexerror("chunk has too many syntax levels", 0);
  	}
  
  	void leavelevel() {
  		L.nCcalls--;
  	}
  
  	void closegoto(int g, Labeldesc label) {
  		FuncState fs = this.fs;
  		Labeldesc[] gl = this.dyd.gt;
  		Labeldesc gt = gl[g];
  		LuaC._assert(gt.name.eq_b(label.name));
  		if (gt.nactvar < label.nactvar) {
  			LuaString vname = fs.getlocvar(gt.nactvar).varname;
  			String msg = L.pushfstring("<goto " + gt.name + "> at line "
  					+ gt.line + " jumps into the scope of local '"
  					+ vname.tojstring() + "'");
  			semerror(msg);
  		}
  		fs.patchlist(gt.pc, label.pc);
  		/* remove goto from pending list */
  		System.arraycopy(gl, g + 1, gl, g, this.dyd.n_gt - g - 1);
  		gl[--this.dyd.n_gt] = null;
  	}
  
  	/*
  	 ** try to close a goto with existing labels; this solves backward jumps
  	 */
  	boolean findlabel (int g) {
  		int i;
  		BlockCnt bl = fs.bl;
  		Dyndata dyd = this.dyd;
  		Labeldesc gt = dyd.gt[g];
  		/* check labels in current block for a match */
  		for (i = bl.firstlabel; i < dyd.n_label; i++) {
  			Labeldesc lb = dyd.label[i];
  			if (lb.name.eq_b(gt.name)) {  /* correct label? */
  				if (gt.nactvar > lb.nactvar &&
  						(bl.upval || dyd.n_label > bl.firstlabel))
  					fs.patchclose(gt.pc, lb.nactvar);
  				closegoto(g, lb);  /* close it */
  				return true;
  			}
  		}
  		return false;  /* label not found; cannot close goto */
  	}
  
  	/* Caller must LuaC.grow() the vector before calling this. */
  	int newlabelentry(Labeldesc[] l, int index, LuaString name, int line, int pc) {
  		l[index] = new Labeldesc(name, pc, line, fs.nactvar);
  		return index;
  	}
  
  	/*
  	 ** check whether new label 'lb' matches any pending gotos in current
  	 ** block; solves forward jumps
  	 */
  	void findgotos (Labeldesc lb) {
  		Labeldesc[] gl = dyd.gt;
  		int i = fs.bl.firstgoto;
  		while (i < dyd.n_gt) {
  			if (gl[i].name.eq_b(lb.name))
  				closegoto(i, lb);
  			else
  				i++;
  		}
  	}
  
  
  	/*
  	** create a label named "break" to resolve break statements
  	*/
  	void breaklabel () {
  		LuaString n = LuaString.valueOf("break");
  		int l = newlabelentry(dyd.label=LuaC.grow(dyd.label, dyd.n_label+1), dyd.n_label++, n, 0, fs.pc);
  		findgotos(dyd.label[l]);
  	}
  
  	/*
  	** generates an error for an undefined 'goto'; choose appropriate
  	** message when label name is a reserved word (which can only be 'break')
  	*/
  	void undefgoto (Labeldesc gt) {
  	  String msg = L.pushfstring(isReservedKeyword(gt.name.tojstring())
  	                    ? "<"+gt.name+"> at line "+gt.line+" not inside a loop"
  	                    : "no visible label '"+gt.name+"' for <goto> at line "+gt.line);
  	  semerror(msg);
  	}
  
  	Prototype addprototype () {
  	  Prototype clp;
  	  Prototype f = fs.f;  /* prototype of current function */
  	  if (f.p == null || fs.np >= f.p.length) {
  	    f.p = LuaC.realloc(f.p, Math.max(1, fs.np * 2));
  	  }
  	  f.p[fs.np++] = clp = new Prototype();
  	  return clp;
  	}
  
  	void codeclosure (expdesc v) {
  	  FuncState fs = this.fs.prev;
  	  v.init(VRELOCABLE, fs.codeABx(LuaC.OP_CLOSURE, 0, fs.np - 1));
  	  fs.exp2nextreg(v);  /* fix it at stack top (for GC) */
  	}
  
  	void open_func (FuncState fs, BlockCnt bl) {
  		  fs.prev = this.fs;  /* linked list of funcstates */
  		  fs.ls = this;
  		  this.fs = fs;
  		  fs.pc = 0;
  		  fs.lasttarget = -1;
  		  fs.jpc = new IntPtr( NO_JUMP );
  		  fs.freereg = 0;
  		  fs.nk = 0;
  		  fs.np = 0;
  		  fs.nups = 0;
  		  fs.nlocvars = 0;
  		  fs.nactvar = 0;
  		  fs.firstlocal = dyd.n_actvar;
  		  fs.bl = null;
  		  fs.f.source = this.source;
  		  fs.f.maxstacksize = 2;  /* registers 0/1 are always valid */
  		  fs.enterblock(bl,  false);
  	}
  
  	void close_func() {
  		FuncState fs = this.fs;
  		Prototype f = fs.f;
  		fs.ret(0, 0); /* final return */
  		fs.leaveblock();
  		f.code = LuaC.realloc(f.code, fs.pc);
  		f.lineinfo = LuaC.realloc(f.lineinfo, fs.pc);
  		f.k = LuaC.realloc(f.k, fs.nk);
  		f.p = LuaC.realloc(f.p, fs.np);
  		f.locvars = LuaC.realloc(f.locvars, fs.nlocvars);
  		f.upvalues = LuaC.realloc(f.upvalues, fs.nups);
  		LuaC._assert (fs.bl == null);
  		this.fs = fs.prev;
  		// last token read was anchored in defunct function; must reanchor it
  		// ls.anchor_token();
  	}
  
  	/*============================================================*/
  	/* GRAMMAR RULES */
  	/*============================================================*/
  
  	void fieldsel(expdesc v) {
  		/* fieldsel -> ['.' | ':'] NAME */
  		FuncState fs = this.fs;
  		expdesc key = new expdesc();
  		fs.exp2anyregup(v);
  		this.next(); /* skip the dot or colon */
  		this.checkname(key);
  		fs.indexed(v, key);
  	}
  
  	void yindex(expdesc v) {
  		/* index -> '[' expr ']' */
  		this.next(); /* skip the '[' */
  		this.expr(v);
  		this.fs.exp2val(v);
  		this.checknext(']');
  	}
  
  
   /*
  	** {======================================================================
  	** Rules for Constructors
  	** =======================================================================
  	*/
  
  
  	static class ConsControl {
  		expdesc v = new expdesc(); /* last list item read */
  		expdesc t; /* table descriptor */
  		int nh; /* total number of `record' elements */
  		int na; /* total number of array elements */
  		int tostore; /* number of array elements pending to be stored */
  	};
  
  
  	void recfield(ConsControl cc) {
  		/* recfield -> (NAME | `['exp1`]') = exp1 */
  		FuncState fs = this.fs;
  		int reg = this.fs.freereg;
  		expdesc key = new expdesc();
  		expdesc val = new expdesc();
  		int rkkey;
  		if (this.t.token == TK_NAME) {
  			fs.checklimit(cc.nh, MAX_INT, "items in a constructor");
  			this.checkname(key);
  		} else
  			/* this.t.token == '[' */
  			this.yindex(key);
  		cc.nh++;
  		this.checknext('=');
  		rkkey = fs.exp2RK(key);
  		this.expr(val);
  		fs.codeABC(Lua.OP_SETTABLE, cc.t.u.info, rkkey, fs.exp2RK(val));
  		fs.freereg = (short)reg; /* free registers */
  	}
  
  	void listfield (ConsControl cc) {
  	  this.expr(cc.v);
  	  fs.checklimit(cc.na, MAX_INT, "items in a constructor");
  	  cc.na++;
  	  cc.tostore++;
  	}
  
  
  	void constructor(expdesc t) {
  		/* constructor -> ?? */
  		FuncState fs = this.fs;
  		int line = this.linenumber;
  		int pc = fs.codeABC(Lua.OP_NEWTABLE, 0, 0, 0);
  		ConsControl cc = new ConsControl();
  		cc.na = cc.nh = cc.tostore = 0;
  		cc.t = t;
  		t.init(VRELOCABLE, pc);
  		cc.v.init(VVOID, 0); /* no value (yet) */
  		fs.exp2nextreg(t); /* fix it at stack top (for gc) */
  		this.checknext('{');
  		do {
  			LuaC._assert (cc.v.k == VVOID || cc.tostore > 0);
  			if (this.t.token == '}')
  				break;
  			fs.closelistfield(cc);
  			switch (this.t.token) {
  			case TK_NAME: { /* may be listfields or recfields */
  				this.lookahead();
  				if (this.lookahead.token != '=') /* expression? */
  					this.listfield(cc);
  				else
  					this.recfield(cc);
  				break;
  			}
  			case '[': { /* constructor_item -> recfield */
  				this.recfield(cc);
  				break;
  			}
  			default: { /* constructor_part -> listfield */
  				this.listfield(cc);
  				break;
  			}
  			}
  		} while (this.testnext(',') || this.testnext(';'));
  		this.check_match('}', '{', line);
  		fs.lastlistfield(cc);
  		InstructionPtr i = new InstructionPtr(fs.f.code, pc);
  		LuaC.SETARG_B(i, luaO_int2fb(cc.na)); /* set initial array size */
  		LuaC.SETARG_C(i, luaO_int2fb(cc.nh));  /* set initial table size */
  	}
  
  	/*
  	** converts an integer to a "floating point byte", represented as
  	** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
  	** eeeee != 0 and (xxx) otherwise.
  	*/
  	static int luaO_int2fb (int x) {
  	  int e = 0;  /* expoent */
  	  while (x >= 16) {
  	    x = (x+1) >> 1;
  	    e++;
  	  }
  	  if (x < 8) return x;
  	  else return ((e+1) << 3) | (((int)x) - 8);
  	}
  
  
  	/* }====================================================================== */
  
  	void parlist () {
  	  /* parlist -> [ param { `,' param } ] */
  	  FuncState fs = this.fs;
  	  Prototype f = fs.f;
  	  int nparams = 0;
  	  f.is_vararg = 0;
  	  if (this.t.token != ')') {  /* is `parlist' not empty? */
  	    do {
  	      switch (this.t.token) {
  	        case TK_NAME: {  /* param . NAME */
  	          this.new_localvar(this.str_checkname());
  	          ++nparams;
  	          break;
  	        }
  	        case TK_DOTS: {  /* param . `...' */
  	          this.next();
  	          f.is_vararg = 1;
  	          break;
  	        }
  	        default: this.syntaxerror("<name> or " + LUA_QL("...") + " expected");
  	      }
  	    } while ((f.is_vararg==0) && this.testnext(','));
  	  }
  	  this.adjustlocalvars(nparams);
  	  f.numparams = fs.nactvar;
  	  fs.reserveregs(fs.nactvar);  /* reserve register for parameters */
  	}
  
  
  	void body(expdesc e, boolean needself, int line) {
  		/* body -> `(' parlist `)' chunk END */
  		FuncState new_fs = new FuncState();
  		BlockCnt bl = new BlockCnt();
  		new_fs.f = addprototype();
  		new_fs.f.linedefined = line;
  		open_func(new_fs, bl);
  		this.checknext('(');
  		if (needself) {
  			new_localvarliteral("self");
  			adjustlocalvars(1);
  		}
  		this.parlist();
  		this.checknext(')');
  		this.statlist();
  		new_fs.f.lastlinedefined = this.linenumber;
  		this.check_match(TK_END, TK_FUNCTION, line);
  		this.codeclosure(e);
  		this.close_func();
  	}
  
  	int explist(expdesc v) {
  		/* explist1 -> expr { `,' expr } */
  		int n = 1; /* at least one expression */
  		this.expr(v);
  		while (this.testnext(',')) {
  			fs.exp2nextreg(v);
  			this.expr(v);
  			n++;
  		}
  		return n;
  	}
  
  
  	void funcargs(expdesc f, int line) {
  		FuncState fs = this.fs;
  		expdesc args = new expdesc();
  		int base, nparams;
  		switch (this.t.token) {
  		case '(': { /* funcargs -> `(' [ explist1 ] `)' */
  			this.next();
  			if (this.t.token == ')') /* arg list is empty? */
  				args.k = VVOID;
  			else {
  				this.explist(args);
  				fs.setmultret(args);
  			}
  			this.check_match(')', '(', line);
  			break;
  		}
  		case '{': { /* funcargs -> constructor */
  			this.constructor(args);
  			break;
  		}
  		case TK_STRING: { /* funcargs -> STRING */
  			this.codestring(args, this.t.seminfo.ts);
  			this.next(); /* must use `seminfo' before `next' */
  			break;
  		}
  		default: {
  			this.syntaxerror("function arguments expected");
  			return;
  		}
  		}
  		LuaC._assert (f.k == VNONRELOC);
  		base = f.u.info; /* base register for call */
  		if (hasmultret(args.k))
  			nparams = Lua.LUA_MULTRET; /* open call */
  		else {
  			if (args.k != VVOID)
  				fs.exp2nextreg(args); /* close last argument */
  			nparams = fs.freereg - (base + 1);
  		}
  		f.init(VCALL, fs.codeABC(Lua.OP_CALL, base, nparams + 1, 2));
  		fs.fixline(line);
  		fs.freereg = (short)(base+1);  /* call remove function and arguments and leaves
  							 * (unless changed) one result */
  	}
  
  
  	/*
  	** {======================================================================
  	** Expression parsing
  	** =======================================================================
  	*/
  
  	void primaryexp (expdesc v) {
  		/* primaryexp -> NAME | '(' expr ')' */
  		switch (t.token) {
  		case '(': {
  			int line = linenumber;
  			this.next();
  			this.expr(v);
  			this.check_match(')', '(', line);
  			fs.dischargevars(v);
  			return;
  		}
  		case TK_NAME: {
  			singlevar(v);
  			return;
  		}
  		default: {
  			this.syntaxerror("unexpected symbol " + t.token + " (" + ((char) t.token) + ")");
  			return;
  		}
  		}
  	}
  
  
  	void suffixedexp (expdesc v) {
  		/* suffixedexp ->
         	primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */
          int line = linenumber;
          primaryexp(v);
          for (; ; ) {
              switch (t.token) {
                  case '.': { /* fieldsel */
                      if(standardSyntax){//标准语法
                          this.fieldsel(v);
                      } else {
  						this.lookahead();
  						if (t.token == '.' && lookahead.token == TK_NAME && ( lookahead2.token == '(' || lookahead2.token == TK_STRING || lookahead2.token == '{')) {
  							//修改:和.调用方式 dongxicheng
  							t.token = ':';
  							expdesc key = new expdesc();
  							this.next();
  							this.checkname(key);
  							fs.self(v, key);
  							this.funcargs(v, line);
  						} else {
  							this.fieldsel(v);
  						}
                      }
                      break;
                  }
                  case '[': { /* `[' exp1 `]' */
                      expdesc key = new expdesc();
                      fs.exp2anyregup(v);
                      this.yindex(key);
                      fs.indexed(v, key);
                      break;
                  }
                  case ':': { /* `:' NAME funcargs */
                      if(standardSyntax){//标准语法
                          expdesc key = new expdesc();
                          this.next();
                          this.checkname(key);
                          fs.self(v, key);
                          this.funcargs(v, line);
                      } else {//非标准语法
                          this.fieldsel(v);
                      }
                      break;
                  }
                  case '(':
                  case TK_STRING:
                  case '{': { /* funcargs */
                      fs.exp2nextreg(v);
                      this.funcargs(v, line);
                      break;
                  }
                  default:
                      return;
              }
          }
      }
  
  
  	void simpleexp(expdesc v) {
  		/*
  		 * simpleexp -> NUMBER | STRING | NIL | true | false | ... | constructor |
  		 * FUNCTION body | primaryexp
  		 */
  		switch (this.t.token) {
  		case TK_NUMBER: {
  			v.init(VKNUM, 0);
  			v.u.setNval(this.t.seminfo.r);
  			break;
  		}
  		case TK_STRING: {
  			this.codestring(v, this.t.seminfo.ts);
  			break;
  		}
  		case TK_NIL: {
  			v.init(VNIL, 0);
  			break;
  		}
  		case TK_TRUE: {
  			v.init(VTRUE, 0);
  			break;
  		}
  		case TK_FALSE: {
  			v.init(VFALSE, 0);
  			break;
  		}
  		case TK_DOTS: { /* vararg */
  			FuncState fs = this.fs;
  			this.check_condition(fs.f.is_vararg!=0, "cannot use " + LUA_QL("...")
  					+ " outside a vararg function");
  			v.init(VVARARG, fs.codeABC(Lua.OP_VARARG, 0, 1, 0));
  			break;
  		}
  		case '{': { /* constructor */
  			this.constructor(v);
  			return;
  		}
  		case TK_FUNCTION: {
  			this.next();
  			this.body(v, false, this.linenumber);
  			return;
  		}
  		default: {
  			this.suffixedexp(v);
  			return;
  		}
  		}
  		this.next();
  	}
  
  
  	int getunopr(int op) {
  		switch (op) {
  		case TK_NOT:
  			return OPR_NOT;
  		case '-':
  			return OPR_MINUS;
  		case '#':
  			return OPR_LEN;
  		default:
  			return OPR_NOUNOPR;
  		}
  	}
  
  
  	int getbinopr(int op) {
  		switch (op) {
  		case '+':
  			return OPR_ADD;
  		case '-':
  			return OPR_SUB;
  		case '*':
  			return OPR_MUL;
  		case '/':
  			return OPR_DIV;
  		case '%':
  			return OPR_MOD;
  		case '^':
  			return OPR_POW;
  		case TK_CONCAT:
  			return OPR_CONCAT;
  		case TK_NE:
  			return OPR_NE;
  		case TK_EQ:
  			return OPR_EQ;
  		case '<':
  			return OPR_LT;
  		case TK_LE:
  			return OPR_LE;
  		case '>':
  			return OPR_GT;
  		case TK_GE:
  			return OPR_GE;
  		case TK_AND:
  			return OPR_AND;
  		case TK_OR:
  			return OPR_OR;
  		default:
  			return OPR_NOBINOPR;
  		}
  	}
  
  	static class Priority {
  		final byte left; /* left priority for each binary operator */
  
  		final byte right; /* right priority */
  
  		public Priority(int i, int j) {
  			left = (byte) i;
  			right = (byte) j;
  		}
  	};
  
  	static Priority[] priority = {  /* ORDER OPR */
  	   new Priority(6, 6), new Priority(6, 6), new Priority(7, 7), new Priority(7, 7), new Priority(7, 7),  /* `+' `-' `/' `%' */
  	   new Priority(10, 9), new Priority(5, 4),                 /* power and concat (right associative) */
  	   new Priority(3, 3), new Priority(3, 3),                  /* equality and inequality */
  	   new Priority(3, 3), new Priority(3, 3), new Priority(3, 3), new Priority(3, 3),  /* order */
  	   new Priority(2, 2), new Priority(1, 1)                   /* logical (and/or) */
  	};
  
  	static final int UNARY_PRIORITY	= 8;  /* priority for unary operators */
  
  
  	/*
  	** subexpr -> (simpleexp | unop subexpr) { binop subexpr }
  	** where `binop' is any binary operator with a priority higher than `limit'
  	*/
  	int subexpr(expdesc v, int limit) {
  		int op;
  		int uop;
  		this.enterlevel();
  		uop = getunopr(this.t.token);
  		if (uop != OPR_NOUNOPR) {
  		    int line = linenumber;
  			this.next();
  			this.subexpr(v, UNARY_PRIORITY);
  			fs.prefix(uop, v, line);
  		} else
  			this.simpleexp(v);
  		/* expand while operators have priorities higher than `limit' */
  		op = getbinopr(this.t.token);
  		while (op != OPR_NOBINOPR && priority[op].left > limit) {
  			expdesc v2 = new expdesc();
  			int line = linenumber;
  			this.next();
  			fs.infix(op, v);
  			/* read sub-expression with higher priority */
  			int nextop = this.subexpr(v2, priority[op].right);
  			fs.posfix(op, v, v2, line);
  			op = nextop;
  		}
  		this.leavelevel();
  		return op; /* return first untreated operator */
  	}
  
  	void expr(expdesc v) {
  		this.subexpr(v, 0);
  	}
  
  	/* }==================================================================== */
  
  
  
  	/*
  	** {======================================================================
  	** Rules for Statements
  	** =======================================================================
  	*/
  
  
  	boolean block_follow (boolean withuntil) {
  		switch (t.token) {
  		    case TK_ELSE: case TK_ELSEIF: case TK_END: case TK_EOS:
  		    	return true;
  			case TK_UNTIL:
  		    	return withuntil;
  		    default: return false;
  		}
  	}
  
  
  	void block () {
  	  /* block -> chunk */
  	  FuncState fs = this.fs;
  	  BlockCnt bl = new BlockCnt();
  	  fs.enterblock(bl, false);
  	  this.statlist();
  	  fs.leaveblock();
  	}
  
  
  	/*
  	** structure to chain all variables in the left-hand side of an
  	** assignment
  	*/
  	static class LHS_assign {
  		LHS_assign prev;
  		/* variable (global, local, upvalue, or indexed) */
  		expdesc v = new expdesc();
  	};
  
  
  	/*
  	** check whether, in an assignment to a local variable, the local variable
  	** is needed in a previous assignment (to a table). If so, save original
  	** local value in a safe place and use this safe copy in the previous
  	** assignment.
  	*/
  	void check_conflict (LHS_assign lh, expdesc v) {
  		FuncState fs = this.fs;
  		short extra = (short) fs.freereg;  /* eventual position to save local variable */
  		boolean conflict = false;
  		for (; lh!=null; lh = lh.prev) {
  			if (lh.v.k == VINDEXED) {
  				/* table is the upvalue/local being assigned now? */
  				if (lh.v.u.ind_vt == v.k && lh.v.u.ind_t == v.u.info) {
  					conflict = true;
  					lh.v.u.ind_vt = VLOCAL;
  					lh.v.u.ind_t = extra;  /* previous assignment will use safe copy */
  				}
  				/* index is the local being assigned? (index cannot be upvalue) */
  				if (v.k == VLOCAL && lh.v.u.ind_idx == v.u.info) {
  					conflict = true;
  					lh.v.u.ind_idx = extra;  /* previous assignment will use safe copy */
  				}
  			}
  		}
  		if (conflict) {
  		    /* copy upvalue/local value to a temporary (in position 'extra') */
  		    int op = (v.k == VLOCAL) ? Lua.OP_MOVE : Lua.OP_GETUPVAL;
  		    fs.codeABC(op, extra, v.u.info, 0);
  		    fs.reserveregs(1);
  		}
  	}
  
  
  	void assignment (LHS_assign lh, int nvars) {
  		expdesc e = new expdesc();
  		this.check_condition(VLOCAL <= lh.v.k && lh.v.k <= VINDEXED,
  	                      "syntax error");
  		if (this.testnext(',')) {  /* assignment -> `,' primaryexp assignment */
  		    LHS_assign nv = new LHS_assign();
  		    nv.prev = lh;
  		    this.suffixedexp(nv.v);
  		    if (nv.v.k != VINDEXED)
  		      this.check_conflict(lh, nv.v);
  		    this.assignment(nv, nvars+1);
  		}
  		else {  /* assignment . `=' explist1 */
  		    int nexps;
  		    this.checknext('=');
  		    nexps = this.explist(e);
  		    if (nexps != nvars) {
  		      this.adjust_assign(nvars, nexps, e);
  		      if (nexps > nvars)
  		        this.fs.freereg -= nexps - nvars;  /* remove extra values */
  	    }
  	    else {
  	    	fs.setoneret(e);  /* close last expression */
  	    	fs.storevar(lh.v, e);
  	    	return;  /* avoid default */
  	    }
  	  }
  	  e.init(VNONRELOC, this.fs.freereg-1);  /* default assignment */
  	  fs.storevar(lh.v, e);
  	}
  
  
  	int cond() {
  		/* cond -> exp */
  		expdesc v = new expdesc();
  		/* read condition */
  		this.expr(v);
  		/* `falses' are all equal here */
  		if (v.k == VNIL)
  			v.k = VFALSE;
  		fs.goiftrue(v);
  		return v.f.i;
  	}
  
  	void gotostat(int pc) {
  		int line = linenumber;
  		LuaString label;
  		int g;
  		if (testnext(TK_GOTO))
  			label = str_checkname();
  		else {
  			next();  /* skip break */
  			label = LuaString.valueOf("break");
  		}
  		g = newlabelentry(dyd.gt =LuaC.grow(dyd.gt, dyd.n_gt+1), dyd.n_gt++, label, line, pc);
  		findlabel(g);  /* close it if label already defined */
  	}
  
  
  	/* skip no-op statements */
  	void skipnoopstat () {
  		while (t.token == ';' || t.token == TK_DBCOLON)
  			statement();
  	}
  
  
  	void labelstat (LuaString label, int line) {
  		/* label -> '::' NAME '::' */
  		int l;  /* index of new label being created */
  		fs.checkrepeated(dyd.label, dyd.n_label, label);  /* check for repeated labels */
  		checknext(TK_DBCOLON);  /* skip double colon */
  		/* create new entry for this label */
  		l = newlabelentry(dyd.label=LuaC.grow(dyd.label, dyd.n_label+1), dyd.n_label++, label, line, fs.pc);
  		skipnoopstat();  /* skip other no-op statements */
  		if (block_follow(false)) {  /* label is last no-op statement in the block? */
  			/* assume that locals are already out of scope */
  			dyd.label[l].nactvar = fs.bl.nactvar;
  		}
  		findgotos(dyd.label[l]);
  }
  
  
  	void whilestat (int line) {
  		/* whilestat -> WHILE cond DO block END */
  		FuncState fs = this.fs;
  		int whileinit;
  		int condexit;
  		BlockCnt bl = new BlockCnt();
  		this.next();  /* skip WHILE */
  		whileinit = fs.getlabel();
  		condexit = this.cond();
  		fs.enterblock(bl, true);
  		this.checknext(TK_DO);
  		this.block();
  		fs.patchlist(fs.jump(), whileinit);
  		this.check_match(TK_END, TK_WHILE, line);
  		fs.leaveblock();
  		fs.patchtohere(condexit);  /* false conditions finish the loop */
  	}
  
  	void repeatstat(int line) {
  		/* repeatstat -> REPEAT block UNTIL cond */
  		int condexit;
  		FuncState fs = this.fs;
  		int repeat_init = fs.getlabel();
  		BlockCnt bl1 = new BlockCnt();
  		BlockCnt bl2 = new BlockCnt();
  		fs.enterblock(bl1, true); /* loop block */
  		fs.enterblock(bl2, false); /* scope block */
  		this.next(); /* skip REPEAT */
  		this.statlist();
  		this.check_match(TK_UNTIL, TK_REPEAT, line);
  		condexit = this.cond(); /* read condition (inside scope block) */
  		if (bl2.upval) { /* upvalues? */
  		    fs.patchclose(condexit, bl2.nactvar);
  		}
  		fs.leaveblock(); /* finish scope */
  		fs.patchlist(condexit, repeat_init); /* close the loop */
  		fs.leaveblock(); /* finish loop */
  	}
  
  
  	int exp1() {
  		expdesc e = new expdesc();
  		int k;
  		this.expr(e);
  		k = e.k;
  		fs.exp2nextreg(e);
  		return k;
  	}
  
  
  	void forbody(int base, int line, int nvars, boolean isnum) {
  		/* forbody -> DO block */
  		BlockCnt bl = new BlockCnt();
  		FuncState fs = this.fs;
  		int prep, endfor;
  		this.adjustlocalvars(3); /* control variables */
  		this.checknext(TK_DO);
  		prep = isnum ? fs.codeAsBx(Lua.OP_FORPREP, base, NO_JUMP) : fs.jump();
  		fs.enterblock(bl, false); /* scope for declared variables */
  		this.adjustlocalvars(nvars);
  		fs.reserveregs(nvars);
  		this.block();
  		fs.leaveblock(); /* end of scope for declared variables */
  		fs.patchtohere(prep);
  		if (isnum)  /* numeric for? */
  			endfor = fs.codeAsBx(Lua.OP_FORLOOP, base, NO_JUMP);
  		else {  /* generic for */
  			fs.codeABC(Lua.OP_TFORCALL, base, 0, nvars);
  			fs.fixline(line);
  			endfor = fs.codeAsBx(Lua.OP_TFORLOOP, base + 2, NO_JUMP);
  		}
  		fs.patchlist(endfor, prep + 1);
  		fs.fixline(line);
  	}
  
  
  	void fornum(LuaString varname, int line) {
  		/* fornum -> NAME = exp1,exp1[,exp1] forbody */
  		FuncState fs = this.fs;
  		int base = fs.freereg;
  		this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_INDEX);
  		this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_LIMIT);
  		this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_STEP);
  		this.new_localvar(varname);
  		this.checknext('=');
  		this.exp1(); /* initial value */
  		this.checknext(',');
  		this.exp1(); /* limit */
  		if (this.testnext(','))
  			this.exp1(); /* optional step */
  		else { /* default step = 1 */
  			fs.codeABx(Lua.OP_LOADK, fs.freereg, fs.numberK(LuaInteger.valueOf(1)));
  			fs.reserveregs(1);
  		}
  		this.forbody(base, line, 1, true);
  	}
  
  
  	void forlist(LuaString indexname) {
  		/* forlist -> NAME {,NAME} IN explist1 forbody */
  		FuncState fs = this.fs;
  		expdesc e = new expdesc();
  		int nvars = 4;   /* gen, state, control, plus at least one declared var */
  		int line;
  		int base = fs.freereg;
  		/* create control variables */
  		this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_GENERATOR);
  		this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_STATE);
  		this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_CONTROL);
  		/* create declared variables */
  		this.new_localvar(indexname);
  		while (this.testnext(',')) {
  			this.new_localvar(this.str_checkname());
  			++nvars;
  		}
  		this.checknext(TK_IN);
  		line = this.linenumber;
  		this.adjust_assign(3, this.explist(e), e);
  		fs.checkstack(3); /* extra space to call generator */
  		this.forbody(base, line, nvars - 3, false);
  	}
  
  
  	void forstat(int line) {
  		/* forstat -> FOR (fornum | forlist) END */
  		FuncState fs = this.fs;
  		LuaString varname;
  		BlockCnt bl = new BlockCnt();
  		fs.enterblock(bl, true); /* scope for loop and control variables */
  		this.next(); /* skip `for' */
  		varname = this.str_checkname(); /* first variable name */
  		switch (this.t.token) {
  		case '=':
  			this.fornum(varname, line);
  			break;
  		case ',':
  		case TK_IN:
  			this.forlist(varname);
  			break;
  		default:
  			this.syntaxerror(LUA_QL("=") + " or " + LUA_QL("in") + " expected");
  		}
  		this.check_match(TK_END, TK_FOR, line);
  		fs.leaveblock(); /* loop scope (`break' jumps to this point) */
  	}
  
  
  	void test_then_block(IntPtr escapelist) {
  		/* test_then_block -> [IF | ELSEIF] cond THEN block */
  		expdesc v = new expdesc();
  		BlockCnt bl = new BlockCnt();
  		int jf;  /* instruction to skip 'then' code (if condition is false) */
  		this.next(); /* skip IF or ELSEIF */
  		expr(v);  /* read expression */
  		this.checknext(TK_THEN);
  		if (t.token == TK_GOTO || t.token == TK_BREAK) {
  			fs.goiffalse(v); /* will jump to label if condition is true */
  			fs.enterblock(bl, false); /* must enter block before 'goto' */
  			gotostat(v.t.i); /* handle goto/break */
  			skipnoopstat(); /* skip other no-op statements */
  			if (block_follow(false)) { /* 'goto' is the entire block? */
  				fs.leaveblock();
  				return; /* and that is it */
  			} else
  				/* must skip over 'then' part if condition is false */
  				jf = fs.jump();
  		} else { /* regular case (not goto/break) */
  			fs.goiftrue(v); /* skip over block if condition is false */
  			fs.enterblock(bl, false);
  			jf = v.f.i;
  		}
  		statlist(); /* `then' part */
  		fs.leaveblock();
  		if (t.token == TK_ELSE || t.token == TK_ELSEIF)
  			fs.concat(escapelist, fs.jump()); /* must jump over it */
  		fs.patchtohere(jf);
  	}
  
  
  	void ifstat(int line) {
  		IntPtr escapelist = new IntPtr(NO_JUMP);  /* exit list for finished parts */
  		test_then_block(escapelist);  /* IF cond THEN block */
  		while (t.token == TK_ELSEIF)
  		    test_then_block(escapelist);  /* ELSEIF cond THEN block */
  		if (testnext(TK_ELSE))
  		    block();  /* `else' part */
  		check_match(TK_END, TK_IF, line);
  		fs.patchtohere(escapelist.i);  /* patch escape list to 'if' end */
  	}
  
  	void localfunc() {
  		expdesc b = new expdesc();
  		FuncState fs = this.fs;
  		this.new_localvar(this.str_checkname());
  		this.adjustlocalvars(1);
  		this.body(b, false, this.linenumber);
  		/* debug information will only see the variable after this point! */
  		fs.getlocvar(fs.nactvar - 1).startpc = fs.pc;
  	}
  
  
  	void localstat() {
  		/* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */
  		int nvars = 0;
  		int nexps;
  		expdesc e = new expdesc();
  		do {
  			this.new_localvar(this.str_checkname());
  			++nvars;
  		} while (this.testnext(','));
  		if (this.testnext('='))
  			nexps = this.explist(e);
  		else {
  			e.k = VVOID;
  			nexps = 0;
  		}
  		this.adjust_assign(nvars, nexps, e);
  		this.adjustlocalvars(nvars);
  	}
  
  
  	boolean funcname(expdesc v) {
  		/* funcname -> NAME {field} [`:' NAME] */
  		if(standardSyntax){//TODO . 和 : 兼容
  			boolean ismethod = false;
  			this.singlevar(v);
  			while (this.t.token == '.')
  				this.fieldsel(v);
  			if (this.t.token == ':') {
  				ismethod = true;
  				this.fieldsel(v);
  			}
  			return ismethod;
  		} else {
  			boolean needself = false;
  			this.singlevar(v);
  			while (this.t.token == '.') {
  				needself = true;
  				this.fieldsel(v);
  			}
  			if (this.t.token == ':') {
  				needself = false;
  				this.fieldsel(v);
  			}
  			return needself;
  		}
      }
  
  
  	void funcstat(int line) {
  		/* funcstat -> FUNCTION funcname body */
  		boolean needself;
  		expdesc v = new expdesc();
  		expdesc b = new expdesc();
  		this.next(); /* skip FUNCTION */
  		needself = this.funcname(v);
  		this.body(b, needself, line);
  		fs.storevar(v, b);
  		fs.fixline(line); /* definition `happens' in the first line */
  	}
  
  
  	void exprstat() {
  		/* stat -> func | assignment */
  		FuncState fs = this.fs;
  		LHS_assign v = new LHS_assign();
  		this.suffixedexp(v.v);
  		if (t.token == '=' || t.token == ',') { /* stat -> assignment ? */
  			v.prev = null;
  			assignment(v, 1);
  		}
  		else {  /* stat -> func */
  			check_condition(v.v.k == VCALL, "syntax error");
  			LuaC.SETARG_C(fs.getcodePtr(v.v), 1);  /* call statement uses no results */
  		}
  	}
  
  	void retstat() {
  		/* stat -> RETURN explist */
  		FuncState fs = this.fs;
  		expdesc e = new expdesc();
  		int first, nret; /* registers with returned values */
  		if (block_follow(true) || this.t.token == ';')
  			first = nret = 0; /* return no values */
  		else {
  			nret = this.explist(e); /* optional return values */
  			if (hasmultret(e.k)) {
  				fs.setmultret(e);
  				if (e.k == VCALL && nret == 1) { /* tail call? */
  					LuaC.SET_OPCODE(fs.getcodePtr(e), Lua.OP_TAILCALL);
  					LuaC._assert (Lua.GETARG_A(fs.getcode(e)) == fs.nactvar);
  				}
  				first = fs.nactvar;
  				nret = Lua.LUA_MULTRET; /* return all values */
  			} else {
  				if (nret == 1) /* only one single value? */
  					first = fs.exp2anyreg(e);
  				else {
  					fs.exp2nextreg(e); /* values must go to the `stack' */
  					first = fs.nactvar; /* return all `active' values */
  					LuaC._assert (nret == fs.freereg - first);
  				}
  			}
  		}
  		fs.ret(first, nret);
  		testnext(';');  /* skip optional semicolon */
  	}
  
  	void statement() {
  		int line = this.linenumber; /* may be needed for error messages */
  		enterlevel();
  		switch (this.t.token) {
  		case ';': { /* stat -> ';' (empty statement) */
  			next(); /* skip ';' */
  			break;
  		}
  		case TK_IF: { /* stat -> ifstat */
  			this.ifstat(line);
  			break;
  		}
  		case TK_WHILE: { /* stat -> whilestat */
  			this.whilestat(line);
  			break;
  		}
  		case TK_DO: { /* stat -> DO block END */
  			this.next(); /* skip DO */
  			this.block();
  			this.check_match(TK_END, TK_DO, line);
  			break;
  		}
  		case TK_FOR: { /* stat -> forstat */
  			this.forstat(line);
  			break;
  		}
  		case TK_REPEAT: { /* stat -> repeatstat */
  			this.repeatstat(line);
  			break;
  		}
  		case TK_FUNCTION: {
  			this.funcstat(line); /* stat -> funcstat */
  			break;
  		}
  		case TK_LOCAL: { /* stat -> localstat */
  			this.next(); /* skip LOCAL */
  			if (this.testnext(TK_FUNCTION)) /* local function? */
  				this.localfunc();
  			else
  				this.localstat();
  			break;
  		}
  		case TK_DBCOLON: { /* stat -> label */
  			next(); /* skip double colon */
  			labelstat(str_checkname(), line);
  			break;
  		}
  		case TK_RETURN: { /* stat -> retstat */
  		    next();  /* skip RETURN */
  			this.retstat();
  			break;
  		}
  		case TK_BREAK:
  		case TK_GOTO: { /* stat -> breakstat */
  			this.gotostat(fs.jump());
  			break;
  		}
  		default: {
  			this.exprstat();
  			break;
  		}
  		}
  		LuaC._assert(fs.f.maxstacksize >= fs.freereg
  				&& fs.freereg >= fs.nactvar);
  		fs.freereg = fs.nactvar; /* free registers */
  		leavelevel();
  	}
  
  	void statlist() {
  		/* statlist -> { stat [`;'] } */
  		while (!block_follow(true)) {
  			if (t.token == TK_RETURN) {
  				statement();
  				return; /* 'return' must be last statement */
  			}
  			statement();
  		}
  	}
  
  	/*
  	** compiles the main function, which is a regular vararg function with an
  	** upvalue named LUA_ENV
  	*/
  	public void mainfunc(FuncState funcstate) {
  		  BlockCnt bl = new BlockCnt();
  		  open_func(funcstate, bl);
  		  fs.f.is_vararg = 1;  /* main function is always vararg */
  		  expdesc v = new expdesc();
  		  v.init(VLOCAL, 0);  /* create and... */
  		  fs.newupvalue(envn, v);  /* ...set environment upvalue */
  		  next();  /* read first token */
  		  statlist();  /* parse main body */
  		  check(TK_EOS);
  		  close_func();
  	}
  	
  	/* }====================================================================== */
  
  }
  