525 lines
14 KiB
Plaintext
525 lines
14 KiB
Plaintext
%{
|
|
package parse
|
|
|
|
import (
|
|
"github.com/yuin/gopher-lua/ast"
|
|
)
|
|
%}
|
|
%type<stmts> chunk
|
|
%type<stmts> chunk1
|
|
%type<stmts> block
|
|
%type<stmt> stat
|
|
%type<stmts> elseifs
|
|
%type<stmt> laststat
|
|
%type<funcname> funcname
|
|
%type<funcname> funcname1
|
|
%type<exprlist> varlist
|
|
%type<expr> var
|
|
%type<namelist> namelist
|
|
%type<exprlist> exprlist
|
|
%type<expr> expr
|
|
%type<expr> string
|
|
%type<expr> prefixexp
|
|
%type<expr> functioncall
|
|
%type<expr> afunctioncall
|
|
%type<exprlist> args
|
|
%type<expr> function
|
|
%type<funcexpr> funcbody
|
|
%type<parlist> parlist
|
|
%type<expr> tableconstructor
|
|
%type<fieldlist> fieldlist
|
|
%type<field> field
|
|
%type<fieldsep> fieldsep
|
|
|
|
%union {
|
|
token ast.Token
|
|
|
|
stmts []ast.Stmt
|
|
stmt ast.Stmt
|
|
|
|
funcname *ast.FuncName
|
|
funcexpr *ast.FunctionExpr
|
|
|
|
exprlist []ast.Expr
|
|
expr ast.Expr
|
|
|
|
fieldlist []*ast.Field
|
|
field *ast.Field
|
|
fieldsep string
|
|
|
|
namelist []string
|
|
parlist *ast.ParList
|
|
}
|
|
|
|
/* Reserved words */
|
|
%token<token> TAnd TBreak TDo TElse TElseIf TEnd TFalse TFor TFunction TIf TIn TLocal TNil TNot TOr TReturn TRepeat TThen TTrue TUntil TWhile
|
|
|
|
/* Literals */
|
|
%token<token> TEqeq TNeq TLte TGte T2Comma T3Comma TIdent TNumber TString '{' '('
|
|
|
|
/* Operators */
|
|
%left TOr
|
|
%left TAnd
|
|
%left '>' '<' TGte TLte TEqeq TNeq
|
|
%right T2Comma
|
|
%left '+' '-'
|
|
%left '*' '/' '%'
|
|
%right UNARY /* not # -(unary) */
|
|
%right '^'
|
|
|
|
%%
|
|
|
|
chunk:
|
|
chunk1 {
|
|
$$ = $1
|
|
if l, ok := yylex.(*Lexer); ok {
|
|
l.Stmts = $$
|
|
}
|
|
} |
|
|
chunk1 laststat {
|
|
$$ = append($1, $2)
|
|
if l, ok := yylex.(*Lexer); ok {
|
|
l.Stmts = $$
|
|
}
|
|
} |
|
|
chunk1 laststat ';' {
|
|
$$ = append($1, $2)
|
|
if l, ok := yylex.(*Lexer); ok {
|
|
l.Stmts = $$
|
|
}
|
|
}
|
|
|
|
chunk1:
|
|
{
|
|
$$ = []ast.Stmt{}
|
|
} |
|
|
chunk1 stat {
|
|
$$ = append($1, $2)
|
|
} |
|
|
chunk1 ';' {
|
|
$$ = $1
|
|
}
|
|
|
|
block:
|
|
chunk {
|
|
$$ = $1
|
|
}
|
|
|
|
stat:
|
|
varlist '=' exprlist {
|
|
$$ = &ast.AssignStmt{Lhs: $1, Rhs: $3}
|
|
$$.SetLine($1[0].Line())
|
|
} |
|
|
/* 'stat = functioncal' causes a reduce/reduce conflict */
|
|
prefixexp {
|
|
if _, ok := $1.(*ast.FuncCallExpr); !ok {
|
|
yylex.(*Lexer).Error("parse error")
|
|
} else {
|
|
$$ = &ast.FuncCallStmt{Expr: $1}
|
|
$$.SetLine($1.Line())
|
|
}
|
|
} |
|
|
TDo block TEnd {
|
|
$$ = &ast.DoBlockStmt{Stmts: $2}
|
|
$$.SetLine($1.Pos.Line)
|
|
$$.SetLastLine($3.Pos.Line)
|
|
} |
|
|
TWhile expr TDo block TEnd {
|
|
$$ = &ast.WhileStmt{Condition: $2, Stmts: $4}
|
|
$$.SetLine($1.Pos.Line)
|
|
$$.SetLastLine($5.Pos.Line)
|
|
} |
|
|
TRepeat block TUntil expr {
|
|
$$ = &ast.RepeatStmt{Condition: $4, Stmts: $2}
|
|
$$.SetLine($1.Pos.Line)
|
|
$$.SetLastLine($4.Line())
|
|
} |
|
|
TIf expr TThen block elseifs TEnd {
|
|
$$ = &ast.IfStmt{Condition: $2, Then: $4}
|
|
cur := $$
|
|
for _, elseif := range $5 {
|
|
cur.(*ast.IfStmt).Else = []ast.Stmt{elseif}
|
|
cur = elseif
|
|
}
|
|
$$.SetLine($1.Pos.Line)
|
|
$$.SetLastLine($6.Pos.Line)
|
|
} |
|
|
TIf expr TThen block elseifs TElse block TEnd {
|
|
$$ = &ast.IfStmt{Condition: $2, Then: $4}
|
|
cur := $$
|
|
for _, elseif := range $5 {
|
|
cur.(*ast.IfStmt).Else = []ast.Stmt{elseif}
|
|
cur = elseif
|
|
}
|
|
cur.(*ast.IfStmt).Else = $7
|
|
$$.SetLine($1.Pos.Line)
|
|
$$.SetLastLine($8.Pos.Line)
|
|
} |
|
|
TFor TIdent '=' expr ',' expr TDo block TEnd {
|
|
$$ = &ast.NumberForStmt{Name: $2.Str, Init: $4, Limit: $6, Stmts: $8}
|
|
$$.SetLine($1.Pos.Line)
|
|
$$.SetLastLine($9.Pos.Line)
|
|
} |
|
|
TFor TIdent '=' expr ',' expr ',' expr TDo block TEnd {
|
|
$$ = &ast.NumberForStmt{Name: $2.Str, Init: $4, Limit: $6, Step:$8, Stmts: $10}
|
|
$$.SetLine($1.Pos.Line)
|
|
$$.SetLastLine($11.Pos.Line)
|
|
} |
|
|
TFor namelist TIn exprlist TDo block TEnd {
|
|
$$ = &ast.GenericForStmt{Names:$2, Exprs:$4, Stmts: $6}
|
|
$$.SetLine($1.Pos.Line)
|
|
$$.SetLastLine($7.Pos.Line)
|
|
} |
|
|
TFunction funcname funcbody {
|
|
$$ = &ast.FuncDefStmt{Name: $2, Func: $3}
|
|
$$.SetLine($1.Pos.Line)
|
|
$$.SetLastLine($3.LastLine())
|
|
} |
|
|
TLocal TFunction TIdent funcbody {
|
|
$$ = &ast.LocalAssignStmt{Names:[]string{$3.Str}, Exprs: []ast.Expr{$4}}
|
|
$$.SetLine($1.Pos.Line)
|
|
$$.SetLastLine($4.LastLine())
|
|
} |
|
|
TLocal namelist '=' exprlist {
|
|
$$ = &ast.LocalAssignStmt{Names: $2, Exprs:$4}
|
|
$$.SetLine($1.Pos.Line)
|
|
} |
|
|
TLocal namelist {
|
|
$$ = &ast.LocalAssignStmt{Names: $2, Exprs:[]ast.Expr{}}
|
|
$$.SetLine($1.Pos.Line)
|
|
}
|
|
|
|
elseifs:
|
|
{
|
|
$$ = []ast.Stmt{}
|
|
} |
|
|
elseifs TElseIf expr TThen block {
|
|
$$ = append($1, &ast.IfStmt{Condition: $3, Then: $5})
|
|
$$[len($$)-1].SetLine($2.Pos.Line)
|
|
}
|
|
|
|
laststat:
|
|
TReturn {
|
|
$$ = &ast.ReturnStmt{Exprs:nil}
|
|
$$.SetLine($1.Pos.Line)
|
|
} |
|
|
TReturn exprlist {
|
|
$$ = &ast.ReturnStmt{Exprs:$2}
|
|
$$.SetLine($1.Pos.Line)
|
|
} |
|
|
TBreak {
|
|
$$ = &ast.BreakStmt{}
|
|
$$.SetLine($1.Pos.Line)
|
|
}
|
|
|
|
funcname:
|
|
funcname1 {
|
|
$$ = $1
|
|
} |
|
|
funcname1 ':' TIdent {
|
|
$$ = &ast.FuncName{Func:nil, Receiver:$1.Func, Method: $3.Str}
|
|
}
|
|
|
|
funcname1:
|
|
TIdent {
|
|
$$ = &ast.FuncName{Func: &ast.IdentExpr{Value:$1.Str}}
|
|
$$.Func.SetLine($1.Pos.Line)
|
|
} |
|
|
funcname1 '.' TIdent {
|
|
key:= &ast.StringExpr{Value:$3.Str}
|
|
key.SetLine($3.Pos.Line)
|
|
fn := &ast.AttrGetExpr{Object: $1.Func, Key: key}
|
|
fn.SetLine($3.Pos.Line)
|
|
$$ = &ast.FuncName{Func: fn}
|
|
}
|
|
|
|
varlist:
|
|
var {
|
|
$$ = []ast.Expr{$1}
|
|
} |
|
|
varlist ',' var {
|
|
$$ = append($1, $3)
|
|
}
|
|
|
|
var:
|
|
TIdent {
|
|
$$ = &ast.IdentExpr{Value:$1.Str}
|
|
$$.SetLine($1.Pos.Line)
|
|
} |
|
|
prefixexp '[' expr ']' {
|
|
$$ = &ast.AttrGetExpr{Object: $1, Key: $3}
|
|
$$.SetLine($1.Line())
|
|
} |
|
|
prefixexp '.' TIdent {
|
|
key := &ast.StringExpr{Value:$3.Str}
|
|
key.SetLine($3.Pos.Line)
|
|
$$ = &ast.AttrGetExpr{Object: $1, Key: key}
|
|
$$.SetLine($1.Line())
|
|
}
|
|
|
|
namelist:
|
|
TIdent {
|
|
$$ = []string{$1.Str}
|
|
} |
|
|
namelist ',' TIdent {
|
|
$$ = append($1, $3.Str)
|
|
}
|
|
|
|
exprlist:
|
|
expr {
|
|
$$ = []ast.Expr{$1}
|
|
} |
|
|
exprlist ',' expr {
|
|
$$ = append($1, $3)
|
|
}
|
|
|
|
expr:
|
|
TNil {
|
|
$$ = &ast.NilExpr{}
|
|
$$.SetLine($1.Pos.Line)
|
|
} |
|
|
TFalse {
|
|
$$ = &ast.FalseExpr{}
|
|
$$.SetLine($1.Pos.Line)
|
|
} |
|
|
TTrue {
|
|
$$ = &ast.TrueExpr{}
|
|
$$.SetLine($1.Pos.Line)
|
|
} |
|
|
TNumber {
|
|
$$ = &ast.NumberExpr{Value: $1.Str}
|
|
$$.SetLine($1.Pos.Line)
|
|
} |
|
|
T3Comma {
|
|
$$ = &ast.Comma3Expr{}
|
|
$$.SetLine($1.Pos.Line)
|
|
} |
|
|
function {
|
|
$$ = $1
|
|
} |
|
|
prefixexp {
|
|
$$ = $1
|
|
} |
|
|
string {
|
|
$$ = $1
|
|
} |
|
|
tableconstructor {
|
|
$$ = $1
|
|
} |
|
|
expr TOr expr {
|
|
$$ = &ast.LogicalOpExpr{Lhs: $1, Operator: "or", Rhs: $3}
|
|
$$.SetLine($1.Line())
|
|
} |
|
|
expr TAnd expr {
|
|
$$ = &ast.LogicalOpExpr{Lhs: $1, Operator: "and", Rhs: $3}
|
|
$$.SetLine($1.Line())
|
|
} |
|
|
expr '>' expr {
|
|
$$ = &ast.RelationalOpExpr{Lhs: $1, Operator: ">", Rhs: $3}
|
|
$$.SetLine($1.Line())
|
|
} |
|
|
expr '<' expr {
|
|
$$ = &ast.RelationalOpExpr{Lhs: $1, Operator: "<", Rhs: $3}
|
|
$$.SetLine($1.Line())
|
|
} |
|
|
expr TGte expr {
|
|
$$ = &ast.RelationalOpExpr{Lhs: $1, Operator: ">=", Rhs: $3}
|
|
$$.SetLine($1.Line())
|
|
} |
|
|
expr TLte expr {
|
|
$$ = &ast.RelationalOpExpr{Lhs: $1, Operator: "<=", Rhs: $3}
|
|
$$.SetLine($1.Line())
|
|
} |
|
|
expr TEqeq expr {
|
|
$$ = &ast.RelationalOpExpr{Lhs: $1, Operator: "==", Rhs: $3}
|
|
$$.SetLine($1.Line())
|
|
} |
|
|
expr TNeq expr {
|
|
$$ = &ast.RelationalOpExpr{Lhs: $1, Operator: "~=", Rhs: $3}
|
|
$$.SetLine($1.Line())
|
|
} |
|
|
expr T2Comma expr {
|
|
$$ = &ast.StringConcatOpExpr{Lhs: $1, Rhs: $3}
|
|
$$.SetLine($1.Line())
|
|
} |
|
|
expr '+' expr {
|
|
$$ = &ast.ArithmeticOpExpr{Lhs: $1, Operator: "+", Rhs: $3}
|
|
$$.SetLine($1.Line())
|
|
} |
|
|
expr '-' expr {
|
|
$$ = &ast.ArithmeticOpExpr{Lhs: $1, Operator: "-", Rhs: $3}
|
|
$$.SetLine($1.Line())
|
|
} |
|
|
expr '*' expr {
|
|
$$ = &ast.ArithmeticOpExpr{Lhs: $1, Operator: "*", Rhs: $3}
|
|
$$.SetLine($1.Line())
|
|
} |
|
|
expr '/' expr {
|
|
$$ = &ast.ArithmeticOpExpr{Lhs: $1, Operator: "/", Rhs: $3}
|
|
$$.SetLine($1.Line())
|
|
} |
|
|
expr '%' expr {
|
|
$$ = &ast.ArithmeticOpExpr{Lhs: $1, Operator: "%", Rhs: $3}
|
|
$$.SetLine($1.Line())
|
|
} |
|
|
expr '^' expr {
|
|
$$ = &ast.ArithmeticOpExpr{Lhs: $1, Operator: "^", Rhs: $3}
|
|
$$.SetLine($1.Line())
|
|
} |
|
|
'-' expr %prec UNARY {
|
|
$$ = &ast.UnaryMinusOpExpr{Expr: $2}
|
|
$$.SetLine($2.Line())
|
|
} |
|
|
TNot expr %prec UNARY {
|
|
$$ = &ast.UnaryNotOpExpr{Expr: $2}
|
|
$$.SetLine($2.Line())
|
|
} |
|
|
'#' expr %prec UNARY {
|
|
$$ = &ast.UnaryLenOpExpr{Expr: $2}
|
|
$$.SetLine($2.Line())
|
|
}
|
|
|
|
string:
|
|
TString {
|
|
$$ = &ast.StringExpr{Value: $1.Str}
|
|
$$.SetLine($1.Pos.Line)
|
|
}
|
|
|
|
prefixexp:
|
|
var {
|
|
$$ = $1
|
|
} |
|
|
afunctioncall {
|
|
$$ = $1
|
|
} |
|
|
functioncall {
|
|
$$ = $1
|
|
} |
|
|
'(' expr ')' {
|
|
$$ = $2
|
|
$$.SetLine($1.Pos.Line)
|
|
}
|
|
|
|
afunctioncall:
|
|
'(' functioncall ')' {
|
|
$2.(*ast.FuncCallExpr).AdjustRet = true
|
|
$$ = $2
|
|
}
|
|
|
|
functioncall:
|
|
prefixexp args {
|
|
$$ = &ast.FuncCallExpr{Func: $1, Args: $2}
|
|
$$.SetLine($1.Line())
|
|
} |
|
|
prefixexp ':' TIdent args {
|
|
$$ = &ast.FuncCallExpr{Method: $3.Str, Receiver: $1, Args: $4}
|
|
$$.SetLine($1.Line())
|
|
}
|
|
|
|
args:
|
|
'(' ')' {
|
|
if yylex.(*Lexer).PNewLine {
|
|
yylex.(*Lexer).TokenError($1, "ambiguous syntax (function call x new statement)")
|
|
}
|
|
$$ = []ast.Expr{}
|
|
} |
|
|
'(' exprlist ')' {
|
|
if yylex.(*Lexer).PNewLine {
|
|
yylex.(*Lexer).TokenError($1, "ambiguous syntax (function call x new statement)")
|
|
}
|
|
$$ = $2
|
|
} |
|
|
tableconstructor {
|
|
$$ = []ast.Expr{$1}
|
|
} |
|
|
string {
|
|
$$ = []ast.Expr{$1}
|
|
}
|
|
|
|
function:
|
|
TFunction funcbody {
|
|
$$ = &ast.FunctionExpr{ParList:$2.ParList, Stmts: $2.Stmts}
|
|
$$.SetLine($1.Pos.Line)
|
|
$$.SetLastLine($2.LastLine())
|
|
}
|
|
|
|
funcbody:
|
|
'(' parlist ')' block TEnd {
|
|
$$ = &ast.FunctionExpr{ParList: $2, Stmts: $4}
|
|
$$.SetLine($1.Pos.Line)
|
|
$$.SetLastLine($5.Pos.Line)
|
|
} |
|
|
'(' ')' block TEnd {
|
|
$$ = &ast.FunctionExpr{ParList: &ast.ParList{HasVargs: false, Names: []string{}}, Stmts: $3}
|
|
$$.SetLine($1.Pos.Line)
|
|
$$.SetLastLine($4.Pos.Line)
|
|
}
|
|
|
|
parlist:
|
|
T3Comma {
|
|
$$ = &ast.ParList{HasVargs: true, Names: []string{}}
|
|
} |
|
|
namelist {
|
|
$$ = &ast.ParList{HasVargs: false, Names: []string{}}
|
|
$$.Names = append($$.Names, $1...)
|
|
} |
|
|
namelist ',' T3Comma {
|
|
$$ = &ast.ParList{HasVargs: true, Names: []string{}}
|
|
$$.Names = append($$.Names, $1...)
|
|
}
|
|
|
|
|
|
tableconstructor:
|
|
'{' '}' {
|
|
$$ = &ast.TableExpr{Fields: []*ast.Field{}}
|
|
$$.SetLine($1.Pos.Line)
|
|
} |
|
|
'{' fieldlist '}' {
|
|
$$ = &ast.TableExpr{Fields: $2}
|
|
$$.SetLine($1.Pos.Line)
|
|
}
|
|
|
|
|
|
fieldlist:
|
|
field {
|
|
$$ = []*ast.Field{$1}
|
|
} |
|
|
fieldlist fieldsep field {
|
|
$$ = append($1, $3)
|
|
} |
|
|
fieldlist fieldsep {
|
|
$$ = $1
|
|
}
|
|
|
|
field:
|
|
TIdent '=' expr {
|
|
$$ = &ast.Field{Key: &ast.StringExpr{Value:$1.Str}, Value: $3}
|
|
$$.Key.SetLine($1.Pos.Line)
|
|
} |
|
|
'[' expr ']' '=' expr {
|
|
$$ = &ast.Field{Key: $2, Value: $5}
|
|
} |
|
|
expr {
|
|
$$ = &ast.Field{Value: $1}
|
|
}
|
|
|
|
fieldsep:
|
|
',' {
|
|
$$ = ","
|
|
} |
|
|
';' {
|
|
$$ = ";"
|
|
}
|
|
|
|
%%
|
|
|
|
func TokenName(c int) string {
|
|
if c >= TAnd && c-TAnd < len(yyToknames) {
|
|
if yyToknames[c-TAnd] != "" {
|
|
return yyToknames[c-TAnd]
|
|
}
|
|
}
|
|
return string([]byte{byte(c)})
|
|
}
|
|
|