read

Sanal makine oluşturduğumuz ara dil çıktısını çalıştıracak olan modülümüzdür. Yapacağınız dile göre daha kompleks sanal makine yazmanız gerekebilir. Burada oluşturacağımız sanal makine stack adında nesnelerimizi tutacağımız bir dizi, o an işlediğimiz yani aktif olan nesneyi belirten current ve o anki komutumuzun adresini tutan IP (Instruction Pointer) değişkenlerinden oluşacaktır.

class VirtualMachine{
	void execute(IL ilcode){
		string tmp;//Geçici olarak kullanmak üzere bir string
		RObject[] stack;//Nesne dizimiz
		RObject current;//Aktif nesne
		RObject[string] variables;//Değişkenlerimiz
		auto IP = ilcode.codes.ptr;//instruction pointer. O anki il kodunun adresini tutar.
		start:

Yapacağınız dile göre sanal makineyi daha da geliştirebilirisiniz fakat şuanki hali bizim işimizi görecektir.

	static RObject[string] global;
	static this(){
		global = [
			"print": new RFunction("print", &builtin._print),
			"int": new RFunction("int", &builtin._int),
		];
	}

Builtin fonksiyonlarımız için de yukarıdaki kodları tanımlayalım.

//
		switch(*cast(il*) IP){/// Çalıştırılacak olan il komutuna git.
			/** Üzerinde işlem yapılacak olan aktif nesneyi değiştirir.  */
			case il.load: IP++;
				current = *cast(RObject*) IP;
				IP += (void*).sizeof;
				goto start;
			/** Aktif "variables" hashmap i üzerine değişken adına göre tanımla.  */
			case il.definevar: IP++;
				tmp = (cast(char*) IP).cstr2dstr();
				variables[tmp] = current;
				IP += tmp.length + 1;
				goto start;
			/** Değişkeni önce kullanıcı tarafından tanımlananlar arasında ara eğer yoksa
			 *  Global değişkenler arasında ara.
			 */
			case il.loadvar: IP++;
				tmp = (cast(char*) IP).cstr2dstr();
				if(auto var = tmp in variables)
					current = *var;
				else if(auto var = tmp in global){
					current = *var;
				}else throw new Exception("'%s' değişkeni tanımlanmadı!".format(tmp));
				IP += tmp.length + 1;
				goto start;
			/** Aktif nesneyi stack'a yaz */
			case il.push:
				stack ~= current;
				IP++;
				goto start;
			/** Aktif nesneyi fonksiyon parametresi olarak stack'a yaz
			 *  Şimdilik yaptığımız işlemler aynı olduğu için kodumuz stack push ile aynı
			 *  ama sistemi daha farklı bir şekilde kullanmak isteyebilirsiniz diye parser'dan
			 *  fonksiyon parametrelerini bu şekilde çıkarttık.
			 */
			case il.pushparam:
				stack ~= current;
				IP++;
				goto start;
			/** - operatörü
			 *  Stack e yüklenen nesneden aktif nesneyi çıkart ve stackdan nesneyi sil.
			 */
			case il.sub:
				current = stack[$-1] - current;
				stack = stack[0..$-1];
				IP++;
				goto start;
			/** + operatörü
			 *  Stack e yüklenen nesneyle aktif nesneyi topla ve stackdan nesneyi sil.
			 */
			case il.add:
				current = stack[$-1] + current;
				stack = stack[0..$-1];
				IP++;
				goto start;
			/** / operatörü
			 *  Stack e yüklenen nesneyi aktif nesneye böl ve stackdan nesneyi sil.
			 */
			case il.div:
				current = stack[$-1] / current;
				stack = stack[0..$-1];
				IP++;
				goto start;
			/** * operatörü
			 *  Stack e yüklenen nesneyle aktif nesneyi çarp ve stackdan nesneyi sil.
			 */
			case il.mul:
				current = stack[$-1] * current;
				stack = stack[0..$-1];
				IP++;
				goto start;
			/** call işlevi
			 *  Çağırılacak olan fonksiyonun parametrelerini stackdan çek onları bir diziye at ve stacki boşalt.
			 *  Not : Çağırılacak olan fonksiyonun parametre sayısı il çıktısı içerisinde geliyor.
			 */
			case il.call: IP++;
				current = current(stack[$-*cast(size_t*) IP..$]);
				stack = stack[0..$-*cast(size_t*) IP];
				IP += size_t.sizeof;
				goto start;
			/** Makineyi sonlandır. */
			case il.hlt: break;
			default:
				throw new Exception("Bilinmeyen operand code %s".format(*cast(il*) IP));
		}
	}
}

Evet sanal makinemiz tamamlandı geriye sadece birkaç tane build-in fonksiyonu tanımlamak kaldı. Projenin bitmiş halinin kaynak kodunu bir sonraki yazıda bulabilirsiniz.

Blog Logo

Talha Zekeriya Durmuş


Published

Image

Talha Zekeriya Durmuş

Bir bilgisayar sevdalısı, Ankara Üniversiteli ve genç bir hayalperest.

Geri Dön