【问题标题】:How to read alternates in EBNF grammars如何阅读 EBNF 语法中的替代词
【发布时间】:2010-06-20 20:16:13
【问题描述】:

我有一个 EBNF 语法,其中包含一些具有这种模式的规则:

sequence ::=
    item
    | item extra* sequence

上面和下面是等价的吗?

sequence ::=
    item (extra* sequence)*

编辑

由于你们中的一些人观察到两个序列中的错误或歧义,我将给出一个具体的例子。 SVG specification 提供grammar for path data。该语法有几个具有这种模式的生成器:

lineto-argument-sequence:
    coordinate-pair
    | coordinate-pair comma-wsp? lineto-argument-sequence

上面可以改写成下面这样吗?

lineto-argument-sequence:
    coordinate-pair (comma-wsp? lineto-argument-sequence)*

【问题讨论】:

  • 你想知道你是否可以这样做,或者你是否应该这样做? EBNF 优于 BNF 的重点是(除其他外)消除对循环构造使用递归的需要。查看您链接的规范后,我可以告诉您它非常模棱两可,可能需要一堆前瞻规则。我会修改我的答案以考虑您的编辑。
  • 好吧,我想知道的一件事是,当第二种样式似乎等效但也更短时,SVG 规范是否会使用第一种样式样式是否有特殊原因,或者为什么它们没有像您建议的那样使用无递归版本。
  • 您可能会发现这些文件格式历来都有手写解析器。当一个人阅读语法时,他们会看到递归并对自己说,“看看一个循环”,但即使是最好的解析器生成器也没有人类那么聪明。像任何编程语言(这就是生成器的语法)一样,程序执行它被告知执行的操作,而不一定是您希望它执行的操作。
  • 许多著名的编译器,至少在某些时候,都是手工滚动的。没有生成器可以比手动解析器的速度和灵活性更好。解析器生成器为您提供的是在短时间内启动和运行的能力。有一些强大的生成器可以处理各种蓬松的语法,但它们有性能损失。如果你想设计一种像蝙蝠一样解析的语言,那么你应该尽可能地限制回溯和前瞻。
  • 您修改原始语法的方式(在 BNF 中有效)的问题是您保留了递归元素,在 BNF 中表示“重复和重复”,并将其包含在 [EBNF ] 可选循环,这意味着同样的事情。如果您要将语法从 BNF 翻译为 EBNF,那么您会尽可能多地尝试删除 BNF 语法中固有的递归元素和空产生式。

标签: grammar ebnf alternate


【解决方案1】:

并非如此,它们似乎有不同的错误。第一个序列在“item”周围是模棱两可的,因为“extra”是可选的。您可以将其重写为以下内容以消除歧义:

sequence3 ::= 
    item extra* sequence3

第二个在“extra”周围含糊不清,因为它基本上是两个以“extra”开头的嵌套循环。您可以将其重写为以下内容以消除歧义:

sequence4 ::=
    item ((extra|item))*

您的第一个版本可能会因包含单个“项目”(取决于解析器实现)的输入序列而窒息,因为它不会消除歧义。

我的重写假设您想要匹配以“item”开头的序列,并且可以选择后跟一系列(0 个或多个)“item”或“extra”,以任意顺序。

例如

item
item extra 
item extra item
item extra extra item
item item item item 
item item item item extra

etc.

如果没有其他信息,我个人会倾向于我标记为“sequence4”的选项,因为所有其他选项只是将递归用作昂贵的循环构造。如果您愿意给我更多信息,我可能会给出更好的答案。

编辑:基于 Jorn 的出色观察(带有一个小模组)。

如果你重写“sequence3”来移除递归,你会得到以下结果:

sequence5 ::= 
    (item extra*)+

它认为这将是我的首选版本,而不是“sequence4”。

我必须指出,以上所有三个版本在功能上都是等效的(作为识别器或生成器)。 3 的解析树与 4 和 5 不同,但我认为这可能会影响性能以外的任何东西。

编辑: 关于以下内容:

lineto-argument-sequence:
    coordinate-pair
    | coordinate-pair comma-wsp? lineto-argument-sequence

这个产品的意思是lineto-argument-sequence 由至少一个coordinate-pair 后跟零个或多个coordinate-pairs 组成,并用可选的白色/逗号分隔。以下任何一项都将构成lineto-argument-sequence(读作 -> 为“成为”):

1,2        -> (1, 2)
1.5.6      -> (1.5, 0.6)
1.5.06     -> (1.5, 0.06)
2 3 3 4    -> (2,3) (3,4)
2,3-3-4    -> (2,3) (-3,-4)
2 3 3      -> ERROR

所以coordinate-pair 实际上是任意两个连续的numbers。

我在 ANTLR 中模拟了一个似乎有效的语法。请注意,lineto_argument_sequence 使用的模式类似于 Jorn 和我之前推荐的模式。

grammar SVG;

lineto_argument_sequence
    : coordinate_pair (COMMA_WSP? coordinate_pair)*
    ;

coordinate_pair
    : coordinate COMMA_WSP? coordinate
    ;

coordinate
    : NUMBER
    ;

COMMA_WSP
    : ( WS+|WS*','WS*) //{ $channel=HIDDEN; }
    ;

NUMBER
    : '-'? (INT | FLOAT) ;

fragment
INT
    : '0'..'9'+ ;

fragment
FLOAT
    : ('0'..'9')+ '.' ('0'..'9')* EXPONENT?
    | '.' ('0'..'9')+ EXPONENT?
    | ('0'..'9')+ EXPONENT
    ;

fragment
WS  : ' '  | '\t' | '\r' | '\n'  ;

fragment
EXPONENT
    : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;

给定以下输入:

2, 3 -3 -4 5.5.65.5.6

它产生这个解析树。

alt text http://www.freeimagehosting.net/uploads/85fc77bc3c.png

【讨论】:

  • 如果“{$channel=HIDDEN;}”与其他作品混淆,您可能希望从 COMMA_WSP 中删除它,我只是将它放在那里,因为 COMMA_WSP 会使图表混乱。
  • 哦,对于像“2,3-3-4 5.5.65.5.6”这样的输入,它给出了相同的结果
【解决方案2】:

此规则也将等效于sequence ::= (item extra*)*,因此删除了sequence 上的递归。

【讨论】:

  • 好,我错过了。我要做的唯一更改是将最后一个“*”更改为“+”,否则它匹配一个空字符串。
【解决方案3】:

是的,这两种语法描述的是同一种语言。

但这真的是 EBNF 吗? Wikipedia article on EBNF 不包括 Kleene 星运算符。

【讨论】:

  • EBNF 更像是一类/一组语言,而不是单一语言。 Wirth 使用一种符号,ISO 标准使用不同的符号。我所拥有的关于这个主题的每一本书都使用了稍微不同的符号。这甚至没有考虑 BNF 版本的差异,然后是工具特定的更改。当我为我的第一个编译器(C 和 Pascal 的一个令人尴尬的混蛋)做规范时,我用箭头、希腊字母(例如不匹配的 epsilon)和循环的尾递归以一种可怕的风格编写了语法。我手工编码,因为生成的代码很乱。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-18
  • 1970-01-01
  • 2016-08-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多