JavaScript 语法部分的左因式分解
Left factoring of part of JavaScript grammar
我使用 EcmaScript 5.1 表达式的语法:
PrimaryExpression :
this
Identifier
Literal
ArrayLiteral
ObjectLiteral
( Expression )
FunctionExpression :
function Identifieropt ( FormalParameterListopt ) { FunctionBody }
MemberExpression :
PrimaryExpression
FunctionExpression
MemberExpression [ Expression ]
MemberExpression . IdentifierName
new MemberExpression Arguments
NewExpression :
MemberExpression
new NewExpression
CallExpression :
MemberExpression Arguments
CallExpression Arguments
CallExpression [ Expression ]
CallExpression . IdentifierName
Arguments :
( )
( ArgumentList )
LeftHandSideExpression :
NewExpression
CallExpression
我用 Wirth 表示法重写它,为它编写递归解析器。
我得到了什么:
PrimaryExpression = this | Identifier | Literal | ObjectLiteral | "(" ExpressionNoIn ")"
Literal = NullLiteral | BooleanLiteral | NumericLiteral | StringLiteral
ObjectLiteral = "{" [PropertyNamesAndValues] "}"
MemberExpression = ( PrimaryExpression | FunctionExpression | new MemberExpression Arguments ) MemberExpression'
MemberExpression' = ( "." Identifier | "[" Expression "]" ) MemberExpression' | e.
NewExpression = ( PrimaryExpression | FunctionExpression ) MemberExpression' | new NewExpression'
NewExpression' = MemberExpression Arguments MemberExpression' | NewExpression
CallExpression = MemberExpression Arguments CallExpression'
CallExpression' = ( Arguments | "[" Expression "]" | "." Identifier ) CallExpression' | e.
Arguments = "(" [ArgumentList] ")"
LeftHandSideExpression = NewExpression | CallExpression
所以,问题是如何在我的新语法中对规则 LeftHandSideExpression 使用左因子分解。我需要它,因为 First[LeftHandSideExpression] 和 First[CallExpression] 的交集不为空。
谢谢!
基本思想是避免在 2 个产生式和路径共享一个公共标记的解析中做出决定。
所以基本上,如果终端被埋在其他非终端中并共享,你想将终端移到产品的前面。
基本上,您会想要分解出常见的标记,并将它们放在新的非终结符中以避免非确定性选择。
例如:
如果我有这个语法:
S -> X | Y
X -> ab
Y -> ac
我必须 "move" 终端 "a" 启动,这样解析器在尝试选择是接受 X 还是 Y 时就不会卡住。
解决方案如下:
S -> A'
A' -> a(X|Y)
X -> b
Y -> c
请仔细考虑之前可能采用的所有路径,包括 lambda(空字符串)。处理 lambda 是一种特殊情况,需要进一步处理才能获得合适的语法(或者甚至反映您想要的语言的语法)。
虽然是的,这增加了额外的非终结符,但它是一种算法,可以保证不需要前瞻的确定性语法。
注意:一些语言生成器(解析语法)可以用先行值指定。有时为了简单起见,这是首选,但请注意,使用超过 1 的前瞻性将大大增加将包含在解析器中的前瞻性 table。它是 N^k 的顺序,其中 n 是产品的数量,k 是先行。
该站点使用我在编译器中使用的特定形式对其进行了解释 class:
http://www.cs.sun.ac.za/rw711/2012term2/lectures/lec5/l5.pdf
如果不喜欢外部站点链接,我可以拍摄一些幻灯片的图像并将它们附加在此处以供将来存档。
我建议您阅读语法,因为它们会很有趣!
我使用 EcmaScript 5.1 表达式的语法:
PrimaryExpression :
this
Identifier
Literal
ArrayLiteral
ObjectLiteral
( Expression )
FunctionExpression :
function Identifieropt ( FormalParameterListopt ) { FunctionBody }
MemberExpression :
PrimaryExpression
FunctionExpression
MemberExpression [ Expression ]
MemberExpression . IdentifierName
new MemberExpression Arguments
NewExpression :
MemberExpression
new NewExpression
CallExpression :
MemberExpression Arguments
CallExpression Arguments
CallExpression [ Expression ]
CallExpression . IdentifierName
Arguments :
( )
( ArgumentList )
LeftHandSideExpression :
NewExpression
CallExpression
我用 Wirth 表示法重写它,为它编写递归解析器。 我得到了什么:
PrimaryExpression = this | Identifier | Literal | ObjectLiteral | "(" ExpressionNoIn ")"
Literal = NullLiteral | BooleanLiteral | NumericLiteral | StringLiteral
ObjectLiteral = "{" [PropertyNamesAndValues] "}"
MemberExpression = ( PrimaryExpression | FunctionExpression | new MemberExpression Arguments ) MemberExpression'
MemberExpression' = ( "." Identifier | "[" Expression "]" ) MemberExpression' | e.
NewExpression = ( PrimaryExpression | FunctionExpression ) MemberExpression' | new NewExpression'
NewExpression' = MemberExpression Arguments MemberExpression' | NewExpression
CallExpression = MemberExpression Arguments CallExpression'
CallExpression' = ( Arguments | "[" Expression "]" | "." Identifier ) CallExpression' | e.
Arguments = "(" [ArgumentList] ")"
LeftHandSideExpression = NewExpression | CallExpression
所以,问题是如何在我的新语法中对规则 LeftHandSideExpression 使用左因子分解。我需要它,因为 First[LeftHandSideExpression] 和 First[CallExpression] 的交集不为空。
谢谢!
基本思想是避免在 2 个产生式和路径共享一个公共标记的解析中做出决定。 所以基本上,如果终端被埋在其他非终端中并共享,你想将终端移到产品的前面。
基本上,您会想要分解出常见的标记,并将它们放在新的非终结符中以避免非确定性选择。
例如: 如果我有这个语法:
S -> X | Y
X -> ab
Y -> ac
我必须 "move" 终端 "a" 启动,这样解析器在尝试选择是接受 X 还是 Y 时就不会卡住。
解决方案如下:
S -> A'
A' -> a(X|Y)
X -> b
Y -> c
请仔细考虑之前可能采用的所有路径,包括 lambda(空字符串)。处理 lambda 是一种特殊情况,需要进一步处理才能获得合适的语法(或者甚至反映您想要的语言的语法)。
虽然是的,这增加了额外的非终结符,但它是一种算法,可以保证不需要前瞻的确定性语法。
注意:一些语言生成器(解析语法)可以用先行值指定。有时为了简单起见,这是首选,但请注意,使用超过 1 的前瞻性将大大增加将包含在解析器中的前瞻性 table。它是 N^k 的顺序,其中 n 是产品的数量,k 是先行。
该站点使用我在编译器中使用的特定形式对其进行了解释 class: http://www.cs.sun.ac.za/rw711/2012term2/lectures/lec5/l5.pdf
如果不喜欢外部站点链接,我可以拍摄一些幻灯片的图像并将它们附加在此处以供将来存档。
我建议您阅读语法,因为它们会很有趣!