Kod Analizine Giriş (101)

   Üniversitelerde defakto olmuş bir ders kodudur 101; ilgili bölümün ilk/giriş dersi kodudur. Mühendislik okuduğum zamanları hatırlarım bu sayıyı duyunca; Introduction to Computer Science (Bilgisayar Bilimine Giriş) 101… Roslyn makale serisinde tam gaz yol alırken sıra artık yavaş yavaş kod analizine geliyor. Bu makalemde birlikte kod analizine adımımızı atalım istedim. Bu yüzden sanırım makaleme verilecek başlıkta olmazsa olmazdı 101…

   Lafı daha fazla uzatmadan isterseniz konumuza geri dönelim; kod analizinde ilk hedefimiz verilen kodu söz dizim ağacına ulaşmak olmalı.

Roslyn derleyici API'si ve Derleyici Boru Hattı

   Roslyn’den bahsederken yukarıdaki grafiği sık sık kullanacağım. Derleyicinin iç yapısının açıldığı Roslyn’de modern derleyici boru hattı çıktılarına ulaşabilmek için bizlere derleyici API’si sunulmaktadır.Girdi olarak verilen kod bu boru hattından derleyici tarafından analiz edilmekte ve bir önceki işlemin çıktısı bir sonrakine girdi olarak kullanılmakta. Bizlerin de bir kodu analiz ederken ya da assembly’e dönüştürürken takip etmesi gereken bu yolun ilk adımı ise verilen kod/projenin söz dizim ağacının oluşturulmasıdır.

   Söz dizim API’si bizlere derleyicilerin bakış açısından bir C# ve Visual Basic uygulamasının nasıl göründüğünü anlayabilmemiz adına ilgili kodu söz dizim ağacını sunmaktadır. Sunulan bu söz dizim ağacı tam anlamıyla girdi olarak verilen kodu yansıtmaktadır. Öyle ki; kod içerisinde yer alan açıklama ve hatta boşlukları dahi bizlere bildirecektir.

   Söz dizim ağacı derleyici tarafında kodun incelenmesi sonrasında bir defa üretilmektedir, dolayısıyla da daha sonradan değiştirilemezler. Bu özellikleri biz yazılım geliştiricilere söz dizim ağaçlarını birden çok iş parçacığıyla inceleyerek uygulamamızı hızlandırabilme fırsatı verecektir.

   Roslyn CTP ile sunulan Söz Dizim API’si  yakından inceleyecek olursak bizlere dört temel bileşen sunduğunu görebiliriz; SyntaxTree, SyntaxNode, SyntaxToken ve SyntaxTrivia.  SyntaxTree bütün bir söz dizim ağacını temsil ederken, SyntaxNode bu söz dizim ağacında yer alan tanımlamalar, ifadeler ve cümlecikler gibi sözdizimsel yapıları temsil etmektedir. SyntaxNode’lar Derleyici API’si tarafından kodun her bir parçasını temsil edecek şekilde ve ağaç hiyerarşisinde oluşturulmaktadırlar. Kod içerisindeki anahtar kelime, operatör ya da tanımlayıcılar gibi bileşenler ise SyntaxToken’larca temsil edilmektedir. Tüm bunların dışında kalan boşluklar, açıklamalar v.b. diğer alanlar ise SyntaxTrivia’larca temsil edilmektedir. Derleyici API’si kod içerisinde yer alan using direktifleri, sınıf/namespace/metod v.b. tanımlamaları, parametre/blok ifadelerini ve daha pek çok yapıyı bizlere yukarıda saydığım bileşenlerin özelleştirilmiş halleriyle (kalıtılmış yapılarla) sunacaktır.

   Bir kodun söz dizim ağacı üzerinde işlem yapabilmek için tabi ki öncelikle işlem yapılacak koda ait söz dizim ağacını elde etmeliyiz. Bunun için ise yapılması gereken işlem yapılacak olan kodu Roslyn.Compilers.CSharp altında yer alan SyntaxTree sınıfına ait ParseCompilationUnit fonksiyonuna parametre olarak geçmektir. Bu fonksiyon verilen kodu işleyerek bize SyntaxTree türünden bir çıktı sunacaktır. SyntaxTree.ParseCompilationUnit fonksiyonunun kullanımını gösterebilmek adına, Çalışma-Zamanında Kod Derlemeye Var Mısınız? makalemde sizlerle paylaştığım klasik merhaba dünya kodumuzun söz dizim ağacını inceleyelim;

using System;
using Roslyn.Compilers.CSharp;

namespace Com.Enterprisecoding.RoslynOrnegi {
    public class Program {
        static void Main(string[] args)         {
            var sozDizimAgaci = SyntaxTree.ParseCompilationUnit(
 @"using System;

namespace Com.Enterprisecoding.RoslynOrnegi {
    public class MerhabaDunya { 
        public static void Mesaj() { 
            Console.WriteLine(""Enterprisecoding'den Roslyn'e Merhaba""); 
        } 
    }
}");

            DugumuYaz(sozDizimAgaci.Root, 0);
        }

        private static void DugumuYaz(SyntaxNode dugum, int seviye) {
            Console.WriteLine("".PadLeft(seviye) + dugum.Kind);

            foreach (var altDugum in dugum.ChildNodes()) {
                DugumuYaz(altDugum, seviye + 1);
            }
        }
    }    
}

Örneğimizi çalıştırdığımızda verdiğimiz kod içerisindeki tüm SyntaxNode 'lar dolaşılarak ekrana yazdırılacaktır

   Uygulamamızın çıktısının güzel görünmesi adına işlediğimiz düğümün derinlik bilgisine göre çıktıda boşluk bırakarak ağaç hiyerarşisinde bir görüntü elde etmiş olduk. Örneğimizi basit tutmak adına gördüğünüz gibi sadece verdiğimiz kod içerisindeki SyntaxNode’ları dolaşarak ekrana bastırdık, istersek aynı işlemi diğer bileşenler içinde uygulamamız tabi ki mümkün.

   Aşağıda, uygulamamızı bir adım ileri götürerek ekrana temel bileşenlere dair bilgiler verdiğimiz haliyle güncellenmiş kodumuzu bulabilirsiniz;

using System;
using Roslyn.Compilers.CSharp;

namespace Com.Enterprisecoding.RoslynOrnegi {
    public class Program {
        static void Main(string[] args)         {
            var sozDizimAgaci = SyntaxTree.ParseCompilationUnit(
 @"using System;

namespace Com.Enterprisecoding.RoslynOrnegi {
    public class MerhabaDunya { 
        public static void Mesaj() { 
            Console.WriteLine(""Enterprisecoding'den Roslyn'e Merhaba""); 
        } 
    }
}");

            DugumuYaz(sozDizimAgaci.Root, 0);

            Console.ReadKey();
        }

        private static void DugumuYaz(SyntaxNode dugum, int seviye) {
            var varsayilanArkaplan = Console.ForegroundColor;

            switch (dugum.Kind) {
                case SyntaxKind.NamespaceDeclaration:
                    Console.Write("".PadLeft(seviye) + dugum.Kind + " => ");
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    
                    Console.WriteLine(((NamespaceDeclarationSyntax)dugum).Name.PlainName);
                    break;
                case SyntaxKind.ClassDeclaration:
                    Console.Write("".PadLeft(seviye) + dugum.Kind + " => ");
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    
                    Console.WriteLine( ((ClassDeclarationSyntax)dugum).Identifier.Value);
                    break;
                case SyntaxKind.MethodDeclaration:
                    Console.Write("".PadLeft(seviye) + dugum.Kind + " => ");
                    Console.ForegroundColor = ConsoleColor.Yellow;

                    Console.WriteLine(((MethodDeclarationSyntax)dugum).Identifier.Value);
                    break;
                case SyntaxKind.StringLiteralExpression:
                    Console.Write("".PadLeft(seviye) + dugum.Kind + " => ");
                    Console.ForegroundColor = ConsoleColor.Yellow;

                    Console.WriteLine( ((LiteralExpressionSyntax)dugum).Token.ValueText); 
                    break;
                case SyntaxKind.UsingDirective:
                    Console.Write("".PadLeft(seviye) + dugum.Kind + " => ");
                    Console.ForegroundColor = ConsoleColor.Yellow;

                    Console.WriteLine(((UsingDirectiveSyntax)dugum).Name.PlainName); 
                    break;
                default:
                    Console.WriteLine("".PadLeft(seviye) + dugum.Kind);
                    break;
            }

            Console.ForegroundColor = varsayilanArkaplan;

            foreach (var altDugum in dugum.ChildNodes()) {
                DugumuYaz(altDugum, seviye + 1);
            }
        }
    }    
}

 

istersen kodumuzun temel bileşenlerine ait bilgileri gösterebilmemiz mümkün   Söz dizim ağacı ile yapılabileceklerimizi tek bir makaleye sığdırmak yerine konuyu belli başlılar altındaki bir kaç makaleye yaymayı daha uygun gördüğümden bu makalemde daha fazla detaya girmiyorum. Devam makalelerimde eminim ki daha çok hoşlanacağınız örnekler bulacaksınız.

Fatih Boy

Ankara'da yaşayan Fatih, bir kamu kurumunda danışman olarak çalışmaktadır. ALM süreçleri, kurumsal veri yolu sistemleri, kurumsal altyapı ve yazılım geliştirme konularında destek vermektedir. Boş zamanlarında açık kaynak kodlu projeler geliştirmeyi ve bilgisini yazdığı makalelerle paylaşmayı seven Fatih, aynı zamanda Visual C# ve Visual Studio teknolojileri konusundan Microsoft tarafından altı yıl üst üste MVP (En Değerli Profesyonel) ödülüne layık görülmüştür. İş hayatı boyunca masaüstü uygulamaları, web teknolojileri, akıllı istemciler gibi konularda Asp.Net, Php, C#, Java programlama dilleri ve MySql, MsSql ve Oracle gibi veritabanı yönetim yazılımları ile çalışmıştır. İngilizce ve Türkçe olarak yayınlanan makalelerini gerek İngilizce bloğunda, gerekse de Türkçe bloğunda bulabileceğiniz gibi web sitesinden de açık kaynak kodlu geliştirdiği yazılımlarına ulaşabilirsiniz. vCard - Twitter - Facebook - Google+

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir