我试图让解析器识别度量单位,然后根据需要使用侦听器转换单位。然而,当解析测试语句时,当解析器在文本的其他部分(例如在单词的中间)中看到单元时,我得到错过的匹配输入错误。这是我的代码的缩减版本。
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>'
| '²'
| '\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规则将其识别为英寸但因为没有数量它会引发错误。
任何人都可以帮我解决这个问题,这样我就可以让语法忽略那些不匹配的输入吗?任何人都可以告诉我,我是否正确地使递归位正确,直到句子结束。
答案 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'
!),我得到以下解析树: