java - Antlr v4 我可以忽略不匹配的输入吗?

标签 java parsing antlr4

我正在尝试创建一个解析器来识别测量单位,然后使用监听器根据需要转换单位。然而,在解析测试句子时,当解析器看到文本其他部分(例如单词中间)的单元时,我会收到丢失匹配输入错误。这是我的代码的精简版本。

测量单位.g4

grammar UnitsOfMeasure;

import
    ImperialUnitsParser;

/*------------------------------------------------------------------
 * UNITS OF MEASURE PARSER RULES
 *------------------------------------------------------------------*/
include_metric_units
    : imperial_types
    | include_metric_units imperial_types
    ;

imperial_types
    : i_area
    ;

i_area
    : QUANTITY square_inch
    | QUANTITY square_feet
    | QUANTITY square_mile
    | QUANTITY square_yard
    ;

/*------------------------------------------------------------------
 * UNITS OF MEASURE - LEXER RULES
 *------------------------------------------------------------------*/
SQUARE
    : [S|s]'quare'
    | [S|s]'q' '.'?
    ;

SQUARED
    : [S|s]'quared'
    | '^2'
    | '<sup>2</sup>'
    | '&#178'
    | '\u00B2'
    ;

fragment PLURAL
    : 's'  ?
    | 'es' ?
    ;

QUANTITY
    : '-'? FLOAT
    | '-'? DIGITS
    ;

FLOAT
    : DIGITS '.' DIGITS
    ;

fragment DIGITS
    : DIGIT+
    ;

fragment DIGIT
    : '0'..'9'
    ;

/*------------------------------------------------------------------
 * SKIP EVERYTHING ELSE
 *------------------------------------------------------------------*/ 
 EVERYTHING 
    : . -> skip 
    ;

ImperialUnitsParser.g4

parser grammar ImperialUnitsParser;

import ImperialUnitsLexer;

/*------------------------------------------------------------------
 * AREA
 *------------------------------------------------------------------*/
square_inch
    : SQUARE INCH
    | INCH SQUARED
    ;

/*------------------------------------------------------------------
 * LENGTH
 *------------------------------------------------------------------*/
inch
    : INCH
    ;

ImperialUnitsLexer.g4

lexer grammar ImperialUnitsLexer;

/*------------------------------------------------------------------
 * BASE UNITS
 *------------------------------------------------------------------*/
INCH
    : [I|i]'nch' PLURAL
    | [I|i]'n' '.'?
    ;

Convert.java

public static String includeMetricUnits(String parse) throws UnitsOfMeasureParserRuntimeException
{           
    StringBuilder builder = new StringBuilder(parse);

    ANTLRInputStream in = new ANTLRInputStream(builder.toString());
    UnitsOfMeasureLexer lexer = new UnitsOfMeasureLexer(in);
    CommonTokenStream tokens = new CommonTokenStream(lexer);

    UnitsOfMeasureParser parser = new UnitsOfMeasureParser(tokens);
    parser.addParseListener(new UnitsOfMeasureParseListener(builder));
    parser.addErrorListener(new UnitsOfMeasureErrorListener());
    parser.include_metric_units(0);
    return builder.toString();
}

因此,这里的监听器在解析流时会对构建器进行一些编辑。其工作示例如下:

“具有 1550 平方英寸书写空间的白板” 返回:

“具有 1550 英寸2(1m2) 书写空间的白板”

但是,当我通过添加多个单元使其变得更复杂时,它会报告以下内容:

line 1:44 mismatched input 'in' expecting {EOF, QUANTITY}

关于:

“具有 1550 平方英寸书写空间的白板和 775 平方英寸的触摸屏” 返回:

“具有 1550 英寸2(1m2) 书写空间的白板和 775 平方英寸的触摸屏”

在调试器之后,它执行第一次转换,没有错误,然后在预测后退出。我可能还没有完全正确地理解递归部分,但本质上语法应该继续查找,直到找到一个数量后跟一个度量单位。如果数量后面没有可识别的单位,则应忽略它并继续。

从错误中我可以看到它在“writing”中拾取了“in”,因为我有一个 Lexer 规则将其识别为英寸,但因为没有数量,所以会引发错误。

任何人都可以帮助我解决这个问题,以便我可以让语法忽略不匹配的输入吗?谁能告诉我递归位是否正确,以便它持续到句子末尾。

最佳答案

当您不想匹配属于另一个单词的标记 INCH 时,您需要匹配单词,并跳过这些:

WORD
 : [a-zA-Z]+ -> skip
 ;

请确保将此规则放置在 INCH 规则之后,否则它也会将输入“in”作为单词进行匹配(你显然不想要)。您还需要扩展此规则匹配的字符:仅 ascii 字母是不够的。

此外,[I|i] 也匹配管道字符:改为执行 [Ii]

虽然正确:

include_metric_units
    : imperial_types
    | include_metric_units imperial_types
    ;

这有点LR/Bison风格。更具可读性的是这样写:

include_metric_units
    : imperial_types+
    ;

要匹配 token 流中可能存在但与您的任何作品都不匹配的 token ,只需匹配顶级规则中的任何 token 即可:

parse
  :  ( include_metric_units // match metrics
     | .                    // or any "dangling" single token
     )*                     // zero or more times
     EOF                    // end of the input
  ;

include_metric_units
  :  imperial_types+
  ;

是的,这是正确的:生产/解析器规则中的 . (DOT) 匹配单个标记,而不是单个字符。它仅匹配词法分析器规则中的单个字符。

当我现在解析输入时

A whiteboard with 1550 square inches of writing space, and 
a touchscreen measuring 775 square inches and an in at the end...

(注意最后的'in'!),我得到以下解析树:

enter image description here

关于java - Antlr v4 我可以忽略不匹配的输入吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22717130/

相关文章:

c# - Enum.Parse() 或 Switch

antlr - 语法文件 .g 从 Antlr 2.7 到 4 的兼容性?

java - 调用已经适用于单选按钮的函数,以便打印详细信息

Java - 读完后让套接字客户端保持 Activity 状态

c++ - 用 C++ 为格式化文本编写解析器

jquery - 解析多级JSON

listener - ANTLR 4 : How get correct order arguments in Listeners

parsing - ANTLR4 语法在输入时没有可行的选择

java - 如何从嵌套的 Hashmap 中获取数据?

java - 部署到 websphere 时在 hibernate 5 上使用 JPA 2.0