在我的语法中,我有这些词法规则:
DECIMAL_NUMBER: DIGITS? DOT_SYMBOL DIGITS;
// Identifiers might start with a digit, even though it is discouraged.
IDENTIFIER: LETTER_WHEN_UNQUOTED+;
fragment LETTER_WHEN_UNQUOTED:
'0'..'9'
| 'A'..'Z' // Only upper case, as we use a case insensitive parser (insensitive only for ASCII).
| '$'
| '_'
| '\u0080'..'\uffff'
;
WHITESPACE: ( ' ' | '\t' | '\f' | '\r'| '\n') { $channel = HIDDEN; };
和这个解析器规则:
qualified_identifier: IDENTIFIER '.' IDENTIFIER;
除了一个特殊情况外,这很好用,例如:
... a.0b
这里的问题是.0由DECIMAL_NUMBER规则捕获,但如果在任何数字后面有非数字字符,我需要忽略它。怎么办呢?
我正在考虑验证谓词,但如果DECIMAL_NUMBER规则与它不匹配,则会彻底破坏解析。我的另一个想法是添加一个动作检查,跟踪到目前为止匹配的任何字符,然后手动生成令牌,这看起来非常难看。
当我的动作代码确定这不是十进制数字时,是否可以在点后标记位置并在输入流中返回它?
答案 0 :(得分:1)
如果我们有一个纯十进制数字,则必须将DECIMAL_NUMBER规则扩展为仅匹配:
DECIMAL_NUMBER:
DIGITS DOT_SYMBOL DIGITS
| DOT_SYMBOL {if (!isAllDigits(ctx)) {FAILEDFLAG = ANTLR3_TRUE; return; }} DIGITS
;
如果后向跟踪处于活动状态,我必须使用与语义谓词隐式使用的相同代码。但是,只有一个谓词没有完成这项工作,因为在这种情况下没有设置所需的后退跟踪标志。
检查输入的功能是:
ANTLR3_BOOLEAN isAllDigits(pMySQLLexer ctx)
{
int i = 1;
while (1)
{
int input = LA(i++);
if (input == EOF || input == ' ' || input == '\t' || input == '\n' || input == '\r' || input == '\f')
return ANTLR3_TRUE;
// Need to check if any of the valid identifier chars comes here (which would make the entire string to an identifier).
// For the used values look up the IDENTIFIER lexer rule.
if ((input >= 'A' && input <= 'Z') || input == '$' || input == '_' || (input >= 0x80 && input <= 0xffff))
return ANTLR3_FALSE;
// Everything else but digits is considered valid input for a new token.
if (input < '0' && input > '9')
return ANTLR3_TRUE;
}
}
答案 1 :(得分:0)
如果内存服务,词法分析器是贪婪的(即寻找在输入流中任何给定点匹配的最长令牌。在平局中,顺序很重要。我非常确定你的唯一解决方案是制作虚线标识符是一个杠杆规则,然后分解后解析的令牌(在我的语法中,这就是我如何处理ID)
看看你指定的是什么,因为IDENTIFIER可以从一个数字开始(并且只需要一个或多个字符),那么我相信你有一个词法分析模糊(1.2是一个点缀的IDENTIFIER或者十进制数)。您可能需要打破使IDENTIFIER令牌指定两个备选(一个以一个或多个数字开头,但要求至少包含非数字字符,另一个允许一个或多个非数字)字符。 (也许你已经在真正的语法中处理了这个问题,这只是针对这个问题进行了简化)。