VairÄkus gadus izmÄÄ£inÄju savus spÄkus savas programmÄÅ”anas valodas izstrÄdÄ. Es gribÄju izveidot, manuprÄt, pÄc iespÄjas vienkÄrÅ”Äku, pilnÄ«bÄ funkcionÄlÄku un ÄrtÄku valodu.
Å ajÄ rakstÄ vÄlos izcelt sava darba galvenos posmus un iesÄkumÄ aprakstÄ«t izveidoto valodas koncepciju un tÄs pirmo realizÄciju, pie kuras Å”obrÄ«d strÄdÄju.
Ä»aujiet man pateikt priekÅ”Ä, ka visu projektu rakstÄ«ju Free Pascal, jo... tajÄ esoÅ”Äs programmas var montÄt ļoti daudzÄm platformÄm, un pats kompilators rada ļoti optimizÄtus binÄros failus (es apkopoju visas projekta sastÄvdaļas ar O2 karogu).
Valodas izpildlaiks
PirmkÄrt, ir vÄrts runÄt par virtuÄlo maŔīnu, kas man bija jÄraksta, lai palaistu turpmÄkÄs lietojumprogrammas manÄ valodÄ. Es nolÄmu ieviest steka arhitektÅ«ru, iespÄjams, tÄpÄc, ka tas bija vienkÄrÅ”Äkais veids. Es neatradu nevienu normÄlu rakstu par to, kÄ to izdarÄ«t krievu valodÄ, tÄpÄc pÄc iepazÄ«Å”anÄs ar angļu valodas materiÄlu, es Ä·Äros pie sava velosipÄda projektÄÅ”anas un rakstÄ«Å”anas. TÄlÄk es iepazÄ«stinÄÅ”u ar savÄm "progresÄ«vÄm" idejÄm un attÄ«stÄ«bu Å”ajÄ jautÄjumÄ.
Stack ievieŔana
AcÄ«mredzot virtuÄlÄs maŔīnas augÅ”pusÄ ir steks. ManÄ realizÄcijÄ tas darbojas blokos. BÅ«tÄ«bÄ tas ir vienkÄrÅ”s rÄdÄ«tÄju masÄ«vs un mainÄ«gais, lai saglabÄtu kaudzes augÅ”daļas indeksu.
Kad tas ir inicializÄts, tiek izveidots 256 elementu masÄ«vs. Ja uz kaudze tiek uzspiests vairÄk rÄdÄ«tÄju, tÄ lielums palielinÄs par nÄkamajiem 256 elementiem. AttiecÄ«gi, noÅemot elementus no kaudzes, tiek pielÄgots tÄ izmÄrs.
VM izmanto vairÄkus stekus:
- GalvenÄ kaudze.
- Kaudze atgrieÅ”anÄs punktu glabÄÅ”anai.
- Atkritumu savÄcÄja kaudze.
- IzmÄÄ£iniet/tveriet/beidzot bloÄ·Äjiet apdarinÄtÄja steku.
Konstantes un mainīgie
Å is ir vienkÄrÅ”s. Konstantes tiek apstrÄdÄtas atseviÅ”Ä·Ä nelielÄ koda daÄ¼Ä un ir pieejamas turpmÄkajÄs lietojumprogrammÄs, izmantojot statiskas adreses. MainÄ«gie ir noteikta izmÄra rÄdÄ«tÄju masÄ«vs, piekļuvi tÄ Å”Å«nÄm veic indekss - t.i. statiskÄ adrese. MainÄ«gos var virzÄ«t uz steka augÅ”daļu vai nolasÄ«t no turienes. PatiesÄ«bÄ, jo Lai gan mÅ«su mainÄ«gie bÅ«tÄ«bÄ saglabÄ norÄdes uz vÄrtÄ«bÄm VM atmiÅÄ, valodÄ dominÄ darbs ar netieÅ”iem rÄdÄ«tÄjiem.
Atkritumu savÄcÄjs
ManÄ virtuÄlajÄ maŔīnÄ tas ir pusautomÄtisks. Tie. pats izstrÄdÄtÄjs izlemj, kad zvanÄ«t atkritumu savÄcÄjam. Tas nedarbojas, izmantojot parasto rÄdÄ«tÄja skaitÄ«tÄju, piemÄram, Python, Perl, Ruby, Lua utt. Tas tiek Ä«stenots, izmantojot marÄ·ieru sistÄmu. Tie. ja mainÄ«gajam ir paredzÄts pieŔķirt pagaidu vÄrtÄ«bu, atkritumu savÄcÄja kaudzÄ tiek pievienots rÄdÄ«tÄjs uz Å”o vÄrtÄ«bu. TurpmÄk kolekcionÄrs Ätri izskrien cauri jau sagatavotajam norÄdes sarakstam.
ApstrÄde ar try/catch/finals blokiem
TÄpat kÄ jebkurÄ mÅ«sdienu valodÄ, izÅÄmumu apstrÄde ir svarÄ«ga sastÄvdaļa. VirtuÄlÄs maŔīnas kodols ir iesaiÅots try..catch blokÄ, kas var atgriezties pie koda izpildes pÄc izÅÄmuma uztverÅ”anas, nospiežot kÄdu informÄciju par to stekÄ. Lietojumprogrammas kodÄ varat definÄt koda izmÄÄ£inÄÅ”anas/tverÅ”anas/beidzot blokus, norÄdot ieejas punktus uztverÅ”anas brÄ«dÄ« (izÅÄmumu apstrÄdÄtÄjs) un visbeidzot/beigÄs (bloka beigas).
Daudzpavedienu veidoŔana
Tas tiek atbalstÄ«ts VM lÄ«menÄ«. Tas ir vienkÄrÅ”i un Ärti lietojams. Tas darbojas bez pÄrtraukumu sistÄmas, tÄpÄc kods ir jÄizpilda vairÄkos pavedienos vairÄkas reizes ÄtrÄk.
ÄrÄjÄs bibliotÄkas virtuÄlajÄm maŔīnÄm
Bez Ŕī nekÄdi nevar iztikt. VM atbalsta importÄÅ”anu, lÄ«dzÄ«gi kÄ tas tiek ieviests citÄs valodÄs. Daļu koda varat rakstÄ«t valodÄ Mash un daļu koda dzimtajÄ valodÄ, pÄc tam saistÄ«t tos vienÄ.
TulkotÄjs no augsta lÄ«meÅa Mash valodas uz baitu kodu virtuÄlajÄm maŔīnÄm
VidÄja valoda
Lai Ätri ierakstÄ«tu tulkotÄju no sarežģītas valodas VM kodÄ, es vispirms izstrÄdÄju starpvalodu. RezultÄts bija montierim lÄ«dzÄ«ga Å”ausmÄ«ga izrÄde, par kuru Å”eit nav Ä«paÅ”as jÄgas. TeikÅ”u tikai to, ka Å”ajÄ lÄ«menÄ« tulkotÄjs apstrÄdÄ lielÄko daļu konstantu un mainÄ«go, aprÄÄ·ina to statiskÄs adreses un ieejas punktu adreses.
TulkotÄja arhitektÅ«ra
ÄŖstenoÅ”anai neizvÄlÄjos labÄko arhitektÅ«ru. TulkotÄjs neveido kodu koku, kÄ to dara citi tulkotÄji. ViÅÅ” aplÅ«ko struktÅ«ras sÄkumu. Tie. ja parsÄjamÄ koda daļa izskatÄs kÄ āwhile :ā, tad ir acÄ«mredzams, ka Ŕī ir while cilpas konstrukcija un tÄ ir jÄapstrÄdÄ kÄ while cilpas konstrukcija. Kaut kas lÄ«dzÄ«gs sarežģītam slÄdža korpusam.
Pateicoties Å”im arhitektoniskajam risinÄjumam, tulks izrÄdÄ«jÄs ne pÄrÄk Ätrs. TomÄr tÄ modifikÄcijas vieglums ir ievÄrojami palielinÄjies. Es pievienoju nepiecieÅ”amÄs struktÅ«ras ÄtrÄk, nekÄ mana kafija spÄja atdzist. Pilns OOP atbalsts tika ieviests mazÄk nekÄ nedÄļas laikÄ.
Koda optimizÄcija
Å eit, protams, to varÄja ieviest labÄk (un tiks ieviests, bet vÄlÄk, tiklÄ«dz kÄds tiks pie tÄ). PagaidÄm optimizÄtÄjs zina tikai to, kÄ no montÄžas nogriezt neizmantoto kodu, konstantes un importÄÅ”anu. TÄpat vairÄkas konstantes ar vienÄdu vÄrtÄ«bu tiek aizstÄtas ar vienu. Tas ir viss.
Mash valoda
Valodas pamatjÄdziens
GalvenÄ ideja bija izstrÄdÄt pÄc iespÄjas funkcionÄlÄku un vienkÄrÅ”Äku valodu. DomÄju, ka attÄ«stÄ«ba ar savu uzdevumu tiek galÄ ar uzviju.
Kodu bloki, procedūras un funkcijas
Visas konstrukcijas valodÄ tiek atvÄrtas ar kolu. : un operators tos aizver beigas.
ProcedÅ«ras un funkcijas tiek deklarÄtas attiecÄ«gi kÄ proc un func. Argumenti ir norÄdÄ«ti iekavÄs. Viss ir kÄ lielÄkajÄ daÄ¼Ä citu valodu.
Operators atgrieÅ”anÄs varat atgriezt vÄrtÄ«bu no funkcijas, operatora pÄrtraukums ļauj iziet no procedÅ«ras/funkcijas (ja tÄ atrodas Ärpus cilpÄm).
Koda piemÄrs:
...
func summ(a, b):
return a + b
end
proc main():
println(summ(inputln(), inputln()))
end
Atbalstītie modeļi
- Cilpas: uz..beigÄm, kamÄr..beigÄm, lÄ«dz..beigÄm
- NosacÄ«jumi: ja..[else..]beigas, pÄrslÄgties..[lieta..beigas..][else..]beigas
- Metodes: proc ():... end, func ():... end
- IezÄ«me un goto: :, lÄkt
- Uzskaitījumu un konstantu masīvu saraksts.
Mainīgie
TulkotÄjs var tos noteikt automÄtiski vai arÄ« tad, ja izstrÄdÄtÄjs pirms to definÄÅ”anas raksta var.
Koda piemÄri:
a ?= 10
b ?= a + 20
var a = 10, b = a + 20
Tiek atbalstÄ«ti globÄlie un vietÄjie mainÄ«gie.
OOP
Nu, mÄs esam nonÄkuÅ”i pie visgarŔīgÄkÄs tÄmas. Mash atbalsta visas objektorientÄtÄs programmÄÅ”anas paradigmas. Tie. klases, iedzimtÄ«ba, polimorfisms (ieskaitot dinamisko), dinamiskÄ automÄtiskÄ refleksija un introspekcija (pilna).
Bez turpmÄkas piepÅ«les labÄk ir sniegt tikai kodu piemÄrus.
VienkÄrÅ”a klase un darbs ar to:
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
IznÄkums: 30.
Mantojums un polimorfisms:
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
IznÄkums: 60.
KÄ ar dinamisko polimorfismu? JÄ, tas ir pÄrdomas!:
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
IznÄkums: 60.
Tagad veltÄ«sim brÄ«di vienkÄrÅ”Äm vÄrtÄ«bÄm un klasÄm ieskatam:
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
Izvadīs: patiess, patiess.
Par pieŔķirÅ”anas operatoriem un precÄ«zÄm norÄdÄm
Operators ?= tiek izmantots, lai pieŔķirtu mainÄ«gajam rÄdÄ«tÄjam vÄrtÄ«bu atmiÅÄ.
Operators = maina vÄrtÄ«bu atmiÅÄ, izmantojot rÄdÄ«tÄju no mainÄ«gÄ.
Un tagad nedaudz par skaidrÄm norÄdÄm. Es tos pievienoju valodai, lai tie pastÄv.
@ ā norÄdiet skaidru rÄdÄ«tÄju uz mainÄ«go.
? ā iegÅ«stiet mainÄ«go pÄc rÄdÄ«tÄja.
@= ā pieŔķiriet mainÄ«gajam vÄrtÄ«bu ar skaidru rÄdÄ«tÄju uz to.
Koda piemÄrs:
uses <bf>
uses <crt>
proc main():
var a = 10, b
b ?= @a
PrintLn(b)
b ?= ?b
PrintLn(b)
b++
PrintLn(a)
InputLn()
end
IzvadÄ«s: kÄds skaitlis, 10, 11.
IzmÄÄ£iniet..[noÄ·ert..][beidzot..]beigt
Koda piemÄrs:
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
PlÄni nÄkotnei
Es turpinu skatÄ«ties un skatÄ«ties uz GraalVM & Truffle. ManÄ izpildlaika vidÄ nav JIT kompilatora, tÄpÄc veiktspÄjas ziÅÄ tÄ paÅ”laik ir konkurÄtspÄjÄ«ga tikai ar Python. Ceru, ka izdosies ieviest JIT kompilÄciju uz GraalVM vai LLVM bÄzes.
krÄtuve
JÅ«s varat spÄlÄt ar attÄ«stÄ«bu un sekot projektam pats.
Paldies, ka izlasÄ«jÄt lÄ«dz beigÄm, ja to izdarÄ«jÄt.
Avots: www.habr.com