Lugha mpya ya programu Mash

Kwa miaka kadhaa nilijaribu mkono wangu katika kukuza lugha yangu ya programu. Nilitaka kuunda, kwa maoni yangu, lugha rahisi zaidi, inayofanya kazi kikamilifu na rahisi iwezekanavyo.

Katika makala hii nataka kuonyesha hatua kuu za kazi yangu na, kwa kuanzia, kuelezea dhana iliyoundwa ya lugha na utekelezaji wake wa kwanza, ambayo ninafanya kazi sasa.

Acha niseme mapema kwamba niliandika mradi mzima katika Free Pascal, kwa sababu ... programu juu yake zinaweza kukusanywa kwa idadi kubwa ya majukwaa, na mkusanyaji yenyewe hutoa jozi zilizoboreshwa sana (mimi hukusanya vifaa vyote vya mradi na bendera ya O2).

Muda wa utekelezaji wa lugha

Kwanza kabisa, inafaa kuzungumza juu ya mashine ya kawaida ambayo ilibidi niandike ili kuendesha programu za siku zijazo katika lugha yangu. Niliamua kutekeleza usanifu wa stack, labda, kwa sababu ilikuwa njia rahisi zaidi. Sikupata makala moja ya kawaida kuhusu jinsi ya kufanya hivyo kwa Kirusi, hivyo baada ya kujijulisha na nyenzo za lugha ya Kiingereza, niliketi kuunda na kuandika baiskeli yangu mwenyewe. Ifuatayo nitawasilisha mawazo yangu "ya hali ya juu" na maendeleo katika suala hili.

Utekelezaji wa rafu

Ni wazi, juu ya VM ni stack. Katika utekelezaji wangu inafanya kazi katika vizuizi. Kimsingi hii ni safu rahisi ya viashiria na kigezo cha kuhifadhi faharasa ya sehemu ya juu ya rafu.
Inapoanzishwa, safu ya vipengele 256 huundwa. Viashirio zaidi vinaposukumwa kwenye rafu, ukubwa wake huongezeka kwa vipengele 256 vinavyofuata. Ipasavyo, wakati wa kuondoa vitu kutoka kwa stack, saizi yake inarekebishwa.

VM hutumia safu kadhaa:

  1. Mkusanyiko mkuu.
  2. Rafu ya kuhifadhi pointi za kurudi.
  3. Mkusanyiko wa mtoza takataka.
  4. Jaribu/kamata/mwisho zuia mrundikano wa kidhibiti.

Mara kwa mara na Vigezo

Hii ni rahisi. Mara kwa mara hushughulikiwa katika sehemu ndogo tofauti ya msimbo na zinapatikana katika programu za baadaye kupitia anwani tuli. Vigezo ni safu ya viashiria vya ukubwa fulani, upatikanaji wa seli zake unafanywa na index - i.e. anwani tuli. Vigezo vinaweza kusukumwa juu ya rafu au kusomwa kutoka hapo. Kweli, kwa sababu Wakati vigeu vyetu kimsingi huhifadhi viashiria kwa maadili katika kumbukumbu ya VM, lugha hutawaliwa na kufanya kazi na viashiria wazi.

Mkusanyaji taka

Katika VM yangu ni nusu otomatiki. Wale. msanidi mwenyewe anaamua wakati wa kumwita mtoza takataka. Haifanyi kazi kwa kutumia kihesabu cha kawaida cha pointer, kama vile Python, Perl, Ruby, Lua, nk. Inatekelezwa kupitia mfumo wa alama. Wale. wakati kigezo kinakusudiwa kupewa thamani ya muda, kielekezi kwa thamani hii huongezwa kwenye mkusanyiko wa mkusanya takataka. Katika siku zijazo, mtoza haraka hupitia orodha iliyoandaliwa tayari ya viashiria.

Kushughulikia jaribu/kamata/mwisho kunazuia

Kama ilivyo katika lugha yoyote ya kisasa, utunzaji wa kipekee ni sehemu muhimu. Msingi wa VM umefungwa katika jaribio..catch block, ambayo inaweza kurudi kwenye utekelezaji wa msimbo baada ya kupata ubaguzi kwa kusukuma habari fulani kuihusu kwenye rafu. Katika msimbo wa maombi, unaweza kufafanua jaribu/kamata/mwisho vizuizi vya msimbo, ukibainisha pointi za kuingia kwenye kukamata (kidhibiti cha ubaguzi) na hatimaye/mwisho (mwisho wa kizuizi).

Usomaji mwingi

Inasaidiwa katika kiwango cha VM. Ni rahisi na rahisi kutumia. Inafanya kazi bila mfumo wa kukatiza, kwa hivyo msimbo unapaswa kutekelezwa katika nyuzi kadhaa mara kadhaa haraka, mtawaliwa.

Maktaba za nje za VMs

Hakuna njia ya kufanya bila hii. VM inasaidia uagizaji, sawa na jinsi inavyotekelezwa katika lugha zingine. Unaweza kuandika sehemu ya msimbo katika Mash na sehemu ya msimbo katika lugha asilia, kisha uunganishe kuwa moja.

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 la kutisha kama la mkusanyaji ambalo hakuna jambo fulani la kuzingatia hapa. Nitasema tu kwamba katika ngazi hii mtafsiri hushughulikia vipengele vingi na vigezo, huhesabu anwani zao za tuli na anwani za pointi za kuingia.

Usanifu wa mtafsiri

Sikuchagua usanifu bora zaidi wa utekelezaji. Mfasiri haungi mti wa msimbo, kama watafsiri wengine wanavyofanya. Anaangalia mwanzo wa muundo. Wale. ikiwa kipande cha msimbo kinachochanganuliwa kinaonekana kama "wakati <condition>:", basi ni dhahiri kuwa huu ni muundo wa kitanzi cha muda na unahitaji kuchakatwa kama muundo wa kitanzi cha muda. Kitu kama kesi changamano ya kubadili.

Shukrani kwa ufumbuzi huu wa usanifu, mtafsiri aligeuka kuwa si haraka sana. Hata hivyo, urahisi wa marekebisho yake umeongezeka kwa kiasi kikubwa. Niliongeza miundo muhimu kwa kasi zaidi kuliko kahawa yangu inaweza kupoa. Usaidizi kamili wa OOP ulitekelezwa chini ya wiki moja.

Uboreshaji wa msimbo

Hapa, bila shaka, ingeweza kutekelezwa vizuri zaidi (na itatekelezwa, lakini baadaye, mara tu mtu anapoizunguka). Kufikia sasa, kiboreshaji kinajua tu jinsi ya kukata nambari isiyotumika, viboreshaji na uagizaji kutoka kwa mkusanyiko. Pia, mara kwa mara kadhaa na thamani sawa hubadilishwa na moja. Ni hayo tu.

Lugha ya mash

Dhana ya msingi ya lugha

Wazo kuu lilikuwa kukuza lugha inayofanya kazi zaidi na rahisi iwezekanavyo. Nadhani maendeleo yanakabiliana na kazi yake kwa kishindo.

Vizuizi vya kanuni, taratibu na kazi

Miundo yote katika lugha hufunguliwa kwa koloni. : na zimefungwa na mwendeshaji mwisho.

Taratibu na kazi zinatangazwa kama proc na func, mtawalia. Hoja zimeorodheshwa kwenye mabano. Kila kitu ni kama lugha nyingine nyingi.

Opereta kurudi unaweza kurudisha thamani kutoka kwa chaguo za kukokotoa, opereta kuvunja inakuwezesha kuondoka 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 Inayotumika

  • 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 kuzifafanua.

Mifano ya kanuni:

a ?= 10
b ?= a + 20

var a = 10, b = a + 20

Vigezo vya kimataifa na vya ndani vinatumika.

OOP

Kweli, tumekuja kwenye mada ya kupendeza zaidi. Mash inasaidia dhana zote za upangaji zinazolenga kitu. Wale. madarasa, urithi, polymorphism (ikiwa ni pamoja na nguvu), tafakari ya moja kwa moja yenye nguvu na uchunguzi (kamili).

Bila ado zaidi, ni bora kutoa mifano ya nambari.

Darasa rahisi na 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

Matokeo: 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

Matokeo: 60.

Vipi kuhusu upolimishaji unaobadilika? Ndio, hii 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

Matokeo: 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

Itatoa matokeo: kweli, kweli.

Kuhusu waendeshaji mgawo na viashiria wazi

Opereta ?= inatumiwa kugawa kiashiria kwa thamani katika kumbukumbu.
Opereta = hubadilisha thamani katika kumbukumbu kwa kutumia pointer kutoka kwa kutofautisha.
Na sasa kidogo juu ya viashiria wazi. Niliwaongeza kwenye lugha ili wawepo.
@<variable> - chukua kiashirio wazi kwa kigezo.
?<variable> β€” pata kigezo kwa kielekezi.
@= β€” toa thamani kwa kigezo kwa kielekezi wazi 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

Ninaendelea kuangalia na kuangalia GraalVM & Truffle. Mazingira yangu ya wakati wa kukimbia hayana mkusanyaji wa JIT, kwa hivyo katika suala la utendaji kwa sasa inashindana tu na Python. Natumai kuwa nitaweza kutekeleza mkusanyiko wa JIT kulingana na GraalVM au LLVM.

hazina

Unaweza kucheza na maendeleo na kufuata mradi mwenyewe.

Site
Hifadhi kwenye GitHub

Asante kwa kusoma hadi mwisho ikiwa ulifanya.

Chanzo: mapenzi.com

Kuongeza maoni