【问题标题】:Remove Ambiguity in abstract syntax in other to write DCG parser Prolog删除其他抽象语法中的歧义以编写 DCG 解析器 Prolog
【发布时间】:2012-10-30 00:33:26
【问题描述】:

P => 程序 K => 阻塞

S => 单命令

C => 命令

E => 表达式

B => 布尔表达式

I => 标识符

N > 数字

P ::= K.

K ::= 开始 C 结束

C ::= C1 ; C2 | S

S ::= I := E |如果 (B) 则 S |如果 (B) 则 S1 否则 S2 |而(B)做S |重复 C 直到 (B) | ķ |打印E

E ::= - E | E1 + E2 | E1 - E2 | E1 E2 | E1 分区 E2 | E1 模组 E2 | (五) |我 |否

B ::= E1 = E2 | E1 > E2 | E1

我应该删除 E 和 B 中的歧义,以便我可以在 prolog 中编写 DCG 解析器。

【问题讨论】:

    标签: prolog dcg left-recursion


    【解决方案1】:

    Prolog 自上而下评估,然后可以调整 LL grammar techniques。 DCG 比 LL(1) 更强大,但仍然必须消除左递归。

    B 更容易处理:左因子产生式。

    B ::= E Bx | not B | (B)
    Bx ::= = E | > E | < E | != E | and B | or B
    

    E 更难,因为缺少mul 标记引入了更多的歧义。暂定

    E ::= − E | (E) | I | N | El
    El ::= Ex E | epsilon
    Ex ::= + El | − El | div El | mod El
    

    DCG中的epsilon(空产生式)可以这样写

    epsilon --> [].
    

    如果您需要处理优先级和关联性(在 B 和 E 中),则需要做更多的工作。您可以参考 this 较早的答案以获取有效的架构。

    【讨论】:

      【解决方案2】:

      @chac 已经给了你一个很好的答案,向你展示了解决这个问题的常用方法。

      让我以另一种方式阅读您的问题:您“应该删除 E 和 B 中的歧义,以便”您“可以在 Prolog 中编写 DCG 解析器”。这意味着,您只需要消除歧义,就可以在 Prolog 中编写 DCG 解析器。有个好消息:编写 DCG 解析器根本不需要消除任何歧义!方法如下:

      歧义的来源是产生式

      C ::= C ; C

      或其他运算符 + - 并列 div mod 和

      让我坚持一个简化的语法:

      E ::= E + E | “1”

      我们可以将其编码为

      e --> "1".
      e --> e, "+", e.
      

      不幸的是,Prolog 不会因类似的查询而终止

      ?- L = "1+1+1", phrase(e,L).
      L = "1+1+1" ;
      ERROR: Out of local stack
      

      实际上,它终止了,但只是因为我的计算机的内存是有限的......

      甚至没有:

      ?- L = "1", phrase(e,L).
      L = "1" ;
      ERROR: Out of local stack
      

      这是一个模棱两可的问题吗?不!这只是 Prolog 的一个程序问题,不能直接处理左递归。这是让 Prolog 处理它的一种方法:

      e([_|S],S) --> "1"。 e([_|S0],S) --> e(S0,S1), "+", e(S1,S)。 ?- L = "1+1+1", 短语(e(L,[]),L)。 L = "1+1+1" ; L = "1+1+1" ; 错误的。 ?- L = "1", 短语(e(L,[]),L)。 L = "1" ; 错误的。

      目前我们只定义了一个语法,大部分时候你也有兴趣看看对应的语法树:

      e(整数(1), [_|S],S) --> "1"。 e(加(L,R), [_|S0],S) --> e(L, S0,S1), "+", e(R, S1,S)。 ?- L = "1+1+1", 短语(e(Tree, L,[]),L)。 L = "1+1+1", 树 = plus(integer(1),plus(integer(1),integer(1))) ; L = "1+1+1", 树 = plus(plus(integer(1),integer(1)),integer(1)) ; 错误的。

      现在,我们看到plus 存在歧义!您的原始语法都接受它为 (1+1)+1 和 1+(1+1) 只要相应的语义保证观察到关联性,这本身就不是问题。大多数情况下,这被消除为左结合,因此意味着 (1+1)+1,但并非所有中缀运算符都是如此。

      【讨论】:

      • 绕过左递归限制的好技巧!不好理解……到底有多笼统?
      • @chac:这是列表长度的另一个区别。您甚至可以通过向左移动来进一步优化它(我很少这样做,因为它节省了一些运行时间,但显着增加了我的思考时间)。至于它的普遍性:这很好,但对于更大的输入来说不是很现实——它变得非常昂贵。但是,有时可以enforce semidet mode 获取“相关块”。
      猜你喜欢
      • 2011-09-25
      • 1970-01-01
      • 1970-01-01
      • 2014-09-02
      • 1970-01-01
      • 1970-01-01
      • 2022-08-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多