【问题标题】:Disallowing unnecessary outermost brackets in a BNFC-grammar禁止 BNFC 语法中不必要的最外层括号
【发布时间】:2020-04-15 08:43:30
【问题描述】:

这是this 问题的延续,我之前问过关于命题逻辑的 BNFC 语法。根据定义,我让它使用括号工作,但我现在想扩展语法以在没有括号的情况下工作,但是有一个问题:不允许不必要的外括号。

例如,原子语句a 应该被允许,但(a) 不应该被识别。句子(a => b) & c 也应该允许,但((a => b) & c) 不允许,等等。最后一个例子强调了括号的必要性。优先级是

  1. 等价<=>和蕴涵=>
  2. 结合&和析取|
  3. 否定-
  4. 原子。

级别越高,越早被解析。

通过递归为不同的运算符设置优先级,我得到了使用不必要括号的语法:

IFF     .   L     ::=   L   "<=>" L1  ;
IF      .   L     ::=   L   "=>"  L1  ;
AND     .   L1    ::=   L1  "&"   L2  ;
OR      .   L1    ::=   L1  "|"   L2  ;
NOT     .   L2    ::=       "-"   L3  ;
NOT2    .   L2    ::=       "-"   L2  ;
P       .   L3    ::=   Ident         ;

_       .   L     ::=   L1            ;
_       .   L1    ::=   L2            ;
_       .   L2    ::=   L3            ;
_       .   L3    ::=   "(" L ")"     ;

现在的问题是,我如何不允许允许外括号,其允许是由最后一条规则L3 ::= "(" L ")"; 引起的?在表达式中允许括号是绝对必要的,但它也允许在边缘使用括号。我想我需要一些额外的规则来消除歧义,但那会是什么样的呢?

这个语法也导致了大约 6 个 reduce/reduce 冲突,但这些在递归定义中不是不可避免的吗?

【问题讨论】:

  • 您可以尝试复制您的一些作品,通过在作品L ::= L' "&lt;=&gt;" L1L ::= L' "=&gt;" L1 中使用不同的L' 来禁止作品直接从LL3。在这种情况下,您的作品的 L' 副本可以被允许向下转换为 L3,但 L 本身不能。因此,' 部分表示生产参与了实际的扩展,而不仅仅是为了优先权而进行的转换。 ' 重复项可以有括号,但非' 不能。
  • @Welbog 所以基本上我会为第一级制作这 4 个作品:L ::= L' "&lt;=&gt;" L1L ::= L' "=&gt;" L1L' ::= L' "&lt;=&gt;" L1L' ::= L' "=&gt;" L1。然后使用L3,我会对L' 版本进行括号括起来,如下所示:_. L3 ::= "(" L' ")";

标签: parsing grammar context-free-grammar bnfc


【解决方案1】:

您可以通过简单地从顶层禁止带括号的形式来做到这一点。这需要以不同的方式编写优先层次结构,以便通过层次结构传播限制。在下文中,r 后缀表示产生式被“限制”为不是括号形式。

我还通过消除NOT 产生式之一来修复reduce/reduce 冲突。见下文。

(我希望我的 BNFC 是正确的。我用 bison 写了这个,然后尝试转换语法。)

_       .   S     ::=   L0r             ;

IFF     .   L0r   ::=   L0 "<=>" L1     ;
IF      .   L0r   ::=   L0 "=>"  L1     ;

AND     .   L1r   ::=   L1 "&"   L2     ;
OR      .   L1r   ::=   L1 "|"   L2     ;

NOT     .   L2r   ::=       "-"   L2    ;
ID      .   L2r   ::=   Ident           ;                                            

PAREN   .   L3    ::=   "(" L0 ")"      ;

_       .   L0r   ::=   L1r             ;
_       .   L1r   ::=   L2r             ;

_       .   L0    ::=   L0r             ;
_       .   L1    ::=   L1r             ;
_       .   L2    ::=   L2r             ;

_       .   L0    ::=   L3              ;
_       .   L1    ::=   L3              ;
_       .   L2    ::=   L3              ;

(编辑:我更改了IFFIFANDOR 规则,方法是从第一个参数中删除限制(r)。这允许规则匹配以括号开头但不匹配 PAREN 语法的表达式。)

如果您还想禁止多余的内部括号(如((a &amp; b))),您可以将PAREN 规则更改为

PAREN   .   L3    ::=   "(" L0r ")"     ;                       

这将使L0 规则变得不必要。

可以在@IraBaxterGrammar for expressions which disallows outer parentheses 的答案中找到一种使用较少单元生产的变体方法。

旁注:

这个语法也会导致大约 6 次 reduce/reduce 冲突,但这些在递归定义中不是不可避免的吗?

不,递归语法可以而且应该是明确的。减少/减少冲突并非不可避免,并且几乎总是表明语法存在问题。在这种情况下,它们是一元 NOT 运算符的冗余产生的结果。有两个可以接受"-" L3 的不同非终结符显然会导致歧义,而歧义总是会产生解析冲突。

【讨论】:

  • 这让我知道应该如何做,但是你忽略了 BNFC 强加的一些规则,所以这不会立即编译。 r 后缀应转换为数字,并且符号 | 无法识别,就像在 BNF 的许多其他变体中一样。最后的规则都应该在它们自己的行上。
  • @sesodesa:抱歉,我不使用 BNFC。你有某种参考文件吗? (或者,我可以包含野牛版本,它可以编译和运行:-))
  • @Sesodesa:好的,我修正了| 的使用。假设 this 是您正在谈论的 BNFC,我看不出使用 L1r 会出现问题。
  • 好吧,未经编辑的答案根本无法为我编译,因为bnfc 抱怨这些特定规则。问题是显然被强制的规则需要具有相同的基本标识符(字母前缀字符串),并且不同的强制级别由后缀数字分隔。这是解释here
  • @SeSodesa:是的,你是对的,这意味着我做错了。我正在解决一个不同的问题,即如何禁止以括号开头的表达式。 (这经常出现,因为在表达式是语句且语句不需要用分号分隔的语言中,您必须避免以括号开头的语句表达式,以避免函数调用产生歧义)。但你的情况不同。我玩了一点 BNFC,我有一些它没有抱怨的东西,所以我会用它来编辑答案。
猜你喜欢
  • 1970-01-01
  • 2012-03-31
  • 1970-01-01
  • 2015-10-05
  • 2020-11-25
  • 2014-12-12
  • 2019-12-16
  • 2023-02-02
  • 1970-01-01
相关资源
最近更新 更多