ANTLR有替代规则的访客

时间:2018-02-22 08:59:57

标签: antlr4 visitor

我有这样的语法规则:

fctDecl
    : id AS FUNCTION O_PAR (argDecl (COMMA argDecl)*)? C_PAR COLON (scalar|VOID)
    (DECLARE LOCAL (varDecl SEMICOLON)+)?
    DO (instruction)+ (RETURN id)? DONE;

当我在visitFctDecl时,我必须访问FctDecl的所有孩子。由于孩子可以是不同类型的规则,我怎么知道哪个是当前孩子的类型?

@Override
public FunctionNode visitFctDecl(B314Parser.FctDeclContext ctx) {

    for (int i = 0; i < ctx.children.size() ;i++)
    {
       //what kind of rule is ?
       ctx.children.get(i);
    }

    return null;
} 

我根本不确定如何使用访客。

1 个答案:

答案 0 :(得分:0)

首先要删除那个大的解析器规则。也许是这样的事情:

fctDecl
  : id AS FUNCTION fctParams COLON ( scalar | VOID ) localDecl doStat
  ;

fctParams
 : O_PAR ( argDecl ( COMMA argDecl )* )? C_PAR
 ;

localDecl
 : ( DECLARE LOCAL ( varDecl SEMICOLON )+ )?
 ;

doStat
 : DO instruction+ ( RETURN id )? DONE
 ;

然后在您的访问者中,您只需返回这样的自定义类(我返回地图和列表,但这可能是您自己的域对象):

public class DemoVisitor extends B314BaseVisitor<Object> {

  // fctDecl
  //  : id AS FUNCTION fctParams COLON ( scalar | VOID ) localDecl doStat
  //  ;
  @Override
  public Object visitFctDecl(B314Parser.FctDeclContext ctx) {
    Map<String, Object> result = new LinkedHashMap<String, Object>();
    result.put("id", ctx.id().getText());
    result.put("fctParams", visit(ctx.fctParams()));
    result.put("type", ctx.scalar() != null ? ctx.scalar().getText() : ctx.VOID().getText());
    result.put("localDecl", visit(ctx.localDecl()));
    result.put("doStat", visit(ctx.doStat()));
    return result;
  }

  // fctParams
  //  : O_PAR ( argDecl ( COMMA argDecl )* )? C_PAR
  //  ;
  //
  // argDecl
  //  : varDecl
  //  ;
  //
  // varDecl
  //  : ID AS type
  //  ;
  @Override
  public Object visitFctParams(B314Parser.FctParamsContext ctx) {
    List<Map<String, String>> declarations = new ArrayList<Map<String, String>>();
    if (ctx.argDecl() != null) {
      for (B314Parser.ArgDeclContext argDecl : ctx.argDecl()) {
        Map<String, String> declaration = new LinkedHashMap<String, String>();
        declaration.put(argDecl.varDecl().ID().getText(), argDecl.varDecl().type().getText());
        declarations.add(declaration);
      }
    }
    return declarations;
  }

  // localDecl
  //  : ( DECLARE LOCAL ( varDecl SEMICOLON )+ )?
  //  ;
  @Override
  public Object visitLocalDecl(B314Parser.LocalDeclContext ctx) {
    // See `visitFctParams(...)` how to traverse `( varDecl SEMICOLON )+`
    return "TODO";
  }

  // doStat
  //  : DO instruction+ ( RETURN id )? DONE
  //  ;
  @Override
  public Object visitDoStat(B314Parser.DoStatContext ctx) {
    // See `visitFctParams(...)` how to traverse `instruction+`
    return "TODO";
  }
}

如果您现在运行以下使用上述访问者的类:

public class Main {

  public static void main(String[] args) {

    String source =
        "mu as function(i as integer, b as boolean): integer\n" +
        "declare local x as square; y as square;\n" +
        "do\n" +
        "  skip\n" +
        "done";

    B314Lexer lexer = new B314Lexer(CharStreams.fromString(source));
    B314Parser parser = new B314Parser(new CommonTokenStream(lexer));
    ParseTree fctDeclTree = parser.fctDecl();
    Object result = new DemoVisitor().visit(fctDeclTree);
    System.out.printf("source:\n\n%s\n\nresult:\n\n%s\n", source, result);
  }
}

以下内容将打印在您的控制台上:

source:

mu as function(i as integer, b as boolean): integer
declare local x as square; y as square;
do
  skip
done

result:

{id=mu, fctParams=[{i=integer}, {b=boolean}], type=integer, localDecl=TODO, doStat=TODO}