【问题标题】:Dealing with overloaded symbols in ambiguous grammars in ANTLR4在 ANTLR4 中处理歧义语法中的重载符号
【发布时间】:2014-05-02 00:48:03
【问题描述】:

我正在尝试为 Answer Set Programming (ASP) 方言编写解析器,就语法而言,它看起来像带有一些扩展的 Prolog。 例如,一种扩展是expansion,这意味着例如fact(1..3).fact(1). fact(2). fact(3). 中扩展。请注意,该语言可以理解 INTFLOAT 数字并使用 . 也作为终止符。

在某些情况下,解析器无法区分整数、浮点数、扩展名和分隔符,因为我认为该语言显然是模棱两可的。在这种情况下,我必须用空格明确分隔标记。但是,任何 PrologASP 解析器都可以正确处理此类产生式。我读到 ANTLR4 可以自动消除有问题的产品的歧义,但可能需要一些帮助,但我不知道该怎么做! ;-) 我读过类似herehere 的东西,但显然它们没有帮助我。

有人能告诉我该怎么做才能克服这种歧义吗? 请注意,我无法更改语言,因为它非常标准。 为了简化专家的工作,我创建了一个最小的工作示例,如下所示。

grammar Test;

program: 
  statement* ;

statement: // DOT is the statement terminator
  range DOT |
  intNum DOT |
  floatNum DOT ;

intNum: // not needed, but helps in TestRig
  INT;

floatNum: // not needed, but helps in TestRig
  FLOAT;

range: // defines an expansion
  INT DOTS INT ;

DOTS: '..';
DOT: '.';

FLOAT: DIGIT+ '.' DIGIT* | '.' DIGIT+ ;
INT: DIGIT+ ;

WS: [ \t\r\n]+ -> skip ;

fragment NONZERO     : [1-9] ;
fragment DIGIT       : [0] | NONZERO ;

我使用以下输入:

1 .
1. .
1.5 .
.5 .
1 .. 5 .

1.
1..
1.5.
.5.
1..5.

我得到以下错误,这些错误被其他工具解析纠正:

line 8:0 extraneous input '1.' expecting '.'
line 11:2 extraneous input '.5' expecting '.'

提前非常感谢!

【问题讨论】:

  • 这种语言真的接受1.作为浮点数吗? Prolog 没有,这大大增加了您语言的歧义。
  • @Daniel Lyons 我没有意识到 Prolog 不接受 1. 作为浮点数......我只是对浮点数进行了相当标准的定义。那么,您的建议是对浮点数使用以下产生式:float: DIGIT+ '.' DIGIT+;?
  • 我认为这会有所帮助,如果它受到伤害,我会感到震惊。
  • 就这么简单!不知道如何将其标记为答案,因为您的只是评论...
  • 现在是答案。 :)

标签: parsing prolog antlr4 answer-set-programming


【解决方案1】:

在您的 DOTS 规则之前,为语句终端点添加一个唯一规则并消除 DOTS 规则的歧义(并更改您的其他规则以使用 TERMINAL):

TERMINAL: DOT { isTerminal(1) }? ;
DOTS: DOT DOT { !isTerminal(2) }? ;
DOT: '.';

谓词方法只是在 _input 字符流上向前看,以查看在当前标记索引处,下一个字符是否是空格。在语法中的 @member 块中添加这样的内容:

public boolean isTerminal(int la) {
    int offset = _tokenStartCharIndex + 1 + la;
    String s = _input.getText(Interval.of(offset, offset));
    if (Character.isWhitespace(s.charAt(0))) {
        return true;
    }
    return false;
}

如果空格在 DOTS 和尾随 INT 之间有效,则可能需要做更多的工作。

【讨论】:

  • 我想我对你的建议有一个直觉,但我明天必须做一些测试,看看我是否做对了!现在谢谢!
【解决方案2】:

我建议将工作转移到解析器。

如果词法分析器无法确定 1..21. .2 还是 1 .. 2,则由解析器决定。

也许有一个上下文可以将其解释为第一个选项,而另一个上下文可以将其解释为第二个选项。

顺便说一句:1..2. 可以解释为1 .. 2 . (range) 或1. . 2 . (floatNum, intNum)。你想怎么处理?

以下语法应该解析所有内容。但请注意. . 被视为dots 以及1 . 23floatNum!您可以在解析时或解析后检查这些难点(取决于它是否会影响解析)。

grammar Test;

program: 
  statement* ;

statement: // DOT is the statement terminator
  range DOT |
  intNum DOT |
  floatNum DOT ;

intNum: // not needed, but helps in TestRig
  INT;

floatNum: 
    INT DOT INT? | DOT INT ;

range: // defines an expansion
  INT dots INT ;

dots : DOT DOT;  

DOT: '.';

INT: DIGIT+ ;

WS: [ \t\r\n]+ -> skip ;

fragment NONZERO     : [1-9] ;
fragment DIGIT       : [0] | NONZERO ;

【讨论】:

    【解决方案3】:

    Prolog 不接受 1. 作为浮点数。此功能使您的语法明显更加模棱两可,因此不妨尝试删除该功能。

    【讨论】:

    • 现在是公认的答案!非常感谢您的帮助!
    猜你喜欢
    • 2017-04-05
    • 1970-01-01
    • 2015-11-16
    • 2023-02-05
    • 1970-01-01
    • 2014-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多