Nýtt forritunarmál Mash

Í nokkur ár reyndi ég fyrir mér að þróa mitt eigið forritunarmál. Ég vildi búa til, að mínu mati, einfaldasta, fullkomlega virka og þægilegasta tungumálið sem mögulegt er.

Í þessari grein vil ég draga fram helstu stig vinnu minnar og til að byrja með lýsa skapaðri hugmynd um tungumálið og fyrstu útfærslu þess sem ég er að vinna að núna.

Leyfðu mér að segja fyrirfram að ég skrifaði allt verkefnið í Free Pascal, vegna þess að... hægt er að setja saman forrit á því fyrir gríðarlegan fjölda kerfa og þýðandinn sjálfur framleiðir mjög bjartsýni tvöfalda (ég safna öllum hlutum verkefnisins með O2 fánanum).

Tungumál keyrslutími

Fyrst af öllu, það er þess virði að tala um sýndarvélina sem ég þurfti að skrifa til að keyra framtíðarforrit á mínu tungumáli. Ég ákvað að innleiða stafla arkitektúr, kannski, vegna þess að það var auðveldasta leiðin. Ég fann ekki eina eðlilega grein um hvernig á að gera þetta á rússnesku, svo eftir að hafa kynnt mér ensku efnið settist ég að því að hanna og skrifa mitt eigið hjól. Næst mun ég kynna „háþróaðar“ hugmyndir mínar og þróun í þessu máli.

Stafla útfærsla

Augljóslega er staflan efst á VM. Í útfærslu minni virkar það í kubbum. Í meginatriðum er þetta einfalt úrval af ábendingum og breyta til að geyma vísitöluna efst á staflanum.
Þegar það er frumstillt er búið til fylki af 256 þáttum. Ef fleiri ábendingum er ýtt á staflann eykst stærð hans um næstu 256 þætti. Í samræmi við það, þegar þættir eru fjarlægðir úr staflanum, er stærð hans aðlöguð.

VM notar nokkra stafla:

  1. Aðalstafla.
  2. Stafla til að geyma skilapunkta.
  3. Sorphirðustafla.
  4. Prófaðu/grípa/lokaðu loksins stjórnandastafla.

Fastar og breytur

Þessi er einföld. Stöður eru meðhöndlaðar í sérstökum litlum kóða og eru fáanlegar í framtíðarforritum með kyrrstæðum heimilisföngum. Breytur eru fylki ábendinga af ákveðinni stærð, aðgangur að frumum hennar fer fram með vísitölu - þ.e. kyrrstætt heimilisfang. Hægt er að ýta breytum efst í staflann eða lesa þaðan. Reyndar vegna þess Þó að breyturnar okkar geymi í raun ábendingar að gildum í VM minni, þá er tungumálið einkennist af því að vinna með óbeinum ábendingum.

Rusla safnari

Í VM mínum er hann hálfsjálfvirkur. Þeir. framkvæmdaraðili ákveður sjálfur hvenær hann hringir í sorphirðu. Það virkar ekki með því að nota venjulegan benditeljara, eins og í Python, Perl, Ruby, Lua o.s.frv. Það er útfært í gegnum merkjakerfi. Þeir. þegar breytu er ætlað að fá tímabundið gildi er bendi á þetta gildi bætt við sorphirðustaflann. Í framtíðinni rennur safnarinn fljótt í gegnum þegar tilbúinn lista yfir ábendingar.

Meðhöndlun reyna/fanga/loka blokkir

Eins og á hverju nútímamáli er meðhöndlun undantekninga mikilvægur þáttur. VM kjarnanum er pakkað inn í try..catch blokk, sem getur farið aftur í keyrslu kóða eftir að hafa náð undantekningu með því að ýta einhverjum upplýsingum um hana inn í stafla. Í forritakóða geturðu skilgreint reyndu/veiða/loka kóðablokka, tilgreina aðgangsstaði við afla (undantekningastjórnun) og loks/lok (lok reitsins).

Fjölþráður

Það er stutt á VM stigi. Það er einfalt og þægilegt í notkun. Það virkar án truflanakerfis, þannig að kóðinn ætti að vera keyrður í nokkrum þræði nokkrum sinnum hraðar, í sömu röð.

Ytri bókasöfn fyrir VM

Það er engin leið að vera án þessa. VM styður innflutning, svipað og það er útfært á öðrum tungumálum. Þú getur skrifað hluta kóðans í Mash og hluta kóðans á móðurmáli og tengt þá síðan í eitt.

Þýðandi úr Mash tungumáli á háu stigi yfir í bækikóða fyrir VM

Millimál

Til að skrifa fljótt þýðanda úr flóknu tungumáli yfir í VM kóða þróaði ég fyrst millimál. Niðurstaðan var hræðilegt sjónarspil sem líkist assembler og það er enginn sérstakur tilgangur að íhuga hér. Ég segi bara að á þessu stigi vinnur þýðandinn flestar fasta og breytur, reiknar út kyrrstæð heimilisföng þeirra og heimilisföng inngangsstaða.

Þýðandi arkitektúr

Ég valdi ekki besta arkitektúrinn til útfærslu. Þýðandinn byggir ekki kóðatré eins og aðrir þýðendur gera. Hann lítur á upphaf byggingarinnar. Þeir. ef kóðastykkið sem verið er að þátta lítur út eins og “meðan <skilyrði>:”, þá er augljóst að þetta er while lykkja smíði og þarf að vinna sem while lykkju smíði. Eitthvað eins og flókið skiptimál.

Þökk sé þessari byggingarlausn reyndist þýðandinn ekki vera mjög fljótur. Hins vegar hefur auðvelt að breyta því verulega. Ég bætti nauðsynlegum mannvirkjum hraðar en kaffið mitt gat kólnað. Fullur OOP stuðningur var innleiddur á innan við viku.

Kóða hagræðingu

Hér hefði auðvitað mátt útfæra það betur (og kemur til framkvæmda, en seinna, um leið og maður kemst að). Enn sem komið er veit fínstillingarmaðurinn aðeins hvernig á að klippa ónotaðan kóða, fasta og innflutning frá samsetningunni. Einnig er nokkrum föstum með sama gildi skipt út fyrir einn. Það er allt og sumt.

Mash tungumál

Grunnhugtak tungumál

Meginhugmyndin var að þróa sem hagnýtasta og einfaldasta tungumálið. Ég held að þróunin ráði við verkefni sitt með glæsibrag.

Kóðablokkir, verklag og aðgerðir

Allar smíðar í tungumálinu eru opnaðar með tvípunkti. : og eru lokaðar af rekstraraðila enda.

Verklag og aðgerðir eru lýstar sem proc og func, í sömu röð. Rökin eru skráð innan sviga. Allt er eins og flest önnur tungumál.

Rekstraraðili aftur þú getur skilað gildi frá falli, rekstraraðila brjóta gerir þér kleift að hætta aðferð/aðgerð (ef hún er utan lykkjunnar).

Dæmi um kóða:

...

func summ(a, b):
  return a + b
end

proc main():
  println(summ(inputln(), inputln()))
end

Stutt hönnun

  • Lykkjur: fyrir..enda, meðan..enda, þar til..enda
  • Skilyrði: ef..[annar..]enda, skipta..[máli..end..][else..]end.
  • Aðferðir: proc <name>():... end, func <name>():... end
  • Label & goto: <nafn>:, hoppa <nafn>
  • Telja upp talningar og fastar fylkingar.

Variables

Þýðandinn getur ákvarðað þær sjálfkrafa, eða ef verktaki skrifar var áður en hann skilgreinir þær.

Dæmi um kóða:

a ?= 10
b ?= a + 20

var a = 10, b = a + 20

Alþjóðlegar og staðbundnar breytur eru studdar.

OOP

Jæja, við erum komin að ljúffengasta efninu. Mash styður allar hlutbundnar forritunaraðferðir. Þeir. flokka, erfðir, fjölbreytni (þar á meðal dýnamískt), kraftmikla sjálfvirka endurspeglun og sjálfsskoðun (full).

Án frekari ummæla er betra að gefa bara kóðadæmi.

Einfaldur flokkur og vinna með hann:

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

Mun gefa út: 30.

Erfðir og fjölbreytni:

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

Mun gefa út: 60.

Hvað með dynamic polymorphism? Já, þetta er spegilmynd!:

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

Mun gefa út: 60.

Nú skulum við taka smá stund til að skoða einföld gildi og flokka:

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

Mun gefa út: satt, satt.

Um verkefnastjóra og skýrar ábendingar

?= stjórnandinn er notaður til að úthluta breytu bendi á gildi í minni.
The = rekstraraðili breytir gildi í minni með því að nota bendi frá breytu.
Og nú aðeins um skýrar ábendingar. Ég bætti þeim við tungumálið þannig að þau væru til.
@<breytu> — taktu skýran bendil á breytu.
?<breytu> — fáðu breytu með bendili.
@= — úthlutaðu gildi til breytu með skýrum bendili á hana.

Dæmi um kóða:

uses <bf>
uses <crt>

proc main():
  var a = 10, b
  b ?= @a
  PrintLn(b)
  b ?= ?b
  PrintLn(b)
  b++
  PrintLn(a)
  InputLn()
end

Mun gefa út: einhver tala, 10, 11.

Prófaðu..[grípa..][loksins..]end

Dæmi um kóða:

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

Áætlanir fyrir framtíðina

Ég held áfram að skoða og skoða GraalVM & Truffle. Runtime umhverfið mitt er ekki með JIT þýðanda, svo hvað varðar afköst er það sem stendur aðeins samkeppnishæft við Python. Ég vona að ég geti innleitt JIT samantekt byggða á GraalVM eða LLVM.

geymsla

Þú getur leikið þér með þróunina og fylgst með verkefninu sjálfur.

Site
Geymsla á GitHub

Þakka þér fyrir að lesa til enda ef þú gerðir það.

Heimild: www.habr.com

Bæta við athugasemd