我有一个使用一些片段的词法规则(Integer)。在解析器规则(解析)中,我想以不同的方式重写我的树,具体取决于生成相关令牌的片段。我做了一个小语法来证明我正在尝试的东西:
grammar subrange;
options {
output=AST;
}
tokens {
NumberNode;
DecimalNode;
BinaryNode;
HexNode;
OctalNode;
}
parse
: Integer+ -> ^(NumberNode Integer)+
;
Integer
: DECIMAL_LITERAL
| BINARY_LITERAL
| HEX_LITERAL
| OCTAL_LITERAL
;
fragment BINARY_LITERAL
: '2#' ('0' | '1')+
;
fragment HEX_LITERAL
: ('16#' | '0' ('x'|'X')) HEX_DIGIT+
;
fragment HEX_DIGIT
: (DIGIT|'a'..'f'|'A'..'F')
;
fragment DECIMAL_LITERAL
: ('0' | '1'..'9' DIGIT*)
;
fragment OCTAL_LITERAL
: '8#' ('0'..'7')+
;
fragment DIGIT
: '0'..'9'
;
SPACE : (' ' | '\t' | '\r' | '\n')+ {skip();};
我希望解析规则在假想的DecimalNode下重写DECIMAL_LITERAL,而在BinaryNode下重写BINARY_LITERAL(而不是NumberNode下的所有内容)。
我试图通过更改词法规则中的令牌类型来做到这一点,这样我就可以在解析规则中相应地重写。
我想我应该可以通过一个动作来做到这一点,但是我一直无法弄清楚如何找到返回的令牌以便改变它的类型。 http://www.antlr.org/wiki/display/ANTLR3/Special+symbols+in+actions似乎表明$ tokenref应该有效,但根本不会被翻译。
或者还有另一种方法可以实现这个目标吗?
提前致谢。
答案 0 :(得分:2)
对我来说似乎有点奇怪:将所有这些文字分组到一个Integer
标记下,然后在解析器规则中再次将它们分开。
为什么不删除Integer
并执行:
integer
: BINARY_LITERAL // when output=AST, this creates a CommonTree with type 'BINARY_LITERAL'
| HEX_LITERAL // ...
| DECIMAL_LITERAL
| OCTAL_LITERAL
;
BINARY_LITERAL
: '2#' ('0' | '1')+
;
HEX_LITERAL
: ('16#' | '0' ('x'|'X')) HEX_DIGIT+
;
DECIMAL_LITERAL
: ('0' | '1'..'9' DIGIT*)
;
OCTAL_LITERAL
: '8#' ('0'..'7')+
;
或者你可以保留Int(eger)
规则但是通过这样做来设置各种int-literals的数值:
Int
@init{int skip = 0, base = 10;}
: ( DECIMAL_LITERAL
| BINARY_LITERAL {base = 2; skip = 2;}
| OCTAL_LITERAL {base = 8; skip = 2;}
| HEX_LITERAL {base = 16; skip = $text.contains("#") ? 3 : 2;}
)
{
setText(String.valueOf(Integer.parseInt($text.substring(skip), base)));
}
;
fragment BINARY_LITERAL
: '2#' ('0' | '1')+
;
fragment HEX_LITERAL
: ('16#' | '0' ('x'|'X')) HEX_DIGIT+
;
fragment DECIMAL_LITERAL
: ('0' | '1'..'9' DIGIT*)
;
fragment OCTAL_LITERAL
: '8#' ('0'..'7')+
;
小心给规则一个名称,因为目标语言的某些对象/类/保留字可以有(Integer
,如果是Java)。
好。我会留下我的另一个答案,万一路人想知道为什么我在提议这个......:)
以下是(我认为)您所追求的内容:
grammar T;
options {
output=AST;
}
tokens {
BinaryNode;
OctalNode;
HexNode;
DecimalNode;
}
parse
: integer+
;
integer
: i=Integer -> {$i.text.startsWith("2#")}? ^(BinaryNode Integer)
-> {$i.text.startsWith("8#")}? ^(OctalNode Integer)
-> {$i.text.matches("(16#|0[xX]).*")}? ^(HexNode Integer)
-> ^(DecimalNode Integer)
;
Integer
: DECIMAL_LITERAL
| BINARY_LITERAL
| HEX_LITERAL
| OCTAL_LITERAL
;
fragment BINARY_LITERAL
: '2#' ('0' | '1')+
;
fragment HEX_LITERAL
: ('16#' | '0' ('x'|'X')) HEX_DIGIT+
;
fragment HEX_DIGIT
: (DIGIT|'a'..'f'|'A'..'F')
;
fragment DECIMAL_LITERAL
: ('0' | '1'..'9' DIGIT*)
;
fragment OCTAL_LITERAL
: '8#' ('0'..'7')+
;
fragment DIGIT
: '0'..'9'
;
SPACE
: (' ' | '\t' | '\r' | '\n')+ {skip();}
;
解析输入"2#1111 8#77 0xff 16#ff 123"
将导致以下AST:
由于您丢失了有关每个文字的Integer
类型的信息,因此您必须在integer
- 规则(重写后的-> {boolean-expression}? ...
内容中进行此项检查规则)。