我正在为VBScript写一个GOLD Parser语法。这是一个摘录:
<CallStmt> ::= 'Call' <CallExpr>
| <CallExpr> <ParameterList>
!| <CallExpr> '(' <Expr> ')'
| <CallExpr> '(' ')'
<AssignStmt> ::= <CallExpr> '=' <Expr>
| 'Set' <CallExpr> '=' <Expr>
| 'Set' <CallExpr> '=' 'New' <CallExpr>
<CallExpr> ::= '.' <LeftExpr>
| <LeftExpr>
<LeftExpr> ::= ID
| IDDot <LeftExpr>
| ID '(' <ParameterList> ')'
| ID '(' <ParameterList> ').' <LeftExpr>
!VBScript allows to skip parameters a(1,,2)
<ParameterList> ::= <Expr> ',' <ParameterList>
| ',' <ParameterList>
| <Expr>
|
! Value can be reduced from <Expr>
<Value> ::= <ConstExpr>
| <CallExpr>
| '(' <Expr> ')'
我对<CallStmt> ::= <CallExpr> <ParameterList>
规则存在冲突。此规则描述了调用sub而不包含括号。例如,以下语句在语法上是正确的:
obj.sub1(1, 2).sub2 1, 2
obj.sub1(1, 2).sub2(1),(2)
Call obj.sub1(1, 2).sub2(1, 2)
如何区分带有周围括号sub1(1, 2)
的子调用和带有围绕参数sub2(1),(2)
的括号的子调用?
答案 0 :(得分:2)
您遇到的问题是VBScript语法不明确。
哪个变体是obj.sub1 (1)
?围绕论点的那个人,或者没有和第一个论点的那个人恰好是在parens?
如果我们无法分辨,那么解析器也不能......我们只能确定何时我们有多个参数,例如:一个逗号。因此,假设默认情况下,当我们遇到多个参数或根本没有参数时,我们选择仅使用parens作为参数。
在您努力解决问题的过程中,您已经开始制作过于称职的终端,其中也包括点。这是一个坏主意,因为它不起作用('。'周围的空格被允许但不被这些终端匹配)并且它可能导致意外的标记化行为和降低的性能。通常它表示你的语法有问题。
这是我一起攻击的语法,它可以很好地解析你的样本,实际上也应该正确地处理赋值和构造函数调用。请注意,<ParameterList>
仅匹配两个或更多参数,但不匹配零个或一个参数;这是解决导致问题的模糊性的关键。
<CallStmt> ::= 'Call' <CallPath>
| <CallPath>
<AssignStmt> ::= <AssignPath> '=' <Expr>
| 'Set' <AssignPath> '=' <Expr>
| 'Set' <AssignPath> '=' 'New' <CtorPath>
<CtorPath> ::= ID '.' <CtorPath>
| ID
| <CallExpr>
| ID <ParameterList>
<CallExpr> ::= ID '(' ')'
| ID '(' <Expr> ')'
| ID '(' <ParameterList> ')'
<CallPath> ::= <Member> '.' <CallPath>
| ID
| <CallExpr>
| ID <ParameterList>
<Member> ::= <CallExpr>
| ID
<MemberPath> ::= <Member> '.' <MemberPath>
| <Member>
<AssignPath> ::= <Member> '.' <AssignPath>
| ID
!VBScript allows to skip parameters a(1,,2)
<ParameterList> ::= <Expr> ',' <ParameterList>
| <Expr> ',' <Expr>
| <Expr> ','
| ',' <ParameterList>
| ','
! Value can be reduced from <Expr>
<Value> ::= NumberLiteral
| StringLiteral
| <MemberPath>
| '(' <Expr> ')'
!--- The rest of the grammar ---
"Start Symbol" = <Start>
{WS} = {Whitespace} - {CR} - {LF}
{ID Head} = {Letter} + [_]
{ID Tail} = {Alphanumeric} + [_]
{String Chars} = {Printable} + {HT} - ["]
Whitespace = {WS}+
NewLine = {CR}{LF} | {CR} | {LF}
ID = {ID Head}{ID Tail}*
StringLiteral = ('"' {String Chars}* '"')+
NumberLiteral = {Number}+ ('.' {Number}+ )?
<nl> ::= NewLine <nl> !One or more
| NewLine
<nl Opt> ::= NewLine <nl Opt> !Zero or more
| !Empty
<Start> ::= <nl opt> <StmtList>
<StmtList> ::= <CallStmt> <nl> <StmtList>
| <AssignStmt> <nl> <StmtList>
|
<Expr> ::= <Add Exp>
<Add Exp> ::= <Add Exp> '+' <Mult Exp>
| <Add Exp> '-' <Mult Exp>
| <Mult Exp>
<Mult Exp> ::= <Mult Exp> '*' <Negate Exp>
| <Mult Exp> '/' <Negate Exp>
| <Negate Exp>
<Negate Exp> ::= '-' <Value>
| <Value>