1 /* $Header: //info.ravenbrook.com/project/jili/version/1.1/code/mnj/lua/Syntax.java#1 $
2 * Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject
11 * to the following conditions:
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
20 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 import java
.io
.IOException
;
28 import java
.io
.Reader
;
29 import java
.util
.Hashtable
;
33 * Syntax analyser. Lexing, parsing, code generation.
37 /** End of File, must be -1 as that is what read() returns. */
38 private static final int EOZ
= -1;
40 private static final int FIRST_RESERVED
= 257;
42 // WARNING: if you change the order of this enumeration,
43 // grep "ORDER RESERVED"
44 private static final int TK_AND
= FIRST_RESERVED
+ 0;
45 private static final int TK_BREAK
= FIRST_RESERVED
+ 1;
46 private static final int TK_DO
= FIRST_RESERVED
+ 2;
47 private static final int TK_ELSE
= FIRST_RESERVED
+ 3;
48 private static final int TK_ELSEIF
= FIRST_RESERVED
+ 4;
49 private static final int TK_END
= FIRST_RESERVED
+ 5;
50 private static final int TK_FALSE
= FIRST_RESERVED
+ 6;
51 private static final int TK_FOR
= FIRST_RESERVED
+ 7;
52 private static final int TK_FUNCTION
= FIRST_RESERVED
+ 8;
53 private static final int TK_IF
= FIRST_RESERVED
+ 9;
54 private static final int TK_IN
= FIRST_RESERVED
+ 10;
55 private static final int TK_LOCAL
= FIRST_RESERVED
+ 11;
56 private static final int TK_NIL
= FIRST_RESERVED
+ 12;
57 private static final int TK_NOT
= FIRST_RESERVED
+ 13;
58 private static final int TK_OR
= FIRST_RESERVED
+ 14;
59 private static final int TK_REPEAT
= FIRST_RESERVED
+ 15;
60 private static final int TK_RETURN
= FIRST_RESERVED
+ 16;
61 private static final int TK_THEN
= FIRST_RESERVED
+ 17;
62 private static final int TK_TRUE
= FIRST_RESERVED
+ 18;
63 private static final int TK_UNTIL
= FIRST_RESERVED
+ 19;
64 private static final int TK_WHILE
= FIRST_RESERVED
+ 20;
65 private static final int TK_CONCAT
= FIRST_RESERVED
+ 21;
66 private static final int TK_DOTS
= FIRST_RESERVED
+ 22;
67 private static final int TK_EQ
= FIRST_RESERVED
+ 23;
68 private static final int TK_GE
= FIRST_RESERVED
+ 24;
69 private static final int TK_LE
= FIRST_RESERVED
+ 25;
70 private static final int TK_NE
= FIRST_RESERVED
+ 26;
71 private static final int TK_NUMBER
= FIRST_RESERVED
+ 27;
72 private static final int TK_NAME
= FIRST_RESERVED
+ 28;
73 private static final int TK_STRING
= FIRST_RESERVED
+ 29;
74 private static final int TK_EOS
= FIRST_RESERVED
+ 30;
76 private static final int NUM_RESERVED
= TK_WHILE
- FIRST_RESERVED
+ 1;
78 /** Equivalent to luaX_tokens. ORDER RESERVED */
79 static String
[] tokens
= new String
[]
81 "and", "break", "do", "else", "elseif",
82 "end", "false", "for", "function", "if",
83 "in", "local", "nil", "not", "or", "repeat",
84 "return", "then", "true", "until", "while",
85 "..", "...", "==", ">=", "<=", "~=",
86 "<number>", "<name>", "<string>", "<eof>"
89 static Hashtable
<Object
, Object
> reserved
= new Hashtable
<Object
, Object
>();
92 for (int i
=0; i
< NUM_RESERVED
; ++i
)
94 reserved
.put(tokens
[i
], new Integer(FIRST_RESERVED
+i
));
98 // From struct LexState
100 /** current character */
102 /** input line counter */
104 /** line of last token 'consumed' */
107 * The token value. For "punctuation" tokens this is the ASCII value
108 * for the character for the token; for other tokens a member of the
109 * enum (all of which are > 255).
112 /** Semantic info for token; a number. */
114 /** Semantic info for token; a string. */
117 /** Lookahead token value. */
118 int lookahead
= TK_EOS
;
119 /** Semantic info for lookahead; a number. */
121 /** Semantic info for lookahead; a string. */
124 /** Semantic info for return value from {@link #llex}; a number. */
126 /** As {@link #semR}, for string. */
129 /** FuncState for current (innermost) function being parsed. */
136 /** Buffer for tokens. */
137 StringBuffer buff
= new StringBuffer();
139 /** current source name */
142 private Syntax(Lua L
, Reader z
, String source
) throws IOException
146 this.source
= source
;
158 // Implementations of functions from <ctype.h> are only correct copies
159 // to the extent that Lua requires them.
160 // Generally they have default access so that StringLib can see them.
161 // Unlike C's these version are not locale dependent, they use the
162 // ISO-Latin-1 definitions from CLDC 1.1 Character class.
164 static boolean isalnum(int c
)
167 return Character
.isUpperCase(ch
) ||
168 Character
.isLowerCase(ch
) ||
169 Character
.isDigit(ch
);
172 static boolean isalpha(int c
)
175 return Character
.isUpperCase(ch
) ||
176 Character
.isLowerCase(ch
);
179 /** True if and only if the char (when converted from the int) is a
182 static boolean iscntrl(int c
)
184 return (char)c
< 0x20 || c
== 0x7f;
187 static boolean isdigit(int c
)
189 return Character
.isDigit((char)c
);
192 static boolean islower(int c
)
194 return Character
.isLowerCase((char)c
);
198 * A character is punctuation if not cntrl, not alnum, and not space.
200 static boolean ispunct(int c
)
202 return !isalnum(c
) && !iscntrl(c
) && !isspace(c
);
205 static boolean isspace(int c
)
214 static boolean isupper(int c
)
216 return Character
.isUpperCase((char)c
);
219 static boolean isxdigit(int c
)
221 return Character
.isDigit((char)c
) ||
222 ('a' <= c
&& c
<= 'f') ||
223 ('A' <= c
&& c
<= 'F');
228 private boolean check_next(String set
) throws IOException
230 if (set
.indexOf(current
) < 0)
238 private boolean currIsNewline()
240 return current
== '\n' || current
== '\r';
243 private void inclinenumber() throws IOException
246 //# assert currIsNewline()
247 next(); // skip '\n' or '\r'
248 if (currIsNewline() && current
!= old
)
250 next(); // skip '\n\r' or '\r\n'
252 if (++linenumber
< 0) // overflow
254 xSyntaxerror("chunk has too many lines");
258 private int skip_sep() throws IOException
262 //# assert s == '[' || s == ']'
264 while (current
== '=')
269 return (current
== s
) ? count
: (-count
) - 1;
272 private void read_long_string(boolean isString
, int sep
) throws IOException
274 save_and_next(); /* skip 2nd `[' */
275 if (currIsNewline()) /* string starts with a newline? */
276 inclinenumber(); /* skip it */
283 xLexerror(isString ?
"unfinished long string" :
284 "unfinished long comment",
286 break; /* to avoid warnings */
288 if (skip_sep() == sep
)
290 save_and_next(); /* skip 2nd `]' */
300 buff
.setLength(0) ; /* avoid wasting space */
304 if (isString
) save_and_next();
310 String rawtoken
= buff
.toString();
311 int trim_by
= 2+sep
;
312 semS
= rawtoken
.substring(trim_by
, rawtoken
.length()-trim_by
) ;
317 /** Lex a token and return it. The semantic info for the token is
318 * stored in <code>this.semR</code> or <code>this.semS</code> as
321 private int llex() throws IOException
336 /* else is a comment */
340 int sep
= skip_sep();
341 buff
.setLength(0) ; /* `skip_sep' may dirty the buffer */
344 read_long_string(false, sep
); /* long comment */
349 /* else short comment */
350 while (!currIsNewline() && current
!= EOZ
)
355 int sep
= skip_sep();
358 read_long_string(true, sep
);
364 xLexerror("invalid long string delimiter", TK_STRING
);
365 continue; // avoids Checkstyle warning.
405 read_string(current
);
420 else if (!isdigit(current
))
432 if (isspace(current
))
434 // assert !currIsNewline();
438 else if (isdigit(current
))
443 else if (isalpha(current
) || current
== '_')
445 // identifier or reserved word
449 } while (isalnum(current
) || current
== '_');
450 String s
= buff
.toString();
451 Object t
= reserved
.get(s
);
459 return ((Integer
)t
).intValue();
466 return c
; // single-char tokens
472 private void next() throws IOException
477 private static final int hexCharValue(char x
) throws NumberFormatException
503 default: throw new NumberFormatException("Bad hexadecimal digit");
507 /** Reads number. Writes to semR. */
508 private void read_numeral() throws IOException
510 // assert isdigit(current);
514 } while (isdigit(current
) || current
== '.');
515 if (check_next("Ee")) // 'E' ?
517 check_next("+-"); // optional exponent sign
519 while (isalnum(current
) || current
== '_')
523 // :todo: consider doing PUC-Rio's decimal point tricks.
526 String n
= buff
.toString();
527 if(n
.length() > 2 && n
.charAt(0) == '0' && n
.charAt(1) == 'x')
529 //Hexadecimal constant.
531 for(int i
= 2; i
< n
.length(); i
++)
532 value
= value
* 16 + hexCharValue(n
.charAt(i
));
536 semR
= Double
.parseDouble(n
);
539 catch (NumberFormatException e
)
541 xLexerror("malformed number", TK_NUMBER
);
545 /** Reads string. Writes to semS. */
546 private void read_string(int del
) throws IOException
549 while (current
!= del
)
554 xLexerror("unfinished string", TK_EOS
);
555 continue; // avoid compiler warning
558 xLexerror("unfinished string", TK_STRING
);
559 continue; // avoid compiler warning
563 next(); // do not save the '\'
566 case 'a': c
= 7; break; // no '\a' in Java.
567 case 'b': c
= '\b'; break;
568 case 'f': c
= '\f'; break;
569 case 'n': c
= '\n'; break;
570 case 'r': c
= '\r'; break;
571 case 't': c
= '\t'; break;
572 case 'v': c
= 11; break; // no '\v' in Java.
573 case '\n': case '\r':
578 continue; // will raise an error next loop
580 if (!isdigit(current
))
582 save_and_next(); // handles \\, \", \', \?
590 c
= 10*c
+ (current
- '0');
592 } while (++i
<3 && isdigit(current
));
593 // In unicode, there are no bounds on a 3-digit decimal.
606 save_and_next(); // skip delimiter
607 String rawtoken
= buff
.toString() ;
608 semS
= rawtoken
.substring(1, rawtoken
.length()-1) ;
613 buff
.append((char)current
);
616 private void save(int c
)
618 buff
.append((char)c
);
621 private void save_and_next() throws IOException
627 /** Getter for source. */
633 private String
txtToken(int tok
)
640 return buff
.toString();
642 return xToken2str(tok
);
646 /** Equivalent to <code>luaX_lexerror</code>. */
647 private void xLexerror(String msg
, int tok
)
649 msg
= source
+ ":" + linenumber
+ ": " + msg
;
652 msg
= msg
+ " near '" + txtToken(tok
) + "'";
655 L
.dThrow(Lua
.ERRSYNTAX
);
658 /** Equivalent to <code>luaX_next</code>. */
659 private void xNext() throws IOException
661 lastline
= linenumber
;
662 if (lookahead
!= TK_EOS
) // is there a look-ahead token?
664 token
= lookahead
; // Use this one,
667 lookahead
= TK_EOS
; // and discharge it.
677 /** Equivalent to <code>luaX_syntaxerror</code>. */
678 void xSyntaxerror(String msg
)
680 xLexerror(msg
, token
);
683 private static String
xToken2str(int token
)
685 if (token
< FIRST_RESERVED
)
687 // assert token == (char)token;
690 return "char(" + token
+ ")";
692 return (new Character((char)token
)).toString();
694 return tokens
[token
-FIRST_RESERVED
];
699 private static boolean block_follow(int token
)
703 case TK_ELSE
: case TK_ELSEIF
: case TK_END
:
704 case TK_UNTIL
: case TK_EOS
:
711 private void check(int c
)
720 * @param what the token that is intended to end the match.
721 * @param who the token that begins the match.
722 * @param where the line number of <var>what</var>.
724 private void check_match(int what
, int who
, int where
)
729 if (where
== linenumber
)
731 error_expected(what
);
735 xSyntaxerror("'" + xToken2str(what
) + "' expected (to close '" +
736 xToken2str(who
) + "' at line " + where
+ ")");
741 private void close_func()
744 fs
.kRet(0, 0); // final return;
746 // :todo: check this is a valid assertion to make
747 //# assert fs != fs.prev
752 static String
opcode_name(int op
)
756 case Lua
.OP_MOVE
: return "MOVE";
757 case Lua
.OP_LOADK
: return "LOADK";
758 case Lua
.OP_LOADBOOL
: return "LOADBOOL";
759 case Lua
.OP_LOADNIL
: return "LOADNIL";
760 case Lua
.OP_GETUPVAL
: return "GETUPVAL";
761 case Lua
.OP_GETGLOBAL
: return "GETGLOBAL";
762 case Lua
.OP_GETTABLE
: return "GETTABLE";
763 case Lua
.OP_SETGLOBAL
: return "SETGLOBAL";
764 case Lua
.OP_SETUPVAL
: return "SETUPVAL";
765 case Lua
.OP_SETTABLE
: return "SETTABLE";
766 case Lua
.OP_NEWTABLE
: return "NEWTABLE";
767 case Lua
.OP_SELF
: return "SELF";
768 case Lua
.OP_ADD
: return "ADD";
769 case Lua
.OP_SUB
: return "SUB";
770 case Lua
.OP_MUL
: return "MUL";
771 case Lua
.OP_DIV
: return "DIV";
772 case Lua
.OP_MOD
: return "MOD";
773 case Lua
.OP_POW
: return "POW";
774 case Lua
.OP_UNM
: return "UNM";
775 case Lua
.OP_NOT
: return "NOT";
776 case Lua
.OP_LEN
: return "LEN";
777 case Lua
.OP_CONCAT
: return "CONCAT";
778 case Lua
.OP_JMP
: return "JMP";
779 case Lua
.OP_EQ
: return "EQ";
780 case Lua
.OP_LT
: return "LT";
781 case Lua
.OP_LE
: return "LE";
782 case Lua
.OP_TEST
: return "TEST";
783 case Lua
.OP_TESTSET
: return "TESTSET";
784 case Lua
.OP_CALL
: return "CALL";
785 case Lua
.OP_TAILCALL
: return "TAILCALL";
786 case Lua
.OP_RETURN
: return "RETURN";
787 case Lua
.OP_FORLOOP
: return "FORLOOP";
788 case Lua
.OP_FORPREP
: return "FORPREP";
789 case Lua
.OP_TFORLOOP
: return "TFORLOOP";
790 case Lua
.OP_SETLIST
: return "SETLIST";
791 case Lua
.OP_CLOSE
: return "CLOSE";
792 case Lua
.OP_CLOSURE
: return "CLOSURE";
793 case Lua
.OP_VARARG
: return "VARARG";
794 default: return "??"+op
;
798 private void codestring(Expdesc e
, String s
)
800 e
.init(Expdesc
.VK
, fs
.kStringK(s
));
803 private void checkname(Expdesc e
) throws IOException
805 codestring(e
, str_checkname());
808 private void enterlevel()
813 private void error_expected(int tok
)
815 xSyntaxerror("'" + xToken2str(tok
) + "' expected");
818 private void leavelevel()
824 /** Equivalent to luaY_parser. */
825 static Proto
parser(Lua L
, Reader in
, String name
)
828 Syntax ls
= new Syntax(L
, in
, name
);
829 FuncState fs
= new FuncState(ls
);
836 //# assert fs.prev == null
837 //# assert fs.f.nups == 0
838 //# assert ls.fs == null
842 private void removevars(int tolevel
)
844 // :todo: consider making a method in FuncState.
845 while (fs
.nactvar
> tolevel
)
847 fs
.getlocvar(--fs
.nactvar
).endpc
= fs
.pc
;
851 private void singlevar(Expdesc var
) throws IOException
853 String varname
= str_checkname();
854 if (singlevaraux(fs
, varname
, var
, true) == Expdesc
.VGLOBAL
)
856 var
.setInfo(fs
.kStringK(varname
));
860 private int singlevaraux(FuncState f
,
865 if (f
== null) // no more levels?
867 var
.init(Expdesc
.VGLOBAL
, Lua
.NO_REG
); // default is global variable
868 return Expdesc
.VGLOBAL
;
872 int v
= f
.searchvar(n
);
875 var
.init(Expdesc
.VLOCAL
, v
);
878 f
.markupval(v
); // local will be used as an upval
880 return Expdesc
.VLOCAL
;
882 else // not found at current level; try upper one
884 if (singlevaraux(f
.prev
, n
, var
, false) == Expdesc
.VGLOBAL
)
886 return Expdesc
.VGLOBAL
;
888 var
.upval(indexupvalue(f
, n
, var
)); // else was LOCAL or UPVAL
889 return Expdesc
.VUPVAL
;
894 private String
str_checkname() throws IOException
902 private boolean testnext(int c
) throws IOException
915 private void chunk() throws IOException
917 // chunk -> { stat [';'] }
918 boolean islast
= false;
920 while (!islast
&& !block_follow(token
))
922 islast
= statement();
924 //# assert fs.f.maxstacksize >= fs.freereg && fs.freereg >= fs.nactvar
925 fs
.freereg
= fs
.nactvar
;
930 private void constructor(Expdesc t
) throws IOException
933 int line
= linenumber
;
934 int pc
= fs
.kCodeABC(Lua
.OP_NEWTABLE
, 0, 0, 0);
935 ConsControl cc
= new ConsControl(t
) ;
936 t
.init(Expdesc
.VRELOCABLE
, pc
);
937 cc
.v
.init(Expdesc
.VVOID
, 0); /* no value (yet) */
938 fs
.kExp2nextreg(t
); /* fix it at stack top (for gc) */
942 //# assert cc.v.k == Expdesc.VVOID || cc.tostore > 0
948 case TK_NAME
: /* may be listfields or recfields */
950 if (lookahead
!= '=') /* expression? */
956 case '[': /* constructor_item -> recfield */
960 default: /* constructor_part -> listfield */
964 } while (testnext(',') || testnext(';'));
965 check_match('}', '{', line
);
967 int [] code
= fs
.f
.code
;
968 code
[pc
] = Lua
.SETARG_B(code
[pc
], oInt2fb(cc
.na
)); /* set initial array size */
969 code
[pc
] = Lua
.SETARG_C(code
[pc
], oInt2fb(cc
.nh
)); /* set initial table size */
972 private static int oInt2fb(int x
)
974 int e
= 0; /* exponent */
975 while (x
< 0 || x
>= 16)
980 return (x
< 8) ? x
: (((e
+1) << 3) | (x
- 8));
983 private void recfield(ConsControl cc
) throws IOException
985 /* recfield -> (NAME | `['exp1`]') = exp1 */
986 int reg
= fs
.freereg
;
987 Expdesc key
= new Expdesc() ;
988 Expdesc val
= new Expdesc() ;
989 if (token
== TK_NAME
)
991 // yChecklimit(fs, cc.nh, MAX_INT, "items in a constructor");
994 else /* token == '[' */
1000 fs
.kCodeABC(Lua
.OP_SETTABLE
, cc
.t
.info
, fs
.kExp2RK(key
), fs
.kExp2RK(val
));
1001 fs
.freereg
= reg
; /* free registers */
1004 private void lastlistfield(ConsControl cc
)
1006 if (cc
.tostore
== 0)
1008 if (hasmultret(cc
.v
.k
))
1010 fs
.kSetmultret(cc
.v
);
1011 fs
.kSetlist(cc
.t
.info
, cc
.na
, Lua
.MULTRET
);
1012 cc
.na
--; /* do not count last expression (unknown number of elements) */
1016 if (cc
.v
.k
!= Expdesc
.VVOID
)
1017 fs
.kExp2nextreg(cc
.v
);
1018 fs
.kSetlist(cc
.t
.info
, cc
.na
, cc
.tostore
);
1022 private void closelistfield(ConsControl cc
)
1024 if (cc
.v
.k
== Expdesc
.VVOID
)
1025 return; /* there is no list item */
1026 fs
.kExp2nextreg(cc
.v
);
1027 cc
.v
.k
= Expdesc
.VVOID
;
1028 if (cc
.tostore
== Lua
.LFIELDS_PER_FLUSH
)
1030 fs
.kSetlist(cc
.t
.info
, cc
.na
, cc
.tostore
); /* flush */
1031 cc
.tostore
= 0; /* no more items pending */
1035 private void expr(Expdesc v
) throws IOException
1040 /** @return number of expressions in expression list. */
1041 private int explist1(Expdesc v
) throws IOException
1043 // explist1 -> expr { ',' expr }
1044 int n
= 1; // at least one expression
1046 while (testnext(','))
1055 private void exprstat() throws IOException
1057 // stat -> func | assignment
1058 LHSAssign v
= new LHSAssign() ;
1060 if (v
.v
.k
== Expdesc
.VCALL
) // stat -> func
1062 fs
.setargc(v
.v
, 1); // call statement uses no results
1064 else // stat -> assignment
1072 ** check whether, in an assignment to a local variable, the local variable
1073 ** is needed in a previous assignment (to a table). If so, save original
1074 ** local value in a safe place and use this safe copy in the previous
1077 private void check_conflict(LHSAssign lh
, Expdesc v
)
1079 int extra
= fs
.freereg
; /* eventual position to save local variable */
1080 boolean conflict
= false ;
1081 for (; lh
!= null; lh
= lh
.prev
)
1083 if (lh
.v
.k
== Expdesc
.VINDEXED
)
1085 if (lh
.v
.info
== v
.info
) /* conflict? */
1088 lh
.v
.info
= extra
; /* previous assignment will use safe copy */
1090 if (lh
.v
.aux
== v
.info
) /* conflict? */
1093 lh
.v
.aux
= extra
; /* previous assignment will use safe copy */
1099 fs
.kCodeABC(Lua
.OP_MOVE
, fs
.freereg
, v
.info
, 0); /* make copy */
1104 private void assignment(LHSAssign lh
, int nvars
) throws IOException
1106 Expdesc e
= new Expdesc() ;
1108 if (!(Expdesc
.VLOCAL
<= kind
&& kind
<= Expdesc
.VINDEXED
))
1109 xSyntaxerror("syntax error");
1110 if (testnext(',')) /* assignment -> `,' primaryexp assignment */
1112 LHSAssign nv
= new LHSAssign(lh
) ;
1114 if (nv
.v
.k
== Expdesc
.VLOCAL
)
1115 check_conflict(lh
, nv
.v
);
1116 assignment(nv
, nvars
+1);
1118 else /* assignment -> `=' explist1 */
1122 nexps
= explist1(e
);
1125 adjust_assign(nvars
, nexps
, e
);
1127 fs
.freereg
-= nexps
- nvars
; /* remove extra values */
1131 fs
.kSetoneret(e
); /* close last expression */
1132 fs
.kStorevar(lh
.v
, e
);
1133 return; /* avoid default */
1136 e
.init(Expdesc
.VNONRELOC
, fs
.freereg
-1); /* default assignment */
1137 fs
.kStorevar(lh
.v
, e
);
1141 private void funcargs(Expdesc f
) throws IOException
1143 Expdesc args
= new Expdesc();
1144 int line
= linenumber
;
1147 case '(': // funcargs -> '(' [ explist1 ] ')'
1148 if (line
!= lastline
)
1150 xSyntaxerror("ambiguous syntax (function call x new statement)");
1153 if (token
== ')') // arg list is empty?
1155 args
.setKind(Expdesc
.VVOID
);
1160 fs
.kSetmultret(args
);
1162 check_match(')', '(', line
);
1165 case '{': // funcargs -> constructor
1169 case TK_STRING
: // funcargs -> STRING
1170 codestring(args
, tokenS
);
1171 xNext(); // must use tokenS before 'next'
1175 xSyntaxerror("function arguments expected");
1178 // assert (f.kind() == VNONRELOC);
1180 int base
= f
.info(); // base register for call
1181 if (args
.hasmultret())
1183 nparams
= Lua
.MULTRET
; // open call
1187 if (args
.kind() != Expdesc
.VVOID
)
1189 fs
.kExp2nextreg(args
); // close last argument
1191 nparams
= fs
.freereg
- (base
+1);
1193 f
.init(Expdesc
.VCALL
, fs
.kCodeABC(Lua
.OP_CALL
, base
, nparams
+1, 2));
1195 fs
.freereg
= base
+1; // call removes functions and arguments
1196 // and leaves (unless changed) one result.
1199 private void prefixexp(Expdesc v
) throws IOException
1201 // prefixexp -> NAME | '(' expr ')'
1206 int line
= linenumber
;
1209 check_match(')', '(', line
);
1210 fs
.kDischargevars(v
);
1217 xSyntaxerror("unexpected symbol");
1222 private void primaryexp(Expdesc v
) throws IOException
1225 // prefixexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs }
1231 case '.': /* field */
1235 case '[': /* `[' exp1 `]' */
1237 Expdesc key
= new Expdesc();
1240 fs
.kIndexed(v
, key
);
1244 case ':': /* `:' NAME funcargs */
1246 Expdesc key
= new Expdesc() ;
1256 case '{': // funcargs
1267 private void retstat() throws IOException
1269 // stat -> RETURN explist
1270 xNext(); // skip RETURN
1271 // registers with returned values (first, nret)
1274 if (block_follow(token
) || token
== ';')
1282 Expdesc e
= new Expdesc();
1284 if (hasmultret(e
.k
))
1287 if (e
.k
== Expdesc
.VCALL
&& nret
== 1) /* tail call? */
1289 fs
.setcode(e
, Lua
.SET_OPCODE(fs
.getcode(e
), Lua
.OP_TAILCALL
));
1290 //# assert Lua.ARGA(fs.getcode(e)) == fs.nactvar
1293 nret
= Lua
.MULTRET
; /* return all values */
1297 if (nret
== 1) // only one single value?
1299 first
= fs
.kExp2anyreg(e
);
1303 fs
.kExp2nextreg(e
); /* values must go to the `stack' */
1304 first
= fs
.nactvar
; /* return all `active' values */
1305 //# assert nret == fs.freereg - first
1309 fs
.kRet(first
, nret
);
1312 private void simpleexp(Expdesc v
) throws IOException
1314 // simpleexp -> NUMBER | STRING | NIL | true | false | ... |
1315 // constructor | FUNCTION body | primaryexp
1319 v
.init(Expdesc
.VKNUM
, 0);
1324 codestring(v
, tokenS
);
1328 v
.init(Expdesc
.VNIL
, 0);
1332 v
.init(Expdesc
.VTRUE
, 0);
1336 v
.init(Expdesc
.VFALSE
, 0);
1339 case TK_DOTS
: /* vararg */
1340 if (!fs
.f
.isVararg())
1341 xSyntaxerror("cannot use \"...\" outside a vararg function");
1342 v
.init(Expdesc
.VVARARG
, fs
.kCodeABC(Lua
.OP_VARARG
, 0, 1, 0));
1345 case '{': /* constructor */
1351 body(v
, false, linenumber
);
1361 private boolean statement() throws IOException
1363 int line
= linenumber
;
1366 case TK_IF
: // stat -> ifstat
1370 case TK_WHILE
: // stat -> whilestat
1374 case TK_DO
: // stat -> DO block END
1377 check_match(TK_END
, TK_DO
, line
);
1380 case TK_FOR
: // stat -> forstat
1384 case TK_REPEAT
: // stat -> repeatstat
1389 funcstat(line
); // stat -> funcstat
1392 case TK_LOCAL
: // stat -> localstat
1393 xNext(); // skip LOCAL
1394 if (testnext(TK_FUNCTION
)) // local function?
1402 return true; // must be last statement
1404 case TK_BREAK
: // stat -> breakstat
1405 xNext(); // skip BREAK
1407 return true; // must be last statement
1415 // grep "ORDER OPR" if you change these enums.
1416 // default access so that FuncState can access them.
1417 static final int OPR_ADD
= 0;
1418 static final int OPR_SUB
= 1;
1419 static final int OPR_MUL
= 2;
1420 static final int OPR_DIV
= 3;
1421 static final int OPR_MOD
= 4;
1422 static final int OPR_POW
= 5;
1423 static final int OPR_CONCAT
= 6;
1424 static final int OPR_NE
= 7;
1425 static final int OPR_EQ
= 8;
1426 static final int OPR_LT
= 9;
1427 static final int OPR_LE
= 10;
1428 static final int OPR_GT
= 11;
1429 static final int OPR_GE
= 12;
1430 static final int OPR_AND
= 13;
1431 static final int OPR_OR
= 14;
1432 static final int OPR_NOBINOPR
= 15;
1434 static final int OPR_MINUS
= 0;
1435 static final int OPR_NOT
= 1;
1436 static final int OPR_LEN
= 2;
1437 static final int OPR_NOUNOPR
= 3;
1439 /** Converts token into binary operator. */
1440 private static int getbinopr(int op
)
1444 case '+': return OPR_ADD
;
1445 case '-': return OPR_SUB
;
1446 case '*': return OPR_MUL
;
1447 case '/': return OPR_DIV
;
1448 case '%': return OPR_MOD
;
1449 case '^': return OPR_POW
;
1450 case TK_CONCAT
: return OPR_CONCAT
;
1451 case TK_NE
: return OPR_NE
;
1452 case TK_EQ
: return OPR_EQ
;
1453 case '<': return OPR_LT
;
1454 case TK_LE
: return OPR_LE
;
1455 case '>': return OPR_GT
;
1456 case TK_GE
: return OPR_GE
;
1457 case TK_AND
: return OPR_AND
;
1458 case TK_OR
: return OPR_OR
;
1459 default: return OPR_NOBINOPR
;
1463 private static int getunopr(int op
)
1467 case TK_NOT
: return OPR_NOT
;
1468 case '-': return OPR_MINUS
;
1469 case '#': return OPR_LEN
;
1470 default: return OPR_NOUNOPR
;
1477 * Priority table. left-priority of an operator is
1478 * <code>priority[op][0]</code>, its right priority is
1479 * <code>priority[op][1]</code>. Please do not modify this table.
1481 private static final int[][] PRIORITY
= new int[][]
1483 {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, // + - * / %
1484 {10, 9}, {5, 4}, // power and concat (right associative)
1485 {3, 3}, {3, 3}, // equality and inequality
1486 {3, 3}, {3, 3}, {3, 3}, {3, 3}, // order
1487 {2, 2}, {1, 1} // logical (and/or)
1490 /** Priority for unary operators. */
1491 private static final int UNARY_PRIORITY
= 8;
1494 * Operator precedence parser.
1495 * <code>subexpr -> (simpleexp) | unop subexpr) { binop subexpr }</code>
1496 * where <var>binop</var> is any binary operator with a priority
1497 * higher than <var>limit</var>.
1499 private int subexpr(Expdesc v
, int limit
) throws IOException
1502 int uop
= getunopr(token
);
1503 if (uop
!= OPR_NOUNOPR
)
1506 subexpr(v
, UNARY_PRIORITY
);
1513 // expand while operators have priorities higher than 'limit'
1514 int op
= getbinopr(token
);
1515 while (op
!= OPR_NOBINOPR
&& PRIORITY
[op
][0] > limit
)
1517 Expdesc v2
= new Expdesc();
1520 // read sub-expression with higher priority
1521 int nextop
= subexpr(v2
, PRIORITY
[op
][1]);
1522 fs
.kPosfix(op
, v
, v2
);
1529 private void enterblock(FuncState f
, BlockCnt bl
, boolean isbreakable
)
1531 bl
.breaklist
= FuncState
.NO_JUMP
;
1532 bl
.isbreakable
= isbreakable
;
1533 bl
.nactvar
= f
.nactvar
;
1537 //# assert f.freereg == f.nactvar
1540 private void leaveblock(FuncState f
)
1544 removevars(bl
.nactvar
);
1546 f
.kCodeABC(Lua
.OP_CLOSE
, bl
.nactvar
, 0, 0);
1547 /* loops have no body */
1548 //# assert (!bl.isbreakable) || (!bl.upval)
1549 //# assert bl.nactvar == f.nactvar
1550 f
.freereg
= f
.nactvar
; /* free registers */
1551 f
.kPatchtohere(bl
.breaklist
);
1556 ** {======================================================================
1557 ** Rules for Statements
1558 ** =======================================================================
1562 private void block() throws IOException
1564 /* block -> chunk */
1565 BlockCnt bl
= new BlockCnt() ;
1566 enterblock(fs
, bl
, false);
1568 //# assert bl.breaklist == FuncState.NO_JUMP
1572 private void breakstat()
1574 BlockCnt bl
= fs
.bl
;
1575 boolean upval
= false;
1576 while (bl
!= null && !bl
.isbreakable
)
1582 xSyntaxerror("no loop to break");
1584 fs
.kCodeABC(Lua
.OP_CLOSE
, bl
.nactvar
, 0, 0);
1585 bl
.breaklist
= fs
.kConcat(bl
.breaklist
, fs
.kJump());
1588 private void funcstat(int line
) throws IOException
1590 /* funcstat -> FUNCTION funcname body */
1591 Expdesc b
= new Expdesc() ;
1592 Expdesc v
= new Expdesc() ;
1593 xNext(); /* skip FUNCTION */
1594 boolean needself
= funcname(v
);
1595 body(b
, needself
, line
);
1597 fs
.kFixline(line
); /* definition `happens' in the first line */
1600 private void checknext(int c
) throws IOException
1606 private void parlist() throws IOException
1608 /* parlist -> [ param { `,' param } ] */
1611 if (token
!= ')') /* is `parlist' not empty? */
1617 case TK_NAME
: /* param -> NAME */
1619 new_localvar(str_checkname(), nparams
++);
1622 case TK_DOTS
: /* param -> `...' */
1628 default: xSyntaxerror("<name> or '...' expected");
1630 } while ((!f
.isVararg()) && testnext(','));
1632 adjustlocalvars(nparams
);
1633 f
.numparams
= fs
.nactvar
; /* VARARG_HASARG not now used */
1634 fs
.kReserveregs(fs
.nactvar
); /* reserve register for parameters */
1638 private LocVar
getlocvar(int i
)
1640 FuncState fstate
= fs
;
1641 return fstate
.f
.locvars
[fstate
.actvar
[i
]] ;
1644 private void adjustlocalvars(int nvars
)
1646 fs
.nactvar
+= nvars
;
1647 for (; nvars
!= 0; nvars
--)
1649 getlocvar(fs
.nactvar
- nvars
).startpc
= fs
.pc
;
1653 private void new_localvarliteral(String v
, int n
)
1655 new_localvar(v
, n
) ;
1658 private void errorlimit(int limit
, String what
)
1660 String msg
= fs
.f
.linedefined
== 0 ?
1661 "main function has more than "+limit
+" "+what
:
1662 "function at line "+fs
.f
.linedefined
+" has more than "+limit
+" "+what
;
1667 private void yChecklimit(int v
, int l
, String m
)
1673 private void new_localvar(String name
, int n
)
1675 yChecklimit(fs
.nactvar
+n
+1, Lua
.MAXVARS
, "local variables");
1676 fs
.actvar
[fs
.nactvar
+n
] = (short)registerlocalvar(name
);
1679 private int registerlocalvar(String varname
)
1682 f
.ensureLocvars(L
, fs
.nlocvars
, Short
.MAX_VALUE
) ;
1683 f
.locvars
[fs
.nlocvars
].varname
= varname
;
1684 return fs
.nlocvars
++;
1688 private void body(Expdesc e
, boolean needself
, int line
) throws IOException
1690 /* body -> `(' parlist `)' chunk END */
1691 FuncState new_fs
= new FuncState(this);
1693 new_fs
.f
.linedefined
= line
;
1697 new_localvarliteral("self", 0);
1703 new_fs
.f
.lastlinedefined
= linenumber
;
1704 check_match(TK_END
, TK_FUNCTION
, line
);
1706 pushclosure(new_fs
, e
);
1709 private int UPVAL_K(int upvaldesc
)
1711 return (upvaldesc
>>> 8) & 0xFF ;
1713 private int UPVAL_INFO(int upvaldesc
)
1715 return upvaldesc
& 0xFF ;
1717 private int UPVAL_ENCODE(int k
, int info
)
1719 //# assert (k & 0xFF) == k && (info & 0xFF) == info
1720 return ((k
& 0xFF) << 8) | (info
& 0xFF) ;
1724 private void pushclosure(FuncState func
, Expdesc v
)
1727 f
.ensureProtos(L
, fs
.np
) ;
1730 v
.init(Expdesc
.VRELOCABLE
, fs
.kCodeABx(Lua
.OP_CLOSURE
, 0, fs
.np
-1));
1731 for (int i
=0; i
< ff
.nups
; i
++)
1733 int upvalue
= func
.upvalues
[i
] ;
1734 int o
= (UPVAL_K(upvalue
) == Expdesc
.VLOCAL
) ? Lua
.OP_MOVE
:
1736 fs
.kCodeABC(o
, 0, UPVAL_INFO(upvalue
), 0);
1740 private boolean funcname(Expdesc v
) throws IOException
1742 /* funcname -> NAME {field} [`:' NAME] */
1743 boolean needself
= false;
1745 while (token
== '.')
1755 private void field(Expdesc v
) throws IOException
1757 /* field -> ['.' | ':'] NAME */
1758 Expdesc key
= new Expdesc() ;
1760 xNext(); /* skip the dot or colon */
1762 fs
.kIndexed(v
, key
);
1765 private void repeatstat(int line
) throws IOException
1767 /* repeatstat -> REPEAT block UNTIL cond */
1768 int repeat_init
= fs
.kGetlabel();
1769 BlockCnt bl1
= new BlockCnt();
1770 BlockCnt bl2
= new BlockCnt();
1771 enterblock(fs
, bl1
, true); /* loop block */
1772 enterblock(fs
, bl2
, false); /* scope block */
1773 xNext(); /* skip REPEAT */
1775 check_match(TK_UNTIL
, TK_REPEAT
, line
);
1776 int condexit
= cond(); /* read condition (inside scope block) */
1777 if (!bl2
.upval
) /* no upvalues? */
1779 leaveblock(fs
); /* finish scope */
1780 fs
.kPatchlist(condexit
, repeat_init
); /* close the loop */
1782 else /* complete semantics when there are upvalues */
1784 breakstat(); /* if condition then break */
1785 fs
.kPatchtohere(condexit
); /* else... */
1786 leaveblock(fs
); /* finish scope... */
1787 fs
.kPatchlist(fs
.kJump(), repeat_init
); /* and repeat */
1789 leaveblock(fs
); /* finish loop */
1792 private int cond() throws IOException
1795 Expdesc v
= new Expdesc() ;
1796 expr(v
); /* read condition */
1797 if (v
.k
== Expdesc
.VNIL
)
1798 v
.k
= Expdesc
.VFALSE
; /* `falses' are all equal here */
1803 private void open_func(FuncState funcstate
)
1805 Proto f
= new Proto(source
, 2); /* registers 0/1 are always valid */
1807 funcstate
.ls
= this;
1810 funcstate
.prev
= this.fs
; /* linked list of funcstates */
1811 this.fs
= funcstate
;
1814 private void localstat() throws IOException
1816 /* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */
1819 Expdesc e
= new Expdesc();
1822 new_localvar(str_checkname(), nvars
++);
1823 } while (testnext(','));
1826 nexps
= explist1(e
);
1830 e
.k
= Expdesc
.VVOID
;
1833 adjust_assign(nvars
, nexps
, e
);
1834 adjustlocalvars(nvars
);
1837 private void forstat(int line
) throws IOException
1839 /* forstat -> FOR (fornum | forlist) END */
1840 BlockCnt bl
= new BlockCnt() ;
1841 enterblock(fs
, bl
, true); /* scope for loop and control variables */
1842 xNext(); /* skip `for' */
1843 String varname
= str_checkname(); /* first variable name */
1847 fornum(varname
, line
);
1854 xSyntaxerror("\"=\" or \"in\" expected");
1856 check_match(TK_END
, TK_FOR
, line
);
1857 leaveblock(fs
); /* loop scope (`break' jumps to this point) */
1860 private void fornum(String varname
, int line
) throws IOException
1862 /* fornum -> NAME = exp1,exp1[,exp1] forbody */
1863 int base
= fs
.freereg
;
1864 new_localvarliteral("(for index)", 0);
1865 new_localvarliteral("(for limit)", 1);
1866 new_localvarliteral("(for step)", 2);
1867 new_localvar(varname
, 3);
1869 exp1(); /* initial value */
1873 exp1(); /* optional step */
1874 else /* default step = 1 */
1876 fs
.kCodeABx(Lua
.OP_LOADK
, fs
.freereg
, fs
.kNumberK(1));
1879 forbody(base
, line
, 1, true);
1882 private int exp1() throws IOException
1884 Expdesc e
= new Expdesc();
1892 private void forlist(String indexname
) throws IOException
1894 /* forlist -> NAME {,NAME} IN explist1 forbody */
1895 Expdesc e
= new Expdesc() ;
1897 int base
= fs
.freereg
;
1898 /* create control variables */
1899 new_localvarliteral("(for generator)", nvars
++);
1900 new_localvarliteral("(for state)", nvars
++);
1901 new_localvarliteral("(for control)", nvars
++);
1902 /* create declared variables */
1903 new_localvar(indexname
, nvars
++);
1904 while (testnext(','))
1905 new_localvar(str_checkname(), nvars
++);
1907 int line
= linenumber
;
1908 adjust_assign(3, explist1(e
), e
);
1909 fs
.kCheckstack(3); /* extra space to call generator */
1910 forbody(base
, line
, nvars
- 3, false);
1913 private void forbody(int base
, int line
, int nvars
, boolean isnum
)
1916 /* forbody -> DO block */
1917 BlockCnt bl
= new BlockCnt() ;
1918 adjustlocalvars(3); /* control variables */
1920 int prep
= isnum ? fs
.kCodeAsBx(Lua
.OP_FORPREP
, base
, FuncState
.NO_JUMP
) : fs
.kJump();
1921 enterblock(fs
, bl
, false); /* scope for declared variables */
1922 adjustlocalvars(nvars
);
1923 fs
.kReserveregs(nvars
);
1925 leaveblock(fs
); /* end of scope for declared variables */
1926 fs
.kPatchtohere(prep
);
1927 int endfor
= isnum ?
1928 fs
.kCodeAsBx(Lua
.OP_FORLOOP
, base
, FuncState
.NO_JUMP
) :
1929 fs
.kCodeABC(Lua
.OP_TFORLOOP
, base
, 0, nvars
);
1930 fs
.kFixline(line
); /* pretend that `OP_FOR' starts the loop */
1931 fs
.kPatchlist((isnum ? endfor
: fs
.kJump()), prep
+ 1);
1934 private void ifstat(int line
) throws IOException
1936 /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */
1937 int escapelist
= FuncState
.NO_JUMP
;
1938 int flist
= test_then_block(); /* IF cond THEN block */
1939 while (token
== TK_ELSEIF
)
1941 escapelist
= fs
.kConcat(escapelist
, fs
.kJump());
1942 fs
.kPatchtohere(flist
);
1943 flist
= test_then_block(); /* ELSEIF cond THEN block */
1945 if (token
== TK_ELSE
)
1947 escapelist
= fs
.kConcat(escapelist
, fs
.kJump());
1948 fs
.kPatchtohere(flist
);
1949 xNext(); /* skip ELSE (after patch, for correct line info) */
1950 block(); /* `else' part */
1953 escapelist
= fs
.kConcat(escapelist
, flist
);
1955 fs
.kPatchtohere(escapelist
);
1956 check_match(TK_END
, TK_IF
, line
);
1959 private int test_then_block() throws IOException
1961 /* test_then_block -> [IF | ELSEIF] cond THEN block */
1962 xNext(); /* skip IF or ELSEIF */
1963 int condexit
= cond();
1965 block(); /* `then' part */
1969 private void whilestat(int line
) throws IOException
1971 /* whilestat -> WHILE cond DO block END */
1972 BlockCnt bl
= new BlockCnt() ;
1973 xNext(); /* skip WHILE */
1974 int whileinit
= fs
.kGetlabel();
1975 int condexit
= cond();
1976 enterblock(fs
, bl
, true);
1979 fs
.kPatchlist(fs
.kJump(), whileinit
);
1980 check_match(TK_END
, TK_WHILE
, line
);
1982 fs
.kPatchtohere(condexit
); /* false conditions finish the loop */
1985 private static boolean hasmultret(int k
)
1987 return k
== Expdesc
.VCALL
|| k
== Expdesc
.VVARARG
;
1990 private void adjust_assign(int nvars
, int nexps
, Expdesc e
)
1992 int extra
= nvars
- nexps
;
1993 if (hasmultret(e
.k
))
1995 extra
++; /* includes call itself */
1998 fs
.kSetreturns(e
, extra
); /* last exp. provides the difference */
2000 fs
.kReserveregs(extra
-1);
2004 if (e
.k
!= Expdesc
.VVOID
)
2005 fs
.kExp2nextreg(e
); /* close last expression */
2008 int reg
= fs
.freereg
;
2009 fs
.kReserveregs(extra
);
2010 fs
.kNil(reg
, extra
);
2015 private void localfunc() throws IOException
2017 Expdesc b
= new Expdesc();
2018 new_localvar(str_checkname(), 0);
2019 Expdesc v
= new Expdesc(Expdesc
.VLOCAL
, fs
.freereg
);
2022 body(b
, false, linenumber
);
2024 /* debug information will only see the variable after this point! */
2025 fs
.getlocvar(fs
.nactvar
- 1).startpc
= fs
.pc
;
2028 private void yindex(Expdesc v
) throws IOException
2030 /* index -> '[' expr ']' */
2031 xNext(); /* skip the '[' */
2037 void xLookahead() throws IOException
2039 //# assert lookahead == TK_EOS
2045 private void listfield(ConsControl cc
) throws IOException
2048 yChecklimit(cc
.na
, Lua
.MAXARG_Bx
, "items in a constructor");
2053 private int indexupvalue(FuncState funcstate
, String name
, Expdesc v
)
2055 Proto f
= funcstate
.f
;
2056 for (int i
=0; i
<f
.nups
; i
++)
2058 int entry
= funcstate
.upvalues
[i
] ;
2059 if (UPVAL_K(entry
) == v
.k
&& UPVAL_INFO(entry
) == v
.info
)
2061 //# assert name.equals(f.upvalues[i])
2066 yChecklimit(f
.nups
+ 1, Lua
.MAXUPVALUES
, "upvalues");
2067 f
.ensureUpvals(L
, f
.nups
) ;
2068 f
.upvalues
[f
.nups
] = name
;
2069 //# assert v.k == Expdesc.VLOCAL || v.k == Expdesc.VUPVAL
2070 funcstate
.upvalues
[f
.nups
] = UPVAL_ENCODE(v
.k
, v
.info
) ;
2075 final class LHSAssign
2078 Expdesc v
= new Expdesc() ;
2083 LHSAssign(LHSAssign prev
)
2089 final class ConsControl
2091 Expdesc v
= new Expdesc() ; /* last list item read */
2092 Expdesc t
; /* table descriptor */
2093 int nh
; /* total number of `record' elements */
2094 int na
; /* total number of array elements */
2095 int tostore
; /* number of array elements pending to be stored */
2097 ConsControl(Expdesc t
)