Nýtt forritunarmál Mash

Í nokkur ár hef ég verið að reyna fyrir mér í að þróa mitt eigið forritunarmál. Ég vildi búa til það sem ég taldi vera einfaldasta, hagnýtasta og þægilegasta forritunarmálið sem völ er á.

Í þessari grein vil ég varpa ljósi á helstu stig vinnu minnar og byrja á að lýsa tungumálshugtakinu sem ég bjó til og fyrstu útfærslu þess, sem ég er nú að vinna að.

Ég skal strax taka fram að ég skrifaði allt verkefnið í Free Pascal, þar sem hægt er að þýða forrit fyrir gríðarlegan fjölda kerfa, og þýðandinn sjálfur býr til mjög fínstilltar tvíundarskrár (ég þýði alla íhluti verkefnisins með O2 fánanum).

Keyrsluumhverfi tungumálsins

Fyrst ætti ég að tala um sýndarvélina sem ég þurfti að skrifa til að keyra framtíðarforrit í mínu forritunarmáli. Ég ákvað að útfæra stafla-byggða arkitektúr, líklega vegna þess að það var auðveldast. Ég fann enga góða grein um hvernig á að gera þetta á rússnesku, svo eftir að hafa lesið eitthvað efni á ensku hófst ég handa við að hanna og skrifa mína eigin vél. Hér að neðan mun ég deila nýjustu hugmyndum mínum og þróun á þessu sviði.

Staflaútfærsla

Augljóslega er staflan efst í sýndarvélinni. Í minni útfærslu virkar hún í blokkum. Í meginatriðum er þetta einföld fylking af bendum og breyta til að geyma vísitölu efstu hluta staflansins.
Þegar staflinn er frumstilltur er hann búinn til fylki með 256 stökum. Ef fleiri bendlar eru settir á staflan eykst stærð hans um 256 stök til viðbótar. Þar af leiðandi, þegar stök eru fjarlægð úr staflanum, er stærð hans aðlöguð.

Sýndarvélin notar nokkra stafla:

  1. Aðalstafla.
  2. Stafla til að geyma skilapunkta.
  3. Ruslsafnara stafli.
  4. Stafli af meðhöndlunaraðilum sem reyna/grípa/loksins blokka.

Fastar og breytur

Þetta er einfalt. Stöður eru meðhöndlaðar af sérstökum, litlum kóðabút og eru aðgengilegar í framtíðarforritum á kyrrstæðum vistföngum. Breytur eru fylki af bendum af ákveðinni stærð og aðgangur að frumum þeirra er aðgengilegur með vísitölu - þ.e. kyrrstæðu vistfangi. Hægt er að færa breytur efst í stafla eða lesa þær þaðan. Reyndar, þar sem breyturnar okkar geyma í raun bendla að gildum í minni sýndarvélarinnar, notar tungumálið aðallega óbeina bendla.

Rusla safnari

Í sýndarvélinni minni er þetta hálfsjálfvirkt. Það er að segja, forritarinn ákveður hvenær á að kalla á ruslasafnið. Það treystir ekki á hefðbundinn bendilteljara, eins og í Python, Perl, Ruby, Lua og svo framvegis. Það er útfært með merkjakerfi. Það er að segja, þegar breyta fær tímabundið gildi, er bendill á það gildi bætt við ruslasafnið. Safnarinn keyrir síðan fljótt í gegnum núverandi lista af bendum.

Meðhöndlun tilrauna/grípu/lokablokka

Eins og í öllum nútímamálum er undantekningarmeðhöndlun nauðsynlegur þáttur. Kjarninn í sýndarvélinni er vafinn inn í try..catch blokk, sem getur snúið aftur til kóðakeyrslu eftir að hafa gripið undantekningu og fært upplýsingar um hana yfir á staflan. Forritskóði getur skilgreint try/catch/finally kóðablokkir, tilgreint aðgangspunkta við catch (undantekningahöndlarann) og finally/end (lok blokkarinnar).

Fjölþráður

Það er stutt á sýndarvélastigi. Það er einfalt og auðvelt í notkun. Það virkar án truflana, þannig að kóði ætti að keyra margfalt hraðar yfir marga þræði.

Ytri bókasöfn fyrir sýndarvélar

Það er engin leið að komast hjá því. Sýndarvél styður innflutning, rétt eins og önnur tungumál. Þú getur skrifað kóða í Mash og annan á móðurmáli og síðan tengt þá saman.

Þýðandi úr hástigs Mash tungumálinu yfir í bætikóða fyrir sýndarvélar

Millistungumál

Til að skrifa fljótt þýðanda úr flóknu tungumáli yfir í sýndarvélakóða þróaði ég fyrst millimál. Niðurstaðan var skelfileg, samsetningarlík sjónarspil sem er í raun ekki skynsamlegt hér. Leyfið mér bara að segja að á þessu stigi vinnur þýðandinn úr flestum fastum og breytum, reiknar út kyrrstæð vistföng þeirra og aðgangspunktvistföng.

Þýðandaarkitektúr

Ég valdi ekki bestu arkitektúrinn fyrir útfærsluna. Þýðandinn býr ekki til kóðatré, eins og aðrir þýðendur gera. Hann skoðar upphaf smíðinnar. Svo ef kóðinn sem verið er að greina lítur út eins og "while <skilyrði>:," þá er þetta augljóslega while-lykkjusmíð og ætti að vera unnin sem while-lykkjusmíð. Eitthvað eins og flókið skiptingartilfelli.

Þökk sé þessari byggingarlausn var þýðandinn ekki sérstaklega hraður. Hins vegar jókst auðveldleiki breytinga gríðarlega. Ég bætti við nauðsynlegum smíðum hraðar en kaffið mitt gat kólnað. Fullur stuðningur við OOP var innleiddur á innan við viku.

Kóða hagræðingu

Auðvitað hefði þetta getað verið betur útfært (og verður það, en síðar, þegar ég kemst að því). Í bili getur fínstillingin aðeins klippt ónotaðan kóða, fasta og innflutning úr smíðinni. Einnig eru margir fastar með sama gildi skipt út fyrir einn. Það er allt og sumt.

Mash tungumál

Grunnhugtakið tungumál

Meginmarkmiðið var að þróa eins hagnýtt og einfalt forritunarmál og mögulegt er. Ég tel að verkefnið nái markmiði sínu með glæsibrag.

Kóðablokkir, verklagsreglur og föll

Allar smíðar í tungumálinu byrja með tvípunkti : og eru lokuð af rekstraraðilanum enda.

Verklagsreglur og föll eru skilgreind sem proc og func, talið í sömu röð. Færibreytur eru taldar upp í sviga. Þetta er það sama og í flestum öðrum forritunarmálum.

Rekstraraðili aftur Þú getur skilað gildi úr falli, virkjara brjóta gerir þér kleift að hætta í ferli/falli (ef það er utan lykkjur).

Dæmi um kóða:

...

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

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

Studdar smíðar

  • Lykkjur: fyrir..end, á meðan..end, þar til..end
  • Skilyrði: ef..[annars..]endi, skipta..[tilfelli..endi..][annars..]endi
  • Aðferðir: proc <nafn>():… enda, func <nafn>():… enda
  • Merkja & fara: <nafn>:, hoppa <nafn>
  • Upptalningar og fastar fylki.

Variables

Þýðandinn getur ákvarðað þau sjálfkrafa, eða ef forritarinn skrifar var á undan skilgreiningu þeirra.

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, þá erum við loksins komin að spennandi efninu. Forritunarmálið Mash styður allar hlutbundnar forritunarlíkön. Það þýðir klasa, erfðir, fjölbreytileika (þar með talið kraftmikla), kraftmikla sjálfvirka speglun og sjálfskoðun (í heild sinni).

Án frekari umfjöllunar mun ég bara gefa nokkur dæmi um kóða.

Einfaldur flokkur og hvernig á að 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

Úttak: 30.

Erfðir og fjölbreytileiki:

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

Úttak: 60.

Hvað með breytilega fjölbreytni? Það er speglun!

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

Úttak: 60.

Við skulum nú skoða einföld gildi og flokka í smá stund:

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

Úttak: satt, satt.

Um úthlutunarvirkja og skýra bendla

Virkinn ?= er notaður til að úthluta bendli á gildi í minni breytu.
Virkinn = breytir gildinu í minninu sem breytan vísar á.
Og nú aðeins um skýrar ábendingar. Ég bætti þeim við forritunarmálið bara svo þær væru til staðar.
@<breyta> — tekur skýran bendil á breytu.
?<breyta> — sækja breytu með bendil.
@= — úthlutar gildi til breytu með því að nota skýran bendil á 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: einhverja tölu, 10, 11.

Reyndu..[náðu..][loksins..]endi

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 er enn að fylgjast með GraalVM og Truffle. Keyrsluumhverfið mitt er ekki með JIT-þýðanda, svo hvað varðar afköst er það núna aðeins samkeppnishæft við Python. Ég vona að ég geti útfært JIT-þýðingu með GraalVM eða LLVM.

geymsla

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

Site
Geymsla á GitHub

Takk fyrir að lesa til enda, ef þú gerðir það.

Heimild: www.habr.com

Kauptu áreiðanlega hýsingu fyrir síður með DDoS vernd, VPS VDS netþjónum 🔥 Kauptu áreiðanlega vefhýsingu með DDoS vörn, VPS VDS netþjónum | ProHoster