В вашем правиле shortFunction
может быть вызван пользовательский метод, который, учитывая paramList
, удалит из них все идентификаторы, оставляя только типы, и вставит это дерево в нужное место:
shortFunction
: type ID '(' paramList ')' block
-> ^( ... {customMethod($paramList.tree)} ... )
;
Демо:
файл: Fun.g
grammar Fun;
options {
output=AST;
ASTLabelType=CommonTree;
}
tokens {
ROOT;
PARAM;
PARAM_LIST;
BLOCK;
VAR_DEF;
FUN;
TYPE_FUN;
TYPE_SIMP;
}
@parser::members {
private CommonTree stripIDs(CommonTree tree) {
CommonTree copy = new CommonTree(new CommonToken(PARAM_LIST, "PARAM_LIST"));
for(int i = 0; i < tree.getChildCount(); i++) {
CommonTree temp = (CommonTree)tree.getChild(i);
CommonTree child = new CommonTree(temp);
child.addChild(new CommonTree((CommonTree)temp.getChild(0)));
copy.addChild(child);
}
return copy;
}
}
parse
: function+ EOF -> ^(ROOT function+)
;
function
: shortFunction
| longFunction
;
shortFunction
: type ID '(' paramList ')' block
-> ^(VAR_DEF ^(TYPE_FUN ^(TYPE_SIMP type) {stripIDs($paramList.tree)}) ID ^(FUN ^(TYPE_SIMP type) paramList block))
;
longFunction
: '#' t1=type '(' typeList ')' ID ':' t2=type '(' paramList ')' block
-> ^(VAR_DEF ^(TYPE_FUN ^(TYPE_SIMP $t1) typeList) ID ^(FUN ^(TYPE_SIMP $t2) paramList block))
;
paramList
: (param (',' param)*)? -> ^(PARAM_LIST param*)
;
param
: type ID -> ^(PARAM type ID)
;
typeList
: (type (',' type)*)? -> ^(PARAM_LIST ^(PARAM type)*)
;
type
: INT
| SHORT
| BYTE
;
block
: '{' '...' '}' -> ^(BLOCK '...')
;
SHORT : 'short';
BYTE : 'byte';
INT : 'int';
ID : ('a'..'z' | 'A'..'Z') ('a'..'z' | 'A'..'Z' | '0'..'9')*;
SPACE : (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;};
файл: Main.java
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;
public class Main {
public static void main(String[] args) throws Exception {
String source = "#short(byte, int) f: short(byte a, int b) { ... } short f(byte a, int b) { ... }";
FunLexer lexer = new FunLexer(new ANTLRStringStream(source));
FunParser parser = new FunParser(new CommonTokenStream(lexer));
CommonTree tree = (CommonTree)parser.parse().getTree();
DOTTreeGenerator gen = new DOTTreeGenerator();
StringTemplate st = gen.toDOT(tree);
System.out.println(st);
}
}
Если вы запустите основной класс, вы увидите, что ввод:
#short(byte, int) f: short(byte a, int b) { ... }
short f(byte a, int b) { ... }
производит два одинаковых дерева: