【问题标题】:How to Remove the ambiguity from the following grammar?如何从以下语法中消除歧义?
【发布时间】:2021-09-13 18:27:46
【问题描述】:

去除以下语法中的歧义

S −−> 如果 E 则 S |如果 E 则 S 否则 S |其他

【问题讨论】:

  • 这能回答你的问题吗? LL(1) grammar for dangling else
  • 我不认为是这样,因为引用的问题讨论的是 LL(1) 解析(确定性),而不是歧义。看看我的答案。

标签: compiler-construction grammar ambiguity


【解决方案1】:

可以删除 dangling-else 歧义。在“编译器:原理、技术和工具”第 2 版,第 211-212 页中有这样的语法。但是,这本书语法,但没有没有解释(或者我没有找到)。

在 ABNF 元语法中,语法是:

statement = matched / open
matched   = "if" expr "then" matched "else" matched 
          / other
open      = "if" expr "then" statement
          / "if" expr "then" matched "else" open

expr      = ...
other     = ...

它是如何工作的?

这里的想法是通过使用非确定性来避免歧义(无论如何已经提出,因为每个模棱两可的语法也是非确定性的;最后我写了我发现的差异(也是) 经常被误解)。这意味着在成功解析后,任何输入可能只有一个语法树(意味着您要求的非歧义)。但是您需要一个解析器,它与确定性 LL(1) 解析器相比复杂的机制。

规则matched 确保子树内的每个 直接嵌套的if 语句将具有else。换句话说,then 将有一个匹配的else

规则open 确保每个子if 语句本身没有else,或者如果有,那么它的else 语句又是open。换句话说,规则open 确保使用less else 关键字多于 then 关键字。换句话说,子树中@9​​87654340@ 的数量将less then 的数量(或者ifs,如果你喜欢) .这与确保两者相等数量的matched 规则形成对比。这意味着在解析器中实现的 matchedopen 永远不会接受相同的输入,从 first 使用规则 statement 算起。

此外,由于规则open 中的matched "else" openelse 将“附加”到最近的if。这解决了在解析器识别第一个使用的statement之前的悬空-else歧义。

示例

为了说明将要执行的步骤,我升级了语法以允许更“自然”的输入。这意味着更多的标点符号和空格。首先是词法分析器:

keyword = %s"if" / %s"then" / %s"else"

它尽可能将输入字符分组,未分组的字符本身成为标记。输入:

if(x)then if(x)then y else y

你有这些字节:

对于这些字节,您将拥有以下标记:

然后你就有了解析器语法,它允许解析器接受这些标记(区分大小写)并明确放置空格。还是可以看原版的,大体流程是一样的。解析器语法:

statement = matched / open
matched   = {keyword, %s"if"} *ws "(" *ws expr *ws ")" *ws {keyword, %s"then"} 1*ws matched {keyword, %s"else"} 1*ws matched 
          / other *ws
open      = {keyword, %s"if"} *ws "(" *ws expr *ws ")" *ws {keyword, %s"then"} 1*ws statement
          / {keyword, %s"if"} *ws "(" *ws expr *ws ")" *ws {keyword, %s"then"} 1*ws matched {keyword, %s"else"} 1*ws open

expr      = %s"x"
other     = %s"y" 
ws        = %s" "

在你开始解析之后,一个深入探索语法规则的解析机,会这样执行:

  • 它将进入启动规则statement
  • 然后进入第一个引用规则 matched 的串联。
  • 它将接受具有字符if(x)then 的第一个令牌
  • 然后它将再次使用matched 规则
  • 它将接受所有其他令牌,直到输入 if(x)then y else y 结束。
  • 然后将移出matched 规则并期待其匹配的else,但没有这样,因为输入已结束。这意味着解析器必须回去寻找另一种方式。此时,您将拥有这个(部分构造的)语法树:
  • 它将回到解析的最开始并尝试规则statement中的第二个连接,即一个引用规则open
  • 它将按其步骤工作,并最终使用此树成功到达输入的末尾:
  • 那么解析机可能会继续探索更多,但不会找到任何其他语法树。

相关理论

确定性、非确定性、模糊性和非模糊性常常被误解。我想分别举一个例子,因为我认为写出来的内容可能对每个人都不是很清楚。

从解析器的角度来看,确定性与给定状态下可能的操作数量有关。当解析器中所有可能的状态大多数动作是可能时,解析器是确定性的。我在很多地方都看到过这样的措辞:“语法主要是确定性的,而在少数地方是非确定性的”。这是误导性的,因为语法的确定性是基于整个语法的——更准确地说,它是最坏的确定性情况。例如,下一个语法是确定性的,当被解析器使用时,解析器也将是确定性的:

rule = "a" / "b"

Non-deterministic 表示解析器存在至少一种可能的状态,其中多于一个 > 对于至少一个输入序列,操作是可能的。例如,下面的语法是不确定的:

rule = "a" / "a" 

显然,您可以将其重写为 rule = "a",但这不是相同的语法。两种语法都只生成 same 语言。 语法生成语言的有效字符串。此语言 其有效字符串组成。解析器接受有效语言字符串,它拒绝无效语言字符串。

歧义表示输入可以更多而不是一种方式被识别。这反过来意味着对于至少一个有效的输入,多于而不是一个语法树是可能的。例如,前面的语法(rule = "a" / "a")是不明确的,因为两个连接都有a

Non-ambiguous 意味着任何有效输入都将以完全一种方式被识别。这反过来意味着恰好每个有效输入存在一个语法树。显然,对于 invalid 输入,有 no 语法树。

您可能有一个非确定性非模棱两可的语法,例如:

rule = "a" "b" / "a" "c"

对于输入字符a,您在规则的开头有一个不确定的选择,但在下一个输入字符中,哪个连接是正确的。这是不可能,在输入被完全处理后具有 more 多于 一个 语法树:这意味着语法是明确的。

显然,每一个确定性语法也是明确的,因为没有没有状态可能导致第二个动作可能导致第二棵树。

此外,每一个模棱两可的语法都是不确定的,因为为了能够拥有多个语法树,somewhere存在一个状态,它有更多一个 可能的操作,对于至少一个输入序列。

本书语法的“诀窍”是非确定性是存在(实际上是“雇用”),但它是让在statement 规则外部传播,以有效防止语法变得不明确。

现在,当解析器一次处理一个字符的输入时,所有这些都是有效的。但我不会离开这里。还有不同类型的歧义。有些你可以计算,有些你不能。但我也不会去那里。

免责声明:我使用了截图和我开发的工具的语法语法:Tunnel Grammar Studio。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-27
    • 1970-01-01
    • 1970-01-01
    • 2013-03-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多