当前位置: 首页 > 面试题库 >

Antlr:初学者的输入期望ID不匹配

范玄裳
2023-03-14
问题内容

作为一个初学者,当我从《权威的ANTLR 4参考》一书中学习ANTLR4时,我尝试从第7章运行修改后的练习版本:

/**
 * to parse properties file
 * this example demonstrates using embedded actions in code
 */
grammar PropFile;

@header  {
    import java.util.Properties;
}
@members {
    Properties props = new Properties();
}
file
    : 
    {
        System.out.println("Loading file...");
    }
        prop+
    {
        System.out.println("finished:\n"+props);
    }
    ;

prop
    : ID '=' STRING NEWLINE 
    {
        props.setProperty($ID.getText(),$STRING.getText());//add one property
    }
    ;

ID  : [a-zA-Z]+ ;
STRING  :(~[\r\n])+; //if use  STRING : '"' .*? '"'  everything is fine
NEWLINE :   '\r'?'\n' ;

由于Java属性只是键值对,因此我STRING用来匹配eveything除外NEWLINE(我不希望它仅支持双引号中的字符串)。运行以下句子时,我得到:

D:\Antlr\Ex\PropFile\Prop1>grun PropFile prop -tokens
driver=mysql
^Z
[@0,0:11='driver=mysql',<3>,1:0]
[@1,12:13='\r\n',<4>,1:12]
[@2,14:13='<EOF>',<-1>,2:14]
line 1:0 mismatched input 'driver=mysql' expecting ID

当我改用STRING : '"' .*? '"'它时,它可以工作。

我想知道我错在哪里,以便将来避免类似的错误。

请给我一些建议,谢谢!


问题答案:

由于ID和STRING都可以匹配以“ driver”开头的输入文本,因此,即使ID规则排在最前面,词法分析器也会选择最长的匹配项。

因此,您在这里有几种选择。最直接的方法是通过要求字符串以等号开头来消除ID和STRING之间的歧义(这是替代方法的工作方式)。

file : prop+ EOF ;
prop : ID STRING NEWLINE ;

ID      : [a-zA-Z]+ ;
STRING  : '=' (~[\r\n])+;
NEWLINE : '\r'?'\n' ;

然后,您可以使用操作从字符串标记的文本中修剪等号。

或者,您可以使用谓词消除规则的歧义。

file : prop+ EOF ;
prop : ID '=' STRING NEWLINE ;

ID      : [a-zA-Z]+ ;
STRING  : { isValue() }? (~[\r\n])+; 
NEWLINE : '\r'?'\n' ;

其中,isValue方法在字符流上向后看以验证其是否跟随等号。就像是:

@members {
public boolean isValue() {
    int offset = _tokenStartCharIndex;
    for (int idx = offset-1; idx >=0; idx--) {
        String s = _input.getText(Interval.of(idx, idx));
        if (Character.isWhitespace(s.charAt(0))) {
            continue;
        } else if (s.charAt(0) == '=') {
            return true;
        } else {
            break;
        }
    }
    return false;
}
}


 类似资料:
  • 我已经开始使用ANTLR,并注意到它的lexer规则非常易变。一个极其令人沮丧的例子如下: 此语法不会匹配以下内容: c: \测试。txt x 奇怪的是,如果我将更改为这次它仍然失败,给出一条错误消息说“不匹配的输入'x'期待'x'”,这非常令人困惑。更奇怪的是,如果我将中的用法替换为,整个事情都可以正常工作(尽管会比我希望匹配的更多,所以一般来说,它对我来说不是一个有效的解决方案)。 我非常困惑

  • 以下语法在Antlr4.5和Java 1.8.45(IDE:IntelliJ Ultimate 14.1.4)中无法正常工作: 让正在评估的生成lexer和parser结果: 行1:22不匹配的输入“随机”期望方向 在使用的数据(文本文件)中,第二行已正确处理,但与上述错误消息一样,不是第一行。以下是正在使用的文本文件: 删除“行”定义中的那些空间不会发生错误。为什么?

  • 问题内容: 由于某些原因,我的代码将不接受最后一行“您想订购的商品:”的输入 谁能告诉我我的错误在这里吗?它正在正确地编译一切。我只是一个初学者,所以请简单地告诉我。 问题答案: 您需要在调用行的后面立即调用 ,原因是仅要求下一个整数不会占用输入中的整个行,因此您需要通过调用来跳至输入中的下一个新行字符 每次您需要在调用不消耗整行的方法后获取新行时,都必须执行此操作。考虑改用对象! 如果无法将输入

  • 我能够成功地设置parse(InputStream,DefaultHandler)方法签名的期望,但是当我试图模拟parse(InputSource,DefaultHandler)签名时,JMockit永远看不到调用,并抛出MissingInvocation异常。 下面的示例显示了两个测试用例,一个模拟InputSource风格,一个模拟InputStream风格: 运行testcase的结果是:

  • 我正在从版本2升级板条箱数据库。当我尝试升级在版本2中创建的表时,根据建议将x升级到3.1.6。x使用文档, https://crate.io/docs/crate/reference/en/latest/admin/system-information.html#tables-需要升级 在步骤5中, 质疑-