성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Get Started with Milvus Vector DB i...
[정성태] cyberark/PipeViewer - A tool that...
[정성태] WinForms in a 64-Bit world – our st...
[정성태] 예제에서 SELECT_SQL도 내부적으로는 SqlCommand/...
[victor] SELECT_LINQ SELECT_SQL 같은 쿼리인...
[victor] 답변 갑사합니다. 예외(Exception)가 났습니다. ...
[정성태] 일단, 위의 방식대로 하면 예외(Exception) 없이 잘 동...
[정성태] Windows 10 (버전 1809)에 이런 기능이 ^^ 추가되...
[정성태] pde windbg extension ; https://lea...
[정성태] // GetEnumerator extensions for Ran...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>Roslyn 맛보기 - Syntax Analysis (Roslyn Syntax API)</h1> <p> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Roslyn 맛보기 (1) - <a target='tab' href='http://www.sysnet.pe.kr/2/0/1153'>C# 소스 코드를 스크립트 처럼 다루는 방법</a> Roslyn 맛보기 (2) - <a target='tab' href='http://www.sysnet.pe.kr/2/0/1154'>C# Interactive (1)</a> Roslyn 맛보기 (3) - <a target='tab' href='http://www.sysnet.pe.kr/2/0/1155'>C# Interactive (2)</a> Roslyn 맛보기 (4) - <a target='tab' href='http://www.sysnet.pe.kr/2/0/1156'>Roslyn Services APIs를 이용한 Code Issue 및 Code Action 기능 소개</a> Roslyn 맛보기 (5) - Syntax Analysis (Roslyn Syntax API) Roslyn 맛보기 (6) - <a target='tab' href='http://www.sysnet.pe.kr/2/0/1158'>Roslyn Symbol / Binding API</a> Roslyn 맛보기 (7) - <a target='tab' href='http://www.sysnet.pe.kr/2/0/1159'>SyntaxTree 조작</a> </pre> <br /> 지난 글에서 Roslyn을 이용한 C# 스크립트 엔진을 다뤘는데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Roslyn 맛보기 - C# 소스 코드를 스크립트 처럼 다루는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/1153'>http://www.sysnet.pe.kr/2/0/1153</a> </pre> <br /> 이번에는 "%PROGRAMFILES% (x86)\Microsoft Codename Roslyn CTP\Documentation\Getting Started - Syntax Analysis (CSharp).docx" 문서에서 설명하고 있는 "Syntax API"를 소개해 보겠습니다.<br /> <br /> Rosyln에서 제공되는 Syntax API는 곧, C# 언어에 대한 Parser를 제공하는 것과 같다고 보면 되겠습니다. 코드 먼저 보고, 설명을 해볼까요?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; using System.Collections.Generic; using System.Linq; using System.Text; using Roslyn.Compilers; using Roslyn.Compilers.CSharp; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { <span style='color: blue; font-weight: bold'>SyntaxTree tree</span> = SyntaxTree.ParseCompilationUnit( @"using System; using System.Collections.Generic; using System.Linq; namespace HelloWorld { class Program { static void Main(string[] args) { Console.WriteLine(""Hello, World!""); } } }"); <span style='color: blue; font-weight: bold'>var root = (CompilationUnitSyntax)tree.Root;</span> } } } </pre> <br /> 사용법이 생각보다 간단하지요? ^^ 보시는 바와 같이 "하나의 코드 파일"에 대해서 그에 매칭되는 "하나의 SyntaxTree"를 얻어내고 있습니다. (SyntaxTree는 Immutable입니다.)<br /> <br /> 자, 그럼 말 그대로 SyntaxTree이니, 하위 구조가 Tree 유형으로 발전할텐데 이 트리에 속하는 구성요소를 보면 다음과 같이 크게 4가지로 나뉠 수 있습니다.<br /> <br /> <div style='BACKGROUND-COLOR: #ccffcc; padding: 10px 10px 5px 10px; MARGIN: 0px 10px 10px 10px; FONT-FAMILY: Malgun Gothic, Consolas, Verdana; COLOR: #005555'> <span style='color: blue; font-weight: bold'>SyntaxTree</span> 클래스: 완전한 하나의 parse tree를 이루는 인스턴스<br /> <span style='color: blue; font-weight: bold'>SyntaxNode</span> 클래스: 구문 구조(Syntax construct)에 해당하는 요소들. 가령 declarations, statements, clauses, expressions.<br /> <span style='color: blue; font-weight: bold'>SyntaxToken</span> 구조체: 개별적인 keyword, identifier, operator, punctuation 요소들<br /> <span style='color: blue; font-weight: bold'>SyntaxTrivia</span> 구조체: 실질적인 C# 소스 코드에 크게 영향이 없는 요소들. 가령 whitespace between tokens, preprocessor directives, comments.<br /> </div><br /> <br /> 위와 같은 정보와 함께, 문서에 있는 예제 트리 구조를 보면 대강의 이해가 되실 것입니다. ^^<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='syntax_tree_1.png' src='/SysWebRes/bbs/syntax_tree_1.png' /><br /> <br /> 다시 소스 코드로 돌아가서,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > var root = (CompilationUnitSyntax)tree.Root; </pre> <br /> 이렇게 구해진 CompilationUnitSyntax 타입의 root 인스턴스는 다음과 같은 4개의 컬렉션 속성값을 가지고 있습니다.<br /> <br /> <div style='BACKGROUND-COLOR: #ccffcc; padding: 10px 10px 5px 10px; MARGIN: 0px 10px 10px 10px; FONT-FAMILY: Malgun Gothic, Consolas, Verdana; COLOR: #005555'> <span style='color: blue; font-weight: bold'>Attributes</span>: [assembly] 특성이 정의된 목록<br /> <span style='color: blue; font-weight: bold'>Externs</span>: "<a target='tab' href='https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/extern-alias'>extern alias</a>" 키워드로 정의된 목록<br /> <span style='color: blue; font-weight: bold'>Members</span>: namespace, class, interface, struct, ... 등의 요소들<br /> <span style='color: blue; font-weight: bold'>Usings</span>: "using System"과 같은 <a target='tab' href='https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/using-directive'>using 지시문</a>이 사용된 목록<br /> </div><br /> <br /> 따라서, 위와 같은 소스 코드의 경우 "firstMember = root.Members[0]"은 첫 번째로 정의된 클래스를 나타내며 이에 대한 정보를 MemberDeclarationSyntax 타입을 상속받은 ClassDeclarationSyntax 타입으로 구현하고 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > firstMember.Kind == SyntaxKind.ClassDeclaration firstMember.GetType().FullName == Roslyn.Compilers.CSharp.ClassDeclarationSyntax </pre> <br /> 문서에 의하면, 이렇게 ClassDeclarationSyntax까지 구한 다음 여전히 하위 노드 목록을 구하기 위해 Members 속성으로 접근하도록 되어 있는데 현재 공개된 CTP에서는 더 이상 Members 속성은 제공되지 않고, 대신 ChildNodes() 메서드를 통해서 하위에 접근할 수 있게 해주고 있습니다. (아마도, 정식 버전이 나오기까지 이런 부분들은 계속해서 변할지도 모릅니다.)<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > foreach (var item in firstMember.ChildNodes()) { Console.WriteLine(item.Kind); } </pre> <br /> 예제 소스 코드의 경우, 당연히 ClassDeclarationSyntax의 첫번째로 열람되는 ChildNode는 Main 메서드에 해당하는 "MethodDeclarationSyntax" 타입을 가리킵니다.<br /> <br /> 대충 감이 잡히시죠? ^^<br /> <br /> 어찌 보면, Reflection 기능과 별반 차이가 없어보이는데요. 중요한 차이점을 하나 정리해 드리자면, Syntax API는 "소스 코드"와 정확히 매핑되어 연동된다는 겁니다. 일례로, "Getting Started - Syntax Analysis (CSharp).docx" 문서에서는 주어진 C# 코드에서 사용된 "using" 문 중에서 "System."으로 시작하지 않은 다른 참조들을 열람하는 기능을 구현한 예제를 소개하고 있습니다. Reflection으로는 그런 기능을 도저히 구현할 수가 없지요. ^^<br /> <br /> 결론적으로 "Roslyn"만 있다면, 필요한 경우 언제든 C# 소스 코드를 마음껏 분석할 수 있다는 것!<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
9129
(왼쪽의 숫자를 입력해야 합니다.)