532 lines
13 KiB
Plaintext
532 lines
13 KiB
Plaintext
/*******************************************************************************
|
|
* Copyright (c) 2010-2012 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.
|
|
******************************************************************************/
|
|
/**
|
|
* Javacc grammar used to produce a parse tree. Based on lua 5.2 syntax.
|
|
*
|
|
*/
|
|
|
|
options {
|
|
STATIC = false;
|
|
JDK_VERSION = "1.3";
|
|
ERROR_REPORTING = false;
|
|
UNICODE_INPUT = true;
|
|
DEBUG_LOOKAHEAD = false;
|
|
DEBUG_PARSER = false;
|
|
DEBUG_TOKEN_MANAGER = false;
|
|
OUTPUT_DIRECTORY = "src/jse/org/luaj/vm2/parser";
|
|
}
|
|
|
|
PARSER_BEGIN(LuaParser)
|
|
package org.luaj.vm2.parser;
|
|
import org.luaj.vm2.*;
|
|
import org.luaj.vm2.ast.*;
|
|
import java.util.*;
|
|
|
|
public class LuaParser {
|
|
static {
|
|
LuaValue.valueOf(true);
|
|
}
|
|
|
|
public static void main(String args[]) throws ParseException {
|
|
LuaParser parser = new LuaParser(System.in);
|
|
parser.Chunk();
|
|
}
|
|
|
|
private static Exp.VarExp assertvarexp(Exp.PrimaryExp pe) throws ParseException {
|
|
if (!pe.isvarexp())
|
|
throw new ParseException("expected variable");
|
|
return (Exp.VarExp) pe;
|
|
}
|
|
|
|
private static Exp.FuncCall assertfunccall(Exp.PrimaryExp pe) throws ParseException {
|
|
if (!pe.isfunccall())
|
|
throw new ParseException("expected function call");
|
|
return (Exp.FuncCall) pe;
|
|
}
|
|
|
|
public SimpleCharStream getCharStream() {
|
|
return jj_input_stream;
|
|
}
|
|
|
|
private long LineInfo() {
|
|
return ((long) jj_input_stream.getBeginLine() << 32) | jj_input_stream.getBeginColumn();
|
|
}
|
|
|
|
private void L(SyntaxElement e, long startinfo) {
|
|
e.beginLine = (int) (startinfo >> 32);
|
|
e.beginColumn = (short) startinfo;
|
|
e.endLine = token.endLine;
|
|
e.endColumn = (short) token.endColumn;
|
|
}
|
|
|
|
private void L(SyntaxElement e, Token starttoken) {
|
|
e.beginLine = starttoken.beginLine;
|
|
e.beginColumn = (short) starttoken.beginColumn;
|
|
e.endLine = token.endLine;
|
|
e.endColumn = (short) token.endColumn;
|
|
}
|
|
|
|
}
|
|
|
|
PARSER_END(LuaParser)
|
|
|
|
/* WHITE SPACE */
|
|
|
|
SKIP :
|
|
{
|
|
" " | "\t" | "\n" | "\r" | "\f"
|
|
}
|
|
|
|
/* COMMENTS and LONG STRINGS */
|
|
|
|
MORE :
|
|
{
|
|
"--[[": IN_LC0
|
|
| "--[=[": IN_LC1
|
|
| "--[==[": IN_LC2
|
|
| "--[===[": IN_LC3
|
|
| < "--[====" ("=")* "[" > : IN_LCN
|
|
| "[[" : IN_LS0
|
|
| "[=[" : IN_LS1
|
|
| "[==[" : IN_LS2
|
|
| "[===[" : IN_LS3
|
|
| < "[====" ("=")* "[" > : IN_LSN
|
|
| "--" : IN_COMMENT
|
|
}
|
|
|
|
<IN_COMMENT> SPECIAL_TOKEN :
|
|
{
|
|
<COMMENT: (~["\n","\r"])* ("\n"|"\r"|"\r\n")? > : DEFAULT
|
|
}
|
|
|
|
<IN_LC0> SPECIAL_TOKEN : { <LONGCOMMENT0: "]]" > : DEFAULT }
|
|
<IN_LC1> SPECIAL_TOKEN : { <LONGCOMMENT1: "]=]" > : DEFAULT }
|
|
<IN_LC2> SPECIAL_TOKEN : { <LONGCOMMENT2: "]==]" > : DEFAULT }
|
|
<IN_LC3> SPECIAL_TOKEN : { <LONGCOMMENT3: "]===]" > : DEFAULT }
|
|
<IN_LCN> SPECIAL_TOKEN : { <LONGCOMMENTN: "]====" ("=")* "]" > : DEFAULT }
|
|
|
|
<IN_LS0> TOKEN : { <LONGSTRING0: "]]" > : DEFAULT }
|
|
<IN_LS1> TOKEN : { <LONGSTRING1: "]=]" > : DEFAULT }
|
|
<IN_LS2> TOKEN : { <LONGSTRING2: "]==]" > : DEFAULT }
|
|
<IN_LS3> TOKEN : { <LONGSTRING3: "]===]" > : DEFAULT }
|
|
<IN_LSN> TOKEN : { <LONGSTRINGN: "]====" ("=")* "]" > : DEFAULT }
|
|
|
|
<IN_LC0,IN_LC1,IN_LC2,IN_LC3,IN_LCN,IN_LS0,IN_LS1,IN_LS2,IN_LS3,IN_LSN> MORE :
|
|
{
|
|
< ~[] >
|
|
}
|
|
|
|
|
|
/* RESERVED WORDS AND LITERALS */
|
|
|
|
TOKEN :
|
|
{
|
|
<AND: "and">
|
|
| <BREAK: "break">
|
|
| <DO: "do">
|
|
| <ELSE: "else">
|
|
| <ELSEIF: "elseif">
|
|
| <END: "end">
|
|
| <FALSE: "false">
|
|
| <FOR: "for">
|
|
| <FUNCTION: "function">
|
|
| <GOTO: "goto">
|
|
| <IF: "if">
|
|
| <IN: "in">
|
|
| <LOCAL: "local">
|
|
| <NIL: "nil">
|
|
| <NOT: "not">
|
|
| <OR: "or">
|
|
| <RETURN: "return">
|
|
| <REPEAT: "repeat">
|
|
| <THEN: "then">
|
|
| <TRUE: "true">
|
|
| <UNTIL: "until">
|
|
| <WHILE: "while">
|
|
}
|
|
|
|
/* LITERALS */
|
|
|
|
TOKEN :
|
|
{
|
|
< NAME: ["a"-"z", "A"-"Z", "_"] (["a"-"z", "A"-"Z", "_", "0"-"9"])* >
|
|
| < NUMBER: <HEX> | <FLOAT> >
|
|
| < #FLOAT: <FNUM> (<EXP>)? >
|
|
| < #FNUM: (<DIGIT>)+ "." (<DIGIT>)* | "." (<DIGIT>)+ | (<DIGIT>)+ >
|
|
| < #DIGIT: ["0"-"9"] >
|
|
| < #EXP: ["e","E"] (["+","-"])? (<DIGIT>)+ >
|
|
| < #HEX: "0" ["x","X"] <HEXNUM> (<HEXEXP>)? >
|
|
| < #HEXNUM: (<HEXDIGIT>)+ "." (<HEXDIGIT>)* | "." (<HEXDIGIT>)+ | (<HEXDIGIT>)+ >
|
|
| < #HEXDIGIT: ["0"-"9","a"-"f","A"-"F"] >
|
|
| < #HEXEXP: ["e","E","p","P"] (["+","-"])? (<DIGIT>)+ >
|
|
| < STRING: "\"" (<QUOTED> | ~["\\","\""])* "\"" >
|
|
| < CHARSTRING: "'" (<QUOTED> | ~["\\","'"])* "'" >
|
|
| < #QUOTED: <DECIMAL> | <UNICODE> | <CHAR> >
|
|
| < #DECIMAL: "\\" ["0"-"9"] (["0"-"9"])? (["0"-"9"])? >
|
|
| < DBCOLON: "::" >
|
|
| < #UNICODE: "\\" "u" <HEXDIGIT> <HEXDIGIT> <HEXDIGIT> <HEXDIGIT> >
|
|
| < #CHAR: "\\" (~[]) >
|
|
| < #LF: ("\n" | "\r" | "\r\n") >
|
|
}
|
|
|
|
/** Root production. */
|
|
Chunk Chunk():
|
|
{
|
|
Block b;
|
|
Chunk c;
|
|
long i = LineInfo();
|
|
}
|
|
{
|
|
( "#" { token_source.SwitchTo(IN_COMMENT); } )? b=Block() <EOF> { c=new Chunk(b); L(c,i); return c; }
|
|
}
|
|
|
|
Block Block():
|
|
{
|
|
Block b = new Block();
|
|
Stat s;
|
|
long i = LineInfo();
|
|
}
|
|
{
|
|
(s=Stat() {b.add(s);} )* (s=ReturnStat() {b.add(s);} )? { L(b,i); return b; }
|
|
}
|
|
|
|
Stat Stat():
|
|
{
|
|
Block b,b2;
|
|
Exp e,e2,e3=null;
|
|
Stat s;
|
|
FuncName fn;
|
|
FuncBody fb;
|
|
Token n;
|
|
List<Name> nl;
|
|
List<Exp> el=null;
|
|
long i = LineInfo();
|
|
}
|
|
{
|
|
";" { return null; }
|
|
| s=Label() { L(s,i); return s; }
|
|
| <BREAK> { s=Stat.breakstat(); L(s,i); return s; }
|
|
| <GOTO> n=<NAME> { s=Stat.gotostat(n.image); L(s,i); return s; }
|
|
| <DO> b=Block() <END> { s=Stat.block(b); L(s,i); return s; }
|
|
| <WHILE> e=Exp() <DO> b=Block() <END> { s=Stat.whiledo(e,b); L(s,i); return s; }
|
|
| <REPEAT> b=Block() <UNTIL> e=Exp() { s=Stat.repeatuntil(b,e); L(s,i); return s; }
|
|
| s=IfThenElse() { L(s,i); return s; }
|
|
| LOOKAHEAD(3) <FOR> n=<NAME> "=" e=Exp() "," e2=Exp() ( "," e3=Exp() )? <DO> b=Block() <END> { s=Stat.fornumeric(n.image,e,e2,e3,b); L(s,i); return s; }
|
|
| <FOR> nl=NameList() <IN> el=ExpList() <DO> b=Block() <END> { s=Stat.forgeneric(nl,el,b); L(s,i); return s; }
|
|
| <FUNCTION> fn=FuncName() fb=FuncBody() { s=Stat.functiondef(fn,fb); L(s,i); return s; }
|
|
| LOOKAHEAD(2) <LOCAL> <FUNCTION> n=<NAME> fb=FuncBody() { s=Stat.localfunctiondef(n.image,fb); L(s,i); return s; }
|
|
| <LOCAL> nl=NameList() ( "=" el=ExpList() )? { s=Stat.localassignment(nl,el); L(s,i); return s; }
|
|
| s=ExprStat() { L(s,i); return s; }
|
|
}
|
|
|
|
Stat IfThenElse():
|
|
{
|
|
Block b,b2,b3=null;
|
|
Exp e,e2;
|
|
List<Exp> el=null;
|
|
List<Block> bl=null;
|
|
}
|
|
{
|
|
<IF> e=Exp()
|
|
<THEN> b=Block()
|
|
(<ELSEIF> e2=Exp() <THEN> b2=Block() {
|
|
if (el==null) el=new ArrayList<Exp>();
|
|
if (bl==null) bl=new ArrayList<Block>();
|
|
el.add(e2);
|
|
bl.add(b2);
|
|
} )*
|
|
(<ELSE> b3=Block())? <END>
|
|
{ return Stat.ifthenelse(e,b,el,bl,b3); }
|
|
}
|
|
|
|
Stat ReturnStat():
|
|
{
|
|
List<Exp> el=null;
|
|
Stat s;
|
|
long i = LineInfo();
|
|
}
|
|
{
|
|
<RETURN> ( el=ExpList() )? ( ";" )? { s=Stat.returnstat(el); L(s,i); return s; }
|
|
}
|
|
|
|
Stat Label():
|
|
{
|
|
Token n;
|
|
}
|
|
{
|
|
<DBCOLON> n=<NAME> <DBCOLON> { return Stat.labelstat(n.image); }
|
|
}
|
|
|
|
Stat ExprStat():
|
|
{
|
|
Exp.PrimaryExp p;
|
|
Stat s=null;
|
|
long i = LineInfo();
|
|
}
|
|
{
|
|
p=PrimaryExp() ( s=Assign(assertvarexp(p)) )?
|
|
{ if (s==null) { s=Stat.functioncall(assertfunccall(p)); } L(s,i); return s; }
|
|
}
|
|
|
|
Stat Assign(Exp.VarExp v0):
|
|
{
|
|
List<Exp.VarExp> vl = new ArrayList<Exp.VarExp>();
|
|
vl.add(v0);
|
|
Exp.VarExp ve;
|
|
List<Exp> el;
|
|
Stat s;
|
|
long i = LineInfo();
|
|
}
|
|
{
|
|
( "," ve=VarExp() { vl.add(ve); } )* "=" el=ExpList() { s=Stat.assignment(vl,el); L(s,i); return s; }
|
|
}
|
|
|
|
Exp.VarExp VarExp():
|
|
{
|
|
Exp.PrimaryExp p;
|
|
}
|
|
{
|
|
p=PrimaryExp() { return assertvarexp(p); }
|
|
}
|
|
|
|
FuncName FuncName():
|
|
{
|
|
Token n;
|
|
FuncName f;
|
|
}
|
|
{
|
|
n=<NAME> {f=new FuncName(n.image);}
|
|
( "." n=<NAME> {f.adddot(n.image);} )*
|
|
( ":" n=<NAME> {f.method=n.image;} )?
|
|
{L(f,n); return f;}
|
|
}
|
|
|
|
Exp.PrimaryExp PrefixExp():
|
|
{
|
|
Token n;
|
|
Exp e;
|
|
Exp.PrimaryExp p;
|
|
long i = LineInfo();
|
|
}
|
|
{
|
|
n=<NAME> { p=Exp.nameprefix(n.image); L(p,i); return p; }
|
|
| "(" e=Exp() ")" { p=Exp.parensprefix(e); L(p,i); return p; }
|
|
}
|
|
|
|
Exp.PrimaryExp PrimaryExp():
|
|
{
|
|
Exp.PrimaryExp p;
|
|
long i = LineInfo();
|
|
}
|
|
{
|
|
p=PrefixExp() ( LOOKAHEAD(2) p=PostfixOp(p) )* { L(p,i); return p; }
|
|
}
|
|
|
|
Exp.PrimaryExp PostfixOp(Exp.PrimaryExp lhs):
|
|
{
|
|
Token n;
|
|
Exp e;
|
|
FuncArgs a;
|
|
Exp.PrimaryExp p;
|
|
long i = LineInfo();
|
|
}
|
|
{
|
|
"." n=<NAME> { p=Exp.fieldop(lhs, n.image); L(p,i); return p; }
|
|
| "[" e=Exp() "]" { p=Exp.indexop(lhs, e); L(p,i); return p; }
|
|
| ":" n=<NAME> a=FuncArgs() { p=Exp.methodop(lhs, n.image,a); L(p,i); return p; }
|
|
| a=FuncArgs() { p=Exp.functionop(lhs, a); L(p,i); return p; }
|
|
}
|
|
|
|
FuncArgs FuncArgs():
|
|
{
|
|
List<Exp> el=null;
|
|
TableConstructor tc;
|
|
LuaString s;
|
|
FuncArgs a;
|
|
long i = LineInfo();
|
|
}
|
|
{
|
|
"(" ( el=ExpList() )? ")" { a=FuncArgs.explist(el); L(a,i); return a; }
|
|
| tc=TableConstructor() { a=FuncArgs.tableconstructor(tc); L(a,i); return a; }
|
|
| s=Str() { a=FuncArgs.string(s); L(a,i); return a; }
|
|
}
|
|
|
|
List<Name> NameList():
|
|
{
|
|
List<Name> l = new ArrayList<Name>();
|
|
Token name;
|
|
}
|
|
{
|
|
name=<NAME> {l.add(new Name(name.image));} ( LOOKAHEAD(2) "," name=<NAME> {l.add(new Name(name.image));} )* {return l;}
|
|
}
|
|
|
|
List<Exp> ExpList():
|
|
{
|
|
List<Exp> l = new ArrayList<Exp>();
|
|
Exp e;
|
|
}
|
|
{
|
|
e=Exp() {l.add(e);} ( "," e=Exp() {l.add(e);} )* {return l;}
|
|
}
|
|
|
|
Exp SimpleExp():
|
|
{
|
|
Token n;
|
|
LuaString s;
|
|
Exp e;
|
|
TableConstructor c;
|
|
FuncBody b;
|
|
long i = LineInfo();
|
|
}
|
|
{
|
|
<NIL> { e=Exp.constant(LuaValue.NIL); L(e,i); return e; }
|
|
| <TRUE> { e=Exp.constant(LuaValue.TRUE); L(e,i); return e; }
|
|
| <FALSE> { e=Exp.constant(LuaValue.FALSE); L(e,i); return e; }
|
|
| n=<NUMBER> { e=Exp.numberconstant(n.image); L(e,i); return e; }
|
|
| s=Str() { e=Exp.constant(s); L(e,i); return e; }
|
|
| "..." { e=Exp.varargs(); L(e,i); return e; }
|
|
| c=TableConstructor() { e=Exp.tableconstructor(c); L(e,i); return e; }
|
|
| b=FunctionCall() { e=Exp.anonymousfunction(b); L(e,i); return e; }
|
|
| e=PrimaryExp() { return e; }
|
|
}
|
|
|
|
LuaString Str():
|
|
{}
|
|
{
|
|
<STRING> { return Str.quoteString(token.image); }
|
|
| <CHARSTRING> { return Str.charString(token.image); }
|
|
| <LONGSTRING0> { return Str.longString(token.image); }
|
|
| <LONGSTRING1> { return Str.longString(token.image); }
|
|
| <LONGSTRING2> { return Str.longString(token.image); }
|
|
| <LONGSTRING3> { return Str.longString(token.image); }
|
|
| <LONGSTRINGN> { return Str.longString(token.image); }
|
|
}
|
|
|
|
Exp Exp():
|
|
{
|
|
Exp e,s;
|
|
int op;
|
|
long i = LineInfo();
|
|
}
|
|
{
|
|
( e=SimpleExp() | op=Unop() s=Exp() {e=Exp.unaryexp(op,s);})
|
|
(LOOKAHEAD(2) op=Binop() s=Exp() {e=Exp.binaryexp(e,op,s);} )* { L(e,i); return e; }
|
|
}
|
|
|
|
FuncBody FunctionCall():
|
|
{
|
|
FuncBody b;
|
|
long i = LineInfo();
|
|
}
|
|
{
|
|
<FUNCTION> b=FuncBody() { L(b,i); return b; }
|
|
}
|
|
|
|
FuncBody FuncBody():
|
|
{
|
|
ParList pl=null;
|
|
Block b;
|
|
FuncBody f;
|
|
long i = LineInfo();
|
|
}
|
|
{
|
|
"(" ( pl=ParList() )? ")" b=Block() <END> { f=new FuncBody(pl,b); L(f,i); return f; }
|
|
}
|
|
|
|
ParList ParList():
|
|
{
|
|
List<Name> l=null;
|
|
boolean v=false;
|
|
ParList p;
|
|
long i = LineInfo();
|
|
}
|
|
{
|
|
l=NameList() ( "," "..." { v=true; } )? { p=new ParList(l,v); L(p,i); return p; }
|
|
| "..." { p=new ParList(null,true); L(p,i); return p; }
|
|
}
|
|
|
|
TableConstructor TableConstructor():
|
|
{
|
|
TableConstructor c = new TableConstructor();
|
|
List<TableField> l = null;
|
|
long i = LineInfo();
|
|
}
|
|
{
|
|
"{" ( l=FieldList() {c.fields=l;} )? "}" { L(c,i); return c; }
|
|
}
|
|
|
|
List<TableField> FieldList():
|
|
{
|
|
List<TableField> l = new ArrayList<TableField>();
|
|
TableField f;
|
|
}
|
|
{
|
|
f=Field() {l.add(f);} (LOOKAHEAD(2) FieldSep() f=Field() {l.add(f);})* (FieldSep())? { return l; }
|
|
}
|
|
|
|
TableField Field():
|
|
{
|
|
Token name;
|
|
Exp exp,rhs;
|
|
TableField f;
|
|
long i = LineInfo();
|
|
}
|
|
{
|
|
"[" exp=Exp() "]" "=" rhs=Exp() { f=TableField.keyedField(exp,rhs); L(f,i); return f; }
|
|
| LOOKAHEAD(2) name=<NAME> "=" rhs=Exp() { f=TableField.namedField(name.image,rhs); L(f,i); return f; }
|
|
| rhs=Exp() { f=TableField.listField(rhs); L(f,i); return f; }
|
|
}
|
|
|
|
void FieldSep():
|
|
{}
|
|
{
|
|
"," | ";"
|
|
}
|
|
|
|
int Binop():
|
|
{}
|
|
{
|
|
"+" { return Lua.OP_ADD; }
|
|
| "-" { return Lua.OP_SUB; }
|
|
| "*" { return Lua.OP_MUL; }
|
|
| "/" { return Lua.OP_DIV; }
|
|
| "^" { return Lua.OP_POW; }
|
|
| "%" { return Lua.OP_MOD; }
|
|
| ".." { return Lua.OP_CONCAT; }
|
|
| "<" { return Lua.OP_LT; }
|
|
| "<=" { return Lua.OP_LE; }
|
|
| ">" { return Lua.OP_GT; }
|
|
| ">=" { return Lua.OP_GE; }
|
|
| "==" { return Lua.OP_EQ; }
|
|
| "~=" { return Lua.OP_NEQ; }
|
|
| <AND> { return Lua.OP_AND; }
|
|
| <OR> { return Lua.OP_OR; }
|
|
}
|
|
|
|
int Unop():
|
|
{}
|
|
{
|
|
"-" { return Lua.OP_UNM; }
|
|
| <NOT> { return Lua.OP_NOT; }
|
|
| "#" { return Lua.OP_LEN; }
|
|
}
|