Í 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:
- Aðalstafla.
- Stafla til að geyma skilapunkta.
- Ruslsafnara stafli.
- 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.
Takk fyrir að lesa til enda, ef þú gerðir það.
Heimild: www.habr.com
