Bir necha yil davomida men o'z dasturlash tilimni ishlab chiqishda o'z kuchimni sinab ko'rdim. Men, mening fikrimcha, mumkin bo'lgan eng sodda, to'liq funktsional va qulay tilni yaratmoqchi edim.
Ushbu maqolada men o'z ishimning asosiy bosqichlarini ta'kidlamoqchiman va avvalo, men hozir ishlayotgan tilning yaratilgan kontseptsiyasi va uning birinchi amalga oshirilishini tasvirlab bermoqchiman.
Oldindan aytamanki, men butun loyihani Free Paskalda yozganman, chunki... undagi dasturlar juda ko'p platformalar uchun yig'ilishi mumkin va kompilyatorning o'zi juda optimallashtirilgan ikkilik fayllarni ishlab chiqaradi (men loyihaning barcha komponentlarini O2 bayrog'i bilan to'playman).
Tilning ishlash vaqti
Avvalo, mening tilimdagi kelajakdagi ilovalarni ishga tushirish uchun yozishim kerak bo'lgan virtual mashina haqida gapirishga arziydi. Men stek arxitekturasini amalga oshirishga qaror qildim, ehtimol bu eng oson yo'li edi. Men buni rus tilida qanday qilish kerakligi haqida oddiy maqola topmadim, shuning uchun ingliz tilidagi material bilan tanishib chiqqanimdan so'ng, men o'z velosipedimni loyihalash va yozishga o'tirdim. Keyinchalik men bu boradagi "ilg'or" g'oyalarim va ishlanmalarimni taqdim etaman.
Stackni amalga oshirish
Shubhasiz, VM ning yuqori qismida stek joylashgan. Mening amaliyotimda u bloklarda ishlaydi. Aslini olganda, bu oddiy ko'rsatkichlar qatori va stekning yuqori qismidagi indeksni saqlash uchun o'zgaruvchidir.
U ishga tushirilganda 256 ta elementdan iborat massiv yaratiladi. Agar stekga ko'proq ko'rsatkichlar surilsa, uning o'lchami keyingi 256 ta elementga ortadi. Shunga ko'ra, elementlarni stekdan olib tashlashda uning o'lchami o'rnatiladi.
VM bir nechta steklardan foydalanadi:
- Asosiy to'plam.
- Qaytish nuqtalarini saqlash uchun stek.
- Axlat yig'uvchilar to'plami.
- Ishlovchilar to'plamini sinab ko'ring/tutib oling/nihoyat blokirovka qiling.
Konstantalar va o'zgaruvchilar
Bu oddiy. Konstantalar alohida kichik kod bo'lagida ishlanadi va kelajakdagi ilovalarda statik manzillar orqali foydalanish mumkin. O'zgaruvchilar ma'lum o'lchamdagi ko'rsatkichlar massivi bo'lib, uning hujayralariga kirish indeks orqali amalga oshiriladi - ya'ni. statik manzil. O'zgaruvchilar stekning yuqori qismiga surilishi yoki u erdan o'qilishi mumkin. Aslida, chunki Bizning o'zgaruvchilarimiz ko'rsatkichlarni VM xotirasida qiymatlarga asosan saqlasa-da, tilda yashirin ko'rsatkichlar bilan ishlash ustunlik qiladi.
Axlat yig'uvchi
Mening VMimda u yarim avtomatik. Bular. chiqindi yig'uvchiga qachon qo'ng'iroq qilishni ishlab chiquvchining o'zi hal qiladi. Python, Perl, Ruby, Lua va boshqalarda bo'lgani kabi oddiy ko'rsatkich hisoblagichi yordamida ishlamaydi. U marker tizimi orqali amalga oshiriladi. Bular. o'zgaruvchiga vaqtinchalik qiymat berish mo'ljallangan bo'lsa, axlat yig'uvchining stekiga ushbu qiymatga ko'rsatgich qo'shiladi. Kelajakda kollektor allaqachon tayyorlangan ko'rsatkichlar ro'yxatidan tezda ishlaydi.
try/catch/nihoyat bloklari bilan ishlash
Har qanday zamonaviy tilda bo'lgani kabi, istisnolardan foydalanish muhim komponent hisoblanadi. VM yadrosi try..catch blokiga o‘ralgan bo‘lib, u istisno holatini qo‘lga kiritgandan so‘ng, u haqidagi ba’zi ma’lumotlarni stekga surish orqali kod bajarilishiga qaytishi mumkin. Ilova kodida siz try/catch/nihoyat kod bloklarini belgilashingiz mumkin, bunda catch (istisno ishlov beruvchisi) va nihoyat/end (blokning oxiri) da kirish nuqtalarini belgilashingiz mumkin.
Ko'p tarmoqli
U VM darajasida qo'llab-quvvatlanadi. Bu oddiy va foydalanish uchun qulay. U uzilish tizimisiz ishlaydi, shuning uchun kod mos ravishda bir necha marta tezroq bajarilishi kerak.
VMlar uchun tashqi kutubxonalar
Busiz qilishning iloji yo'q. VM boshqa tillarda qanday amalga oshirilganiga o'xshash importni qo'llab-quvvatlaydi. Siz Mash-da kodning bir qismini va kodning bir qismini ona tillarida yozishingiz, keyin ularni biriga bog'lashingiz mumkin.
VMlar uchun yuqori darajadagi Mash tilidan bayt-kodga tarjimon
O'rta til
Tarjimonni murakkab tildan VM kodiga tezda yozish uchun men birinchi navbatda oraliq tilni ishlab chiqdim. Natijada assemblerga o'xshash dahshatli tomosha paydo bo'ldi, bu erda alohida ahamiyatga ega emas. Faqat shuni aytmoqchimanki, bu darajada tarjimon ko'pchilik konstantalar va o'zgaruvchilarni qayta ishlaydi, ularning statik manzillari va kirish nuqtalarining manzillarini hisoblaydi.
Tarjimon arxitekturasi
Amalga oshirish uchun eng yaxshi arxitekturani tanlamadim. Tarjimon boshqa tarjimonlar singari kodlar daraxtini qurmaydi. U strukturaning boshiga qaraydi. Bular. agar tahlil qilinayotgan kod qismi “while :” ga o‘xshab ko‘rinsa, bu while tsikli konstruksiyasi ekanligi va uni while tsikli konstruksiyasi sifatida qayta ishlash kerakligi aniq. Murakkab kommutatorga o'xshash narsa.
Ushbu me'moriy yechim tufayli tarjimon unchalik tez emas edi. Biroq, uni o'zgartirish qulayligi sezilarli darajada oshdi. Men kerakli tuzilmalarni qahvam sovib ketishidan tezroq qo'shdim. To'liq OOP yordami bir haftadan kamroq vaqt ichida amalga oshirildi.
Kodni optimallashtirish
Bu erda, albatta, uni yaxshiroq amalga oshirish mumkin edi (va amalga oshiriladi, lekin keyinroq, unga yaqinlashish bilanoq). Hozircha optimallashtiruvchi faqat foydalanilmagan kodni, konstantalarni va yig'ilishdan importni qanday qilib kesishni biladi. Shuningdek, bir xil qiymatga ega bo'lgan bir nechta konstantalar bittaga almashtiriladi. Ana xolos.
Til Mash
Til haqida asosiy tushuncha
Asosiy g'oya iloji boricha funktsional va sodda tilni ishlab chiqish edi. O'ylaymanki, rivojlanish o'z vazifasini portlash bilan engadi.
Kod bloklari, protseduralari va funktsiyalari
Tildagi barcha konstruktsiyalar ikki nuqta bilan ochiladi. : va operator tomonidan yopiladi oxiri.
Protseduralar va funksiyalar mos ravishda proc va func deb e'lon qilinadi. Argumentlar qavs ichida keltirilgan. Hammasi boshqa tillar kabi.
Operator Qaytish funksiyadan, operatordan qiymat qaytarishingiz mumkin tanaffus protsedura/funksiyadan chiqish imkonini beradi (agar u looplardan tashqarida bo'lsa).
Kod namunasi:
...
func summ(a, b):
return a + b
end
proc main():
println(summ(inputln(), inputln()))
end
Qo'llab-quvvatlanadigan dizaynlar
- Davrlar: for..end, while..end, to.. end
- Shartlar: agar..[else..]end, switch..[case..end..][else..]end
- Usullari: proc ():... end, func ():... end
- Yorliq va o'tish: :, o'tish
- Sanoqlar va doimiy massivlarni sanash.
O'zgaruvchilar
Tarjimon ularni avtomatik ravishda aniqlashi mumkin yoki ishlab chiquvchi ularni belgilashdan oldin var yozsa.
Kod misollari:
a ?= 10
b ?= a + 20
var a = 10, b = a + 20
Global va mahalliy o'zgaruvchilar qo'llab-quvvatlanadi.
OOP
Xo'sh, biz eng mazali mavzuga keldik. Mash barcha ob'ektga yo'naltirilgan dasturlash paradigmalarini qo'llab-quvvatlaydi. Bular. sinflar, meros, polimorfizm (shu jumladan dinamik), dinamik avtomatik aks ettirish va introspektsiya (to'liq).
Ko'proq vaqt o'tkazmasdan, shunchaki kod misollarini keltirgan ma'qul.
Oddiy sinf va u bilan ishlash:
uses <bf>
uses <crt>
class MyClass:
var a, b
proc Create, Free
func Summ
end
proc MyClass::Create(a, b):
$a = new(a)
$b = new(b)
end
proc MyClass::Free():
Free($a, $b)
$rem()
end
func MyClass::Summ():
return $a + $b
end
proc main():
x ?= new MyClass(10, 20)
println(x->Summ())
x->Free()
end
Chiqarish: 30.
Meros va polimorfizm:
uses <bf>
uses <crt>
class MyClass:
var a, b
proc Create, Free
func Summ
end
proc MyClass::Create(a, b):
$a = new(a)
$b = new(b)
end
proc MyClass::Free():
Free($a, $b)
$rem()
end
func MyClass::Summ():
return $a + $b
end
class MyNewClass(MyClass):
func Summ
end
func MyNewClass::Summ():
return ($a + $b) * 2
end
proc main():
x ?= new MyNewClass(10, 20)
println(x->Summ())
x->Free()
end
Chiqarish: 60.
Dinamik polimorfizm haqida nima deyish mumkin? Ha, bu aks ettirish!:
uses <bf>
uses <crt>
class MyClass:
var a, b
proc Create, Free
func Summ
end
proc MyClass::Create(a, b):
$a = new(a)
$b = new(b)
end
proc MyClass::Free():
Free($a, $b)
$rem()
end
func MyClass::Summ():
return $a + $b
end
class MyNewClass(MyClass):
func Summ
end
func MyNewClass::Summ():
return ($a + $b) * 2
end
proc main():
x ?= new MyClass(10, 20)
x->Summ ?= MyNewClass::Summ
println(x->Summ())
x->Free()
end
Chiqarish: 60.
Keling, oddiy qadriyatlar va sinflar bilan tanishish uchun bir oz vaqt ajratamiz:
uses <bf>
uses <crt>
class MyClass:
var a, b
end
proc main():
x ?= new MyClass
println(BoolToStr(x->type == MyClass))
x->rem()
println(BoolToStr(typeof(3.14) == typeReal))
end
Chiqarish: rost, rost.
Tayinlash operatorlari va aniq ko'rsatkichlar haqida
?= operatori o'zgaruvchiga xotiradagi qiymatga ko'rsatgichni belgilash uchun ishlatiladi.
= operatori o'zgaruvchidan ko'rsatgich yordamida xotiradagi qiymatni o'zgartiradi.
Va endi aniq ko'rsatkichlar haqida bir oz. Men ularni tilga qo'shdim, shunda ular mavjud.
@ — oʻzgaruvchiga aniq koʻrsatgichni olish.
? — ko‘rsatkich bo‘yicha o‘zgaruvchini olish.
@= — oʻzgaruvchiga aniq koʻrsatgich yordamida qiymat berish.
Kod namunasi:
uses <bf>
uses <crt>
proc main():
var a = 10, b
b ?= @a
PrintLn(b)
b ?= ?b
PrintLn(b)
b++
PrintLn(a)
InputLn()
end
Chiqarish: ba'zi raqamlar, 10, 11.
Sinab ko'ring..[tutib oling..][nihoyat..]end
Kod namunasi:
uses <bf>
uses <crt>
proc main():
println("Start")
try:
println("Trying to do something...")
a ?= 10 / 0
catch:
println(getError())
finally:
println("Finally")
end
println("End")
inputln()
end
Kelajak uchun rejalar
Men GraalVM & Truffle-ga qarashda davom etaman. Mening ish vaqti muhitimda JIT kompilyatori yo'q, shuning uchun unumdorlik nuqtai nazaridan u hozirda faqat Python bilan raqobatlasha oladi. Umid qilamanki, men GraalVM yoki LLVM asosida JIT kompilyatsiyasini amalga oshira olaman.
ombori
Siz ishlanmalar bilan o'ynashingiz va loyihani o'zingiz kuzatib borishingiz mumkin.
Oxirigacha o'qigan bo'lsangiz rahmat.
Manba: www.habr.com