【问题标题】:Left factoring of part of JavaScript grammar部分 JavaScript 语法的左因式分解
【发布时间】:2015-11-02 20:21:14
【问题描述】:

我使用 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] 的交集不为空。

谢谢!

【问题讨论】:

    标签: javascript parsing recursion compiler-construction grammar


    【解决方案1】:

    基本思想是避免在解析中做出决定,即 2 个产生式和路径共享一个公共标记。 因此,如果终端被埋在其他非终端中并共享,基本上你希望将终端移到制作的前面。

    您基本上会想要分解出常见的标记,并将它们放置在新的非终结符中以避免不确定的选择。

    例如: 如果我有这个语法:

    S -> X | Y
    X -> ab
    Y -> ac
    

    我必须将终端“a”向上“移动”,以便解析器在尝试选择是 X 还是 Y 时不会卡住。

    解决方法如下:

    S -> A'
    A' -> a(X|Y)
    X -> b
    Y -> c
    

    请注意考虑之前可能采用的所有路径,包括 lambda(空字符串)。处理 lambda 是一种特殊情况,需要进一步处理以获得体面的语法(或者甚至反映您想要的语言的语法)。

    虽然是的,这增加了额外的非终结符,但它确实是一种算法,可以保证不需要前瞻的确定性语法。

    注意:某些语言生成器(解析语法)可以用前瞻值指定。有时为了简单起见,这是首选,但请注意,使用超过 1 的前瞻,将大大增加将包含在解析器中的前瞻表。它的数量级为 N^k,其中 n 是产生的数量,k 是前瞻。

    这个网站用我在编译器类中使用的特定形式来解释它: http://www.cs.sun.ac.za/rw711/2012term2/lectures/lec5/l5.pdf

    如果不喜欢外部网站链接,我可以拍摄一些幻灯片的图片并将它们附在此处以供将来存档。

    我建议阅读语法,因为它们会很有趣!

    【讨论】:

    • 嗨,@1337GameDev!谢谢你的回复。我知道基础知识,但我不能为规则“LeftHandSideExpression”做左分解,所以我决定问怎么做。
    • @user44647 如果你认为你已经解决了,请回复主帖作为答案。
    猜你喜欢
    • 1970-01-01
    • 2012-01-06
    • 1970-01-01
    • 2016-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多