Lugha mpya ya programu Mash

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:

  1. Mkusanyiko mkuu.
  2. Rafu kwa ajili ya kuhifadhi pointi za kurudi.
  3. Mkusanyiko wa mtoza takataka.
  4. 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.

Site
Hifadhi kwenye GitHub

Asante kwa kusoma hadi mwisho, ikiwa ulifanya.

Chanzo: mapenzi.com

Nunua upangishaji wa kuaminika wa tovuti zilizo na ulinzi wa DDoS, seva za VPS VDS 🔥 Nunua upangishaji wa tovuti unaoaminika kwa ulinzi wa DDoS, seva za VPS VDS | ProHoster