我正在尝试创建一个解析器来识别测量单位,然后使用监听器根据需要转换单位。然而,在解析测试句子时,当解析器看到文本其他部分(例如单词中间)的单元时,我会收到丢失匹配输入错误。这是我的代码的精简版本。
测量单位.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>'
| '²'
| '\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'
!),我得到以下解析树:
关于java - Antlr v4 我可以忽略不匹配的输入吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22717130/