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

时间:2014-03-28 15:34:32

标签: java parsing antlr4

我试图让解析器识别度量单位,然后根据需要使用侦听器转换单位。然而,当解析测试语句时,当解析器在文本的其他部分(例如在单词的中间)中看到单元时,我得到错过的匹配输入错误。这是我的代码的缩减版本。

UnitsOfMeasure.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();
}

因此,这里的监听器会在解析流时对构建器进行一些编辑。一个有效的例子如下:

&#34;白板有1550平方英寸的书写空间&#34; 返回:

&#34;白板1550in 2 (1m 2 )的写作空间&#34;

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

  

第1:44行输入错误输入&#39;期待{EOF,QUANTITY}

在:

&#34;白板具有1550平方英寸的书写空间,触摸屏尺寸为775平方英寸&#34; 返回:

&#34;白板具有1550英寸 2 (1m 2 )的书写空间,以及775平方英寸的触摸屏&#34;

在调试器之后,它执行第一次转换而没有错误,然后在它向前看后退出。我可能还没有得到递归部分,但基本上语法应该继续查找,直到它找到一个数量后跟一个度量单位。如果数量未被认可的单位跟随,则应忽略它并继续。

从错误中我可以看到它已经选择了&#39; in&#39;写作&#39;因为我有一个Lexer规则将其识别为英寸但因为没有数量它会引发错误。

任何人都可以帮我解决这个问题,这样我就可以让语法忽略那些不匹配的输入吗?任何人都可以告诉我,我是否正确地使递归位正确,直到句子结束。

2 个答案:

答案 0 :(得分:1)

使用自由形式语言的解析器不是一个好主意。你需要的是一个有点关键词发现。您查看输入,例如使用正则表达式,对于某些形式的可识别输入,并从此字符串子部分中提取确切的值。

解析器需要一种定义良好的语言,即一种可以完全放入规则中的语言(毫不含糊)。使用自由输入文本只是一个不同的语法,填充词,拼写错误等将彻底破坏你的解析。

答案 1 :(得分:1)

如果您不想将令牌INCH与另一个词的一部分匹配,则需要匹配单词,并跳过这些:

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

请确保在 INCH规则之后放置此规则,否则它也会与输入"in"匹配(您显然不想要) )。你还想扩展这个规则匹配的字符:只有ascii字母是不够的。

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

虽然正确:

include_metric_units
    : imperial_types
    | include_metric_units imperial_types
    ;

它相当 LR / Bison -esque。更可读的是写:

include_metric_units
    : imperial_types+
    ;

要匹配可能位于令牌流中的令牌,但未与您的任何作品匹配,只需匹配顶级规则中的任何令牌:

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