在ANTLR4中处理歧义语法中的重载符号



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

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

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

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: [ trn]+ -> 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 '.'

非常感谢!

在您的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之间有效,可能需要做更多的工作。

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

如果lexer不能决定1..21..2还是1 .. 2,则由解析器决定。

也许有一种语境可以将其解释为第一备选方案,而另一种语境则可以将其理解为第二备选方案。

Btw:1..2.可被解释为1 .. 2 .range)或1. . 2 .floatNumintNum)。你想怎么处理这个问题?

下面的语法应该解析所有内容。但请注意,. .被视为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: [ trn]+ -> skip ;
fragment NONZERO     : [1-9] ;
fragment DIGIT       : [0] | NONZERO ;

Prolog不接受1.作为浮点值。这个功能会让你的语法变得更加模糊,所以也许可以尝试删除这个功能。

相关内容

  • 没有找到相关文章

最新更新