464 lines
11 KiB
Plaintext
464 lines
11 KiB
Plaintext
/*******************************************************************************
|
|
* Copyright (c) 2010 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.
|
|
*
|
|
*/
|
|
|
|
options {
|
|
STATIC = false;
|
|
JDK_VERSION = "1.3";
|
|
ERROR_REPORTING = false;
|
|
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 {
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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">
|
|
| <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: (<DIGIT>)+ "." (<DIGIT>)* (<EXP>)? | "." (<DIGIT>)+ (<EXP>)? | (<DIGIT>)+ (<EXP>)? >
|
|
| < #DIGIT: ["0"-"9"] >
|
|
| < #EXP: ["e","E"] (["+","-"])? (<DIGIT>)+ >
|
|
| < #HEX: "0" ["x","X"] (<HEXDIGIT>)+ >
|
|
| < #HEXDIGIT: ["0"-"9","a"-"f","A"-"F"] >
|
|
| < STRING: "\"" (<QUOTED> | ~["\\","\""])* "\"" >
|
|
| < CHARSTRING: "'" (<QUOTED> | ~["\\","'"])* "'" >
|
|
| < #QUOTED: <DECIMAL> | <UNICODE> | <CHAR> >
|
|
| < #DECIMAL: "\\" ["0"-"9"] (["0"-"9"])? (["0"-"9"])? >
|
|
| < #UNICODE: "\\" "u" <HEXDIGIT> <HEXDIGIT> <HEXDIGIT> <HEXDIGIT> >
|
|
//| < #CHAR: "\\" ("a"|"b"|"f"|"n"|"r"|"t"|"v"|"["|"]"|"'"|"\""|"\\"|"0"|<LF>) >
|
|
| < #CHAR: "\\" (~[]) >
|
|
| < #LF: ("\n" | "\r" | "\r\n") >
|
|
}
|
|
|
|
/** Root production. */
|
|
Chunk Chunk():
|
|
{
|
|
Block b;
|
|
}
|
|
{
|
|
b=Block() <EOF> { return new Chunk(b); }
|
|
}
|
|
|
|
Block Block():
|
|
{
|
|
Block b = new Block();
|
|
Stat s;
|
|
}
|
|
{
|
|
(s=Stat() (";")? {b.add(s);} )* (s=LastStat() (";")? {b.add(s);} )? { 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;
|
|
}
|
|
{
|
|
<DO> b=Block() <END> { return Stat.block(b); }
|
|
| <WHILE> e=Exp() <DO> b=Block() <END> { return Stat.whiledo(e,b); }
|
|
| <REPEAT> b=Block() <UNTIL> e=Exp() { return Stat.repeatuntil(b,e); }
|
|
| s=IfThenElse() { return s; }
|
|
| LOOKAHEAD(3) <FOR> n=<NAME> "=" e=Exp() "," e2=Exp() ( "," e3=Exp() )? <DO> b=Block() <END> { return Stat.fornumeric(n.image,e,e2,e3,b); }
|
|
| <FOR> nl=NameList() <IN> el=ExpList() <DO> b=Block() <END> { return Stat.forgeneric(nl,el,b); }
|
|
| <FUNCTION> fn=FuncName() fb=FuncBody() { return Stat.functiondef(fn,fb); }
|
|
| LOOKAHEAD(2) <LOCAL> <FUNCTION> n=<NAME> fb=FuncBody() { return Stat.localfunctiondef(n.image,fb); }
|
|
| <LOCAL> nl=NameList() ( "=" el=ExpList() )? { return Stat.localassignment(nl,el); }
|
|
| s=ExprStat() { 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 LastStat():
|
|
{
|
|
List<Exp> el=null;
|
|
}
|
|
{
|
|
<BREAK> { return Stat.breakstat(); }
|
|
| <RETURN> ( el=ExpList() )? { return Stat.returnstat(el); }
|
|
}
|
|
|
|
Stat ExprStat():
|
|
{
|
|
Exp.PrimaryExp pe;
|
|
Stat as=null;
|
|
}
|
|
{
|
|
pe=PrimaryExp() ( as=Assign(assertvarexp(pe)) )?
|
|
{ return as==null? Stat.functioncall(assertfunccall(pe)): as; }
|
|
}
|
|
|
|
Stat Assign(Exp.VarExp v0):
|
|
{
|
|
List<Exp.VarExp> vl = new ArrayList<Exp.VarExp>();
|
|
vl.add(v0);
|
|
Exp.VarExp ve;
|
|
List<Exp> el;
|
|
}
|
|
{
|
|
( "," ve=VarExp() { vl.add(ve); } )* "=" el=ExpList() { return Stat.assignment(vl,el); }
|
|
}
|
|
|
|
Exp.VarExp VarExp():
|
|
{
|
|
Exp.PrimaryExp pe;
|
|
}
|
|
{
|
|
pe=PrimaryExp() { return assertvarexp(pe); }
|
|
}
|
|
|
|
FuncName FuncName():
|
|
{
|
|
FuncName fn;
|
|
Token n;
|
|
}
|
|
{
|
|
n=<NAME> {fn=new FuncName(n.image);}
|
|
( "." n=<NAME> {fn.adddot(n.image);} )*
|
|
( ":" n=<NAME> {fn.method=n.image;} )?
|
|
{return fn;}
|
|
}
|
|
|
|
Exp.PrimaryExp PrefixExp():
|
|
{
|
|
Token n;
|
|
Exp e;
|
|
}
|
|
{
|
|
n=<NAME> { return Exp.nameprefix(n.image); }
|
|
| "(" e=Exp() ")" { return Exp.parensprefix(e); }
|
|
}
|
|
|
|
Exp.PrimaryExp PrimaryExp():
|
|
{
|
|
Exp.PrimaryExp pe;
|
|
}
|
|
{
|
|
pe=PrefixExp() ( LOOKAHEAD(2) pe=PostfixOp(pe) )* { return pe; }
|
|
}
|
|
|
|
Exp.PrimaryExp PostfixOp(Exp.PrimaryExp lhs):
|
|
{
|
|
Token n;
|
|
Exp e;
|
|
FuncArgs a;
|
|
}
|
|
{
|
|
"." n=<NAME> { return Exp.fieldop(lhs, n.image); }
|
|
| "[" e=Exp() "]" { return Exp.indexop(lhs, e); }
|
|
| ":" n=<NAME> a=FuncArgs() { return Exp.methodop(lhs, n.image,a); }
|
|
| a=FuncArgs() { return Exp.functionop(lhs, a); }
|
|
}
|
|
|
|
FuncArgs FuncArgs():
|
|
{
|
|
List<Exp> el=null;
|
|
TableConstructor tc;
|
|
LuaString s;
|
|
}
|
|
{
|
|
"(" ( el=ExpList() )? ")" { return FuncArgs.explist(el); }
|
|
| tc=TableConstructor() { return FuncArgs.tableconstructor(tc); }
|
|
| s=Str() { return FuncArgs.string(s); }
|
|
}
|
|
|
|
List<Name> NameList():
|
|
{
|
|
List<Name> nl = new ArrayList<Name>();
|
|
Token name;
|
|
}
|
|
{
|
|
name=<NAME> {nl.add(new Name(name.image));} ( LOOKAHEAD(2) "," name=<NAME> {nl.add(new Name(name.image));} )* {return nl;}
|
|
}
|
|
|
|
List<Exp> ExpList():
|
|
{
|
|
List<Exp> el = new ArrayList<Exp>();
|
|
Exp e;
|
|
}
|
|
{
|
|
e=Exp() {el.add(e);} ( "," e=Exp() {el.add(e);} )* {return el;}
|
|
}
|
|
|
|
Exp SimpleExp():
|
|
{
|
|
Token n;
|
|
LuaString s;
|
|
Exp e;
|
|
TableConstructor tc;
|
|
FuncBody fb;
|
|
}
|
|
{
|
|
<NIL> { return Exp.constant(LuaValue.NIL); }
|
|
| <TRUE> { return Exp.constant(LuaValue.TRUE); }
|
|
| <FALSE> { return Exp.constant(LuaValue.FALSE); }
|
|
| n=<NUMBER> { return Exp.numberconstant(n.image); }
|
|
| s=Str() { return Exp.constant(s); }
|
|
| "..." { return Exp.varargs(); }
|
|
| tc=TableConstructor() { return Exp.tableconstructor(tc); }
|
|
| fb=Function() { return Exp.anonymousfunction(fb); }
|
|
| 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;
|
|
}
|
|
{
|
|
( e=SimpleExp() | op=Unop() s=Exp() {e=Exp.unaryexp(op,s);})
|
|
(LOOKAHEAD(2) op=Binop() s=Exp() {e=Exp.binaryexp(e,op,s);} )* { return e; }
|
|
}
|
|
|
|
FuncBody Function():
|
|
{
|
|
FuncBody fb;
|
|
}
|
|
{
|
|
<FUNCTION> fb=FuncBody() { return fb; }
|
|
}
|
|
|
|
FuncBody FuncBody():
|
|
{
|
|
ParList pl=null;
|
|
Block b;
|
|
}
|
|
{
|
|
"(" ( pl=ParList() )? ")" b=Block() <END> { return new FuncBody(pl,b); }
|
|
}
|
|
|
|
ParList ParList():
|
|
{
|
|
List<Name> nl=null;
|
|
boolean v=false;
|
|
}
|
|
{
|
|
nl=NameList() ( "," "..." { v=true; } )? { return new ParList(nl,v); }
|
|
| "..." { return new ParList(null,true); ; }
|
|
}
|
|
|
|
TableConstructor TableConstructor():
|
|
{
|
|
TableConstructor tc = new TableConstructor();
|
|
List<TableField> fl = null;
|
|
}
|
|
{
|
|
"{" ( fl=FieldList() {tc.fields=fl;} )? "}" { return tc; }
|
|
}
|
|
|
|
List<TableField> FieldList():
|
|
{
|
|
List<TableField> fl = new ArrayList<TableField>();
|
|
TableField f;
|
|
}
|
|
{
|
|
f=Field() {fl.add(f);} (LOOKAHEAD(2) FieldSep() f=Field() {fl.add(f);})* (FieldSep())? { return fl; }
|
|
}
|
|
|
|
TableField Field():
|
|
{
|
|
Token name;
|
|
Exp exp,rhs;
|
|
}
|
|
{
|
|
"[" exp=Exp() "]" "=" rhs=Exp() { return TableField.keyedField(exp,rhs); }
|
|
| LOOKAHEAD(2) name=<NAME> "=" rhs=Exp() { return TableField.namedField(name.image,rhs); }
|
|
| rhs=Exp() { return TableField.listField(rhs); }
|
|
}
|
|
|
|
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; }
|
|
}
|