Kwa miaka kadhaa, nimekuwa nikijaribu mkono wangu katika kukuza lugha yangu ya programu. Nilitaka kuunda lugha ambayo niliamini kuwa rahisi zaidi, inayofanya kazi kikamilifu, na inayoweza kufaa zaidi.
Katika makala hii, nataka kuonyesha hatua kuu za kazi yangu na, kwa kuanza, kuelezea dhana ya lugha niliyounda na utekelezaji wake wa kwanza, ambao ninafanya kazi sasa.
Nitasema mapema kwamba niliandika mradi mzima katika Free Pascal, kwani programu zinaweza kukusanywa kwa idadi kubwa ya majukwaa, na mkusanyaji yenyewe hutoa jozi zilizoboreshwa sana (mimi hukusanya vifaa vyote vya mradi na bendera ya O2).
Mazingira ya wakati wa kutumia lugha
Kwanza, ninapaswa kuzungumza juu ya mashine ya kawaida niliyopaswa kuandika ili kuendesha programu za baadaye katika lugha yangu. Niliamua kutekeleza usanifu wa msingi wa stack, labda kwa sababu ilikuwa rahisi zaidi. Sikuweza kupata makala moja nzuri kuhusu jinsi ya kufanya hivyo kwa Kirusi, kwa hiyo baada ya kusoma nyenzo za lugha ya Kiingereza, nilianza kazi ya kubuni na kuandika mashine yangu mwenyewe. Hapa chini, nitashiriki mawazo yangu ya kisasa na maendeleo katika eneo hili.
Utekelezaji wa rafu
Ni wazi, stack iko juu ya VM. Katika utekelezaji wangu, inafanya kazi katika vizuizi. Kimsingi, ni safu rahisi ya viashiria na tofauti ya kuhifadhi faharasa ya sehemu ya juu ya rafu.
Inapoanzishwa, safu ya vipengele 256 huundwa. Viashirio zaidi vinaposukumwa kwenye rafu, saizi yake huongezeka kwa vipengele vingine 256. Ipasavyo, wakati vitu vinapoondolewa kwenye safu, saizi yake inarekebishwa.
VM hutumia safu kadhaa:
- Mkusanyiko mkuu.
- Rafu kwa ajili ya kuhifadhi pointi za kurudi.
- Mkusanyiko wa mtoza takataka.
- Rundo la jaribu/kamata/mwishowe linazuia kidhibiti.
Mara kwa mara na vigezo
Hii ni rahisi. Mara kwa mara hushughulikiwa na sehemu tofauti, ndogo ya msimbo na zinaweza kufikiwa katika programu za baadaye katika anwani tuli. Vigezo ni safu za viashiria vya ukubwa fulani, na seli zao hupatikana kwa index-yaani, anwani tuli. Vigezo vinaweza kusukumwa juu ya rafu au kusomwa kutoka hapo. Kwa kweli, kwa kuwa vigeu vyetu kimsingi huhifadhi viashiria kwa maadili katika kumbukumbu ya VM, lugha hutumia viashiria wazi.
Mkusanyaji taka
Katika VM yangu, ni nusu otomatiki. Hiyo ni, msanidi anaamua wakati wa kumwita mtoza takataka. Haitegemei kihesabu cha kitamaduni cha pointer, kama vile Python, Perl, Ruby, Lua, na kadhalika. Inatekelezwa kupitia mfumo wa alama. Hiyo ni, wakati tofauti inapewa thamani ya muda, pointer kwa thamani hiyo huongezwa kwenye mkusanyiko wa kukusanya takataka. Mtoza kisha anaendesha haraka kupitia orodha iliyopo ya viashiria.
Kushughulikia jaribu/kamata/mwisho kunazuia
Kama ilivyo katika lugha yoyote ya kisasa, utunzaji wa ubaguzi ni sehemu muhimu. Kiini cha VM kimefungwa kwa try..catch block, ambayo inaweza kurudi kwenye utekelezaji wa msimbo baada ya kupata ubaguzi, ikisukuma habari fulani kuihusu kwenye rafu. Nambari ya maombi inaweza kufafanua jaribu/kamata/mwisho vizuizi vya msimbo, ikibainisha pointi za kuingia wakati wa kukamata (kidhibiti cha ubaguzi) na hatimaye/mwisho (mwisho wa kizuizi).
Usomaji mwingi
Inatumika katika kiwango cha VM. Ni rahisi na rahisi kutumia. Inafanya kazi bila kukatizwa, kwa hivyo msimbo unapaswa kuendeshwa kwa kasi mara kadhaa kwenye nyuzi nyingi.
Maktaba za nje za VMs
Hakuna njia ya kuizunguka. VM inasaidia uagizaji, kama lugha zingine. Unaweza kuandika msimbo fulani katika Mash na baadhi katika lugha za asili, kisha uziunganishe pamoja.
Mtafsiri kutoka lugha ya kiwango cha juu ya Mash hadi bytecode kwa VM
Lugha ya kati
Ili kuandika haraka mfasiri kutoka lugha changamano hadi msimbo wa VM, kwanza nilitengeneza lugha ya kati. Matokeo yake yalikuwa tamasha ya kutisha, kama kusanyiko ambayo haileti maana hapa. Acha niseme tu kwamba katika kiwango hiki, mtafsiri huchakata viunga vingi na vigeu, kuhesabu anwani zao tuli na anwani za mahali pa kuingilia.
Usanifu wa mtafsiri
Sikuchagua usanifu bora zaidi wa utekelezaji. Mfasiri haungi mti wa msimbo, kama watafsiri wengine hufanya. Inatazama mwanzo wa ujenzi. Kwa hivyo, ikiwa nambari inayochanganuliwa inaonekana kama "wakati <condition>:," basi ni wazi ni muundo wa kitanzi cha muda na inapaswa kuchakatwa kama muundo wa kitanzi cha muda. Kitu kama kesi changamano ya kubadili.
Shukrani kwa suluhisho hili la usanifu, mkusanyaji hakuwa na haraka sana. Walakini, urahisi wake wa marekebisho uliongezeka kwa kasi. Niliongeza miundo muhimu kwa haraka zaidi kuliko kahawa yangu inaweza kupoa. Usaidizi kamili wa OOP ulitekelezwa chini ya wiki moja.
Uboreshaji wa msimbo
Kwa kweli, hii inaweza kutekelezwa vyema (na itakuwa, lakini baadaye, nitakapoifikia). Kwa sasa, kiboreshaji kinaweza tu kupunguza nambari zisizotumiwa, vidhibiti, na uagizaji kutoka kwa muundo. Pia, viunga vingi vilivyo na thamani sawa hubadilishwa na moja. Ni hayo tu.
Lugha ya mash
Dhana ya msingi ya lugha
Lengo kuu lilikuwa kukuza lugha ambayo ilikuwa ya utendaji na rahisi iwezekanavyo. Ninaamini mradi unafikia lengo lake kwa rangi zinazoruka.
Vizuizi vya kanuni, taratibu, na kazi
Miundo yote katika lugha hufunguliwa kwa koloni : na zimefungwa na mwendeshaji mwisho.
Taratibu na utendakazi hutangazwa kama proc na func , mtawalia. Hoja zimeorodheshwa kwenye mabano. Hii ni sawa na katika lugha zingine nyingi.
Opereta kurudi Unaweza kurudisha thamani kutoka kwa chaguo za kukokotoa, opereta kuvunja hukuruhusu kutoka kwa utaratibu/kazi (ikiwa ni nje ya vitanzi).
Msimbo wa sampuli:
...
func summ(a, b):
return a + b
end
proc main():
println(summ(inputln(), inputln()))
end
Miundo inayoungwa mkono
- Loops: kwa..mwisho, wakati..mwisho, mpaka..mwisho
- Masharti: ikiwa..[vingine..]mwisho, badilisha..[kesi..mwisho..][else..]mwisho.
- Mbinu: proc <name>():… mwisho, func <name>():… mwisho
- Lebo na goto: <name>:, ruka <name>
- Enum enumerations na safu mara kwa mara.
Vighairi
Mtafsiri anaweza kuzibainisha kiotomatiki, au kama msanidi anaandika var kabla ya ufafanuzi wao.
Mifano ya kanuni:
a ?= 10
b ?= a + 20
var a = 10, b = a + 20
Vigezo vya kimataifa na vya ndani vinatumika.
OOP
Naam, hatimaye tumefikia mada ya kusisimua zaidi. Lugha ya Mash inaauni dhana zote za upangaji zenye mwelekeo wa kitu. Hiyo ina maana madarasa, urithi, upolimishaji (pamoja na nguvu), uakisi otomatiki unaobadilika, na uchunguzi wa ndani (kamili).
Bila ado zaidi, nitatoa mifano kadhaa ya nambari.
Darasa rahisi na jinsi ya kufanya kazi nayo:
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
Pato: 30.
Urithi na polymorphism:
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
Pato: 60.
Vipi kuhusu upolimishaji wenye nguvu? Hiyo ni tafakari!
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
Pato: 60.
Sasa hebu tuchukue muda kutafakari kwa maadili rahisi na madarasa:
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
Matokeo: kweli, kweli.
Kuhusu waendeshaji mgawo na viashiria wazi
Opereta ?= inatumika kugawa kielekezi kwa thamani iliyo kwenye kumbukumbu kwa kigezo.
Opereta = hubadilisha thamani katika kumbukumbu iliyoelekezwa na kigezo.
Na sasa kidogo juu ya viashiria wazi. Niliwaongeza kwenye lugha ili tu wawepo.
@<variable> - chukua kiashirio wazi kwa kigezo.
?<variable> — pata kigezo kwa kielekezi.
@= — toa thamani kwa kigezo kwa kutumia kiashirio dhahiri kwake.
Msimbo wa sampuli:
uses <bf>
uses <crt>
proc main():
var a = 10, b
b ?= @a
PrintLn(b)
b ?= ?b
PrintLn(b)
b++
PrintLn(a)
InputLn()
end
Pato: nambari fulani, 10, 11.
Jaribu..[catch..][hatimaye..]mwisho
Msimbo wa sampuli:
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
Mipango ya siku zijazo
Bado ninaangalia GraalVM na Truffle. Mazingira yangu ya wakati wa kukimbia hayana mkusanyaji wa JIT, kwa hivyo katika suala la utendaji, kwa sasa inashindana tu na Python. Natumai naweza kutekeleza mkusanyiko wa JIT kwa kutumia GraalVM au LLVM.
hazina
Unaweza kucheza na maendeleo na kufuata mradi mwenyewe.
Asante kwa kusoma hadi mwisho, ikiwa ulifanya.
Chanzo: mapenzi.com
