C# AST Parser


Abstract Syntax Tree

한마디로 언어에 관계 없는 프로그래밍 언어의 형태를 나타내어 주는 간략한 트리라고 볼 수 있다.

위키


종류

-Cecil : C#의 IL코드를 분석하여 컴파일?하는 방식

-NRefactory : Cecil 오픈 라이브러리를 이용하여 AST 파서를 만들어 제공하는 것으로 요즘 내가 사용하고 있는 오픈소스 라이브러리임.


NRefactory

Github에서 소스파일이나 Library(Dll) 파일을 받을 수 있으며 사용하는 방법은 CodeProject의 예제에 나와있다. (NRefactory_Demo_and_IndexOf-Sample_-_Source)

Method 들의 호출관계(Call Hierarchy)를 구하고 싶어서 사용했으며 예시 코드는 다음과 같다.


이 프로젝트를 진행하면서 고생했던 것은

1. 오픈소스 라이브러리의 존재 유무

오픈소스 라이브러리가 있는 줄 몰랐기 때문에 처음에는 갖은 방법을 생각했었다.

처음 생각했던 것은 직접 Parser를 구현했지만 역시나 컴파일러 수준으로 작성하는 것은 효율적이지 못했고 어려웠다.

두번째로 생각했던 것은 정규표현식으로 함수모양으로 생긴 것들을 찾아내는 것이었으나 주석안에 있는 함수 등등 상당한 문제를 내포하고 있었다 (주석을 지우고 실행하는 것으로 해결)

마지막으로 찾은 것이 바로 AST Parser였다.

2. 오픈소스 라이브러리의 사용 방법

라이브러리마다 다른 사용법을 가지고 작성되었기 때문에 각각의 특성에 맞게 이용하는 것이 중요하다. 하지만 어떤 구성으로 되어있는지 처음에 사용하기도 어려웠기 때문에 Demo를 통해서 분석했다.

메소드는 어떤 타입으로 검사해야되는지(IMethod, MethodDeclaration) 등등 원하는 정보를 찾는 것도 어려웠다.

3. Find References

호출관계를 구하는 과정에서 시간이 오래걸렸다. 초기의 버전에서는 Method의 Call Hierarchy를 구할때마다 재귀적인 방식으로 FindReferences를 이용하여 구했는데 (해당 주소로 이동) 매번 호출하게 되니 거의 3분가량의 시간이 소모되었다. 개선하는 과정에서 Call Hierarchy를 Map으로 저장해두고 필요할때 타고 이동하는 방식을 사용해야겠다고 생각되었다.

4. Hash Collision

Method를 Hashtable에 넣어서 Call Hierarchy를 저장해두는 방식을 택하게 되었는데 어떤 문제인지 모르겠지만 계속 Hash값이 충돌되는 일이 발생되었다. 처음에는 GetHashCode에 문제가 있는 것 같아서 새로운 Hash값을 넣었지만 같은 충돌이 계속발생되었다. 같은 Method를 2번씩 넣기에 .cs이 중복되지 않았으며 Method는 계속 2번씩 호출되고 있었다. 그 이유는 interface를 피하고 class만을 구하는 방법이 잘못된 것이었다. 해결하기 위해 Method의 BodyRegion이 비어있는지 확인하는 것으로 해결했다.

5. Interface

Class의 method만을 가져오려고하는데 계속 Interface까지 가져오기에 함수가 두번씩 나오게 되었다. 이를 처리하기 위해서 Class를 먼저 구하고, 그 class 내부에서 method를 찾는 방식으로 진행했는데 partial class에서 method를 2번씩 가져오는 문제가 발생되었다.


여러가지 삽질끝에 NRefactory Parser를 잘 쓸 수 있게 됐다.

'프로그래밍 > C#' 카테고리의 다른 글

[Unity] Android Plugin  (0) 2015.09.29
[Error] ClickOnce error  (0) 2014.11.21
FTP with .NET (C#)  (0) 2014.10.21
by 개발자가 되자! 2015. 11. 3. 15:01