programing

ANTLR을 사용하여 구축된 AST를 출력하는 방법은?

bestprogram 2023. 10. 19. 22:40

ANTLR을 사용하여 구축된 AST를 출력하는 방법은?

저는 C의 정적 분석기를 만들고 있습니다.저는 자바 코드를 생성하는 ANTLR을 이용하여 렉서와 파서를 해왔습니다.

ANTLR에서 자동으로 AST를 구축합니까?options {output=AST;}? 아니면 제가 직접 나무를 만들어야 합니까?그렇다면 AST에서 노드를 어떻게 뱉을 수 있습니까?

저는 현재 그 AST의 노드가 SSA를 만드는 데 사용될 것이고, 정적 분석기를 만들기 위해 데이터 플로우 분석을 할 것으로 생각하고 있습니다.제가 가는 길이 맞나요?

라파엘은 이렇게 썼습니다.

antlr에서 옵션 {output=에 의해 자동으로 AST를 구축합니까?AST;}? 아니면 내가 직접 트리를 만들어야 합니까?그렇다면 AST에서 노드를 어떻게 뱉을 수 있습니까?

아니요, 파서는 각 파서 규칙에 대해 루트 및 리프로 원하는 것을 알지 못하므로 단순히 입력하는 것 이상의 작업을 수행해야 합니다.options { output=AST; }너의 문법으로

예를 들어, 소스를 구문 분석할 때"true && (false || true && (true || false))"문법에서 생성된 파서를 사용합니다.

grammar ASTDemo;

options { 
  output=AST; 
}

parse
  :  orExp
  ;

orExp
  :  andExp ('||' andExp)*
  ;

andExp
  :  atom ('&&' atom)*
  ;

atom
  :  'true'
  |  'false'
  |  '(' orExp ')'
  ;

// ignore white space characters
Space
  :  (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;}
  ;

다음 구문 분석 트리가 생성됩니다.

enter image description here

(즉, 평평한 1차원 토큰 목록)

문법에서 어떤 토큰이 루트가 되는지, 잎이 되는지, 또는 단순히 트리에서 제외되는지를 ANTLR에 알려주기를 원할 것입니다.

AST를 만드는 방법은 두 가지가 있습니다.

  1. 다음과 같은 재작성 규칙을 사용합니다.foo : A B C D -> ^(D A B);,어디에foo는 토큰과 일치하는 파서 규칙입니다.A B C D. 그래서 그 이후의 모든 것들은->실제 재작성 규칙입니다.보시다시피 토큰은C재작성 규칙에는 사용되지 않으므로 AST에서 생략됩니다.다음에 바로 배치된 토큰입니다.^(나무의 뿌리가 될 것입니다.
  2. 나무를 이용합니다.^그리고.! 당신의 파서 규칙 안에 토큰이 있는 후에^토큰을 뿌리로 만들 것이고,!트리에서 토큰을 삭제합니다.에 해당하는 것.foo : A B C D -> ^(D A B);되지요foo : A B C! D^;

둘다요.foo : A B C D -> ^(D A B);그리고.foo : A B C! D^;다음 AST를 생성합니다.

enter image description here

이제 문법을 다음과 같이 다시 쓸 수 있습니다.

grammar ASTDemo;

options { 
  output=AST; 
}

parse
  :  orExp
  ;

orExp
  :  andExp ('||'^ andExp)* // Make `||` root
  ;

andExp
  :  atom ('&&'^ atom)* // Make `&&` root
  ;

atom
  :  'true'
  |  'false'
  |  '(' orExp ')' -> orExp // Just a single token, no need to do `^(...)`, 
                            // we're removing the parenthesis. Note that
                            // `'('! orExp ')'!` will do exactly the same.
  ;

// ignore white space characters
Space
  :  (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;}
  ;

소스로부터 다음과 같은 AST를 생성할 것입니다."true && (false || true && (true || false))":

enter image description here

관련 ANTLR 위키 링크:

라파엘은 이렇게 썼습니다.

저는 현재 그 AST의 노드가 SSA를 만드는 데 사용될 것이고, 정적 분석기를 만들기 위해 데이터 플로우 분석을 할 것으로 생각하고 있습니다.제가 가는 길이 맞나요?

그런거 한적은 없지만, IMO 당신이 가장 먼저 원하는것은 출처의 AST니까, 네, 당신이 옳은 길을 가고 있다고 생각해요! :)

편집

생성된 렉서와 파서를 사용하는 방법은 다음과 같습니다.

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 src = "true && (false || true && (true || false))";
    ASTDemoLexer lexer = new ASTDemoLexer(new ANTLRStringStream(src));
    ASTDemoParser parser = new ASTDemoParser(new CommonTokenStream(lexer));
    CommonTree tree = (CommonTree)parser.parse().getTree();
    DOTTreeGenerator gen = new DOTTreeGenerator();
    StringTemplate st = gen.toDOT(tree);
    System.out.println(st);
  }
}

언급URL : https://stackoverflow.com/questions/4931346/how-to-output-the-ast-built-using-antlr