我正在解析一种具有语句'代码'的语言,其次是'{',然后是一堆我对解析的兴趣,然后是'}'。理想情况下,我想拥有一个规则:
skip_code: 'code' '{' ~['}']* '}'
..这只会跳到闭合的卷曲支架上。问题在于被跳过的代码本身可能具有成对的卷发括号。因此,我从本质上需要做的是运行计数器并在每个" {'"上递增每个"}",然后在计数器返回到0时结束解析规则。
在Antlr4中这样做的最好方法是什么?当检测到"代码"并吞下令牌并运行我的柜台时,我是否应该跳过自定义功能,还是在语法本身中表达这一点?
编辑:按要求的一些示例代码:
class foo;
int m_bar;
function foo_bar;
print("hello world");
endfunction
code {
// This is some C code
void my_c_func() {
printf("I have curly braces {} in a string!");
}
}
function back_to_parsed_code;
endfunction
endclass
我会使用以下内容:
skip_code: CODE_SYM block;
block: OPEN_CURLY (~CLOSE_CURLY | block)* CLOSE_CURLY;
CODE_SYM: 'code';
OPEN_CURLY: '{';
CLOSE_CURLY: '}';
我会在Lexer中处理这些代码块。快速演示:
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.Token;
public class Main {
public static void main(String[] args) {
String source = "class foo;n" +
" int m_bar;n" +
" function foo_bar;n" +
" print("hello world");n" +
" endfunctionn" +
" code {n" +
" // This is some C code }}} n" +
" void my_c_func() {n" +
" printf("I have curly braces {} in a string!");n" +
" }n" +
" }n" +
" function back_to_parsed_code;n" +
" endfunctionn" +
"endclass";
System.out.printf("Tokenizing:nn%snn", source);
DemoLexer lexer = new DemoLexer(new ANTLRInputStream(source));
for (Token t : lexer.getAllTokens()){
System.out.printf("%-20s '%s'n",
DemoLexer.VOCABULARY.getSymbolicName(t.getType()),
t.getText().replaceAll("[rn]", "\\n")
);
}
}
}
如果您在上面运行类,则将打印以下内容:
Tokenizing:
class foo;
int m_bar;
function foo_bar;
print("hello world");
endfunction
code {
// This is some C code }}}
void my_c_func() {
printf("I have curly braces {} in a string!");
}
}
function back_to_parsed_code;
endfunction
endclass
ID 'class'
ID 'foo'
ANY ';'
ID 'int'
ID 'm_bar'
ANY ';'
ID 'function'
ID 'foo_bar'
ANY ';'
ID 'print'
ANY '('
STRING '"hello world"'
ANY ')'
ANY ';'
ID 'endfunction'
ID 'code'
BLOCK '{n // This is some C code }}} n void my_c_func() {n printf("I have curly braces {} in a string!");n }n }'
ID 'function'
ID 'back_to_parsed_code'
ANY ';'
ID 'endfunction'
ID 'endclass'
您可以将模式用于目的。请注意两种模式的代码部分。YOY不能仅使用一种模式正确关闭代码部分。
lexer
lexer grammar Question_41355044Lexer;
CODE: 'code';
LCURLY: '{' -> pushMode(CODE_0);
WS: [ trn] -> skip;
mode CODE_0;
CODE_0_LCURLY: '{' -> type(OTHER), pushMode(CODE_N);
RCURLY: '}' -> popMode; // Close for LCURLY
CODE_0_OTHER: ~[{}]+ -> type(OTHER);
mode CODE_N;
CODE_N_LCURLY: '{' -> type(OTHER), pushMode(CODE_N);
CODE_N_RCURLY: '}' -> type(OTHER), popMode;
OTHER: ~[{}]+;
PARSER
parser grammar Question_41355044Parser;
options { tokenVocab = Question_41355044Lexer; }
skip_code: 'code' LCURLY OTHER* RCURLY;
输入
code {
// This is some C code
void my_c_func() {
printf("I have curly braces {} in a string!");
}
}
输出令牌
CODE LCURLY({) OTHER( // Th...) OTHER({) OTHER( pr...)
OTHER({) OTHER(}) OTHER( in a st...) OTHER(}) OTHER() RCURLY(}) EOF
ANTLR语法解析本身使用相同的方法:https://github.com/antlr/grammars-v4/tree/master/master/antlr4
但是在那里使用运行时代码LexerAdaptor.py
而不是两级模式。