Шинэ програмчлалын хэл Mash

Хэдэн жилийн турш би өөрийн програмчлалын хэлийг хөгжүүлэх гэж оролдсон. Би хамгийн энгийн, бүрэн ажиллагаатай, тохиромжтой хэлийг бүтээхийг хүссэн.

Энэ өгүүлэлд би ажлынхаа үндсэн үе шатуудыг онцолж, эхлээд хэлийг бий болгосон үзэл баримтлал, түүний анхны хэрэгжилтийг тайлбарлахыг хүсч байна.

Би бүх төслийг Free Pascal хэл дээр бичсэн гэдгээ урьдчилан хэлье, учир нь... үүн дээрх програмуудыг асар олон тооны платформд зориулж угсарч болох бөгөөд хөрвүүлэгч өөрөө маш оновчтой хоёртын файлуудыг гаргадаг (би O2 туг бүхий төслийн бүх бүрэлдэхүүн хэсгүүдийг цуглуулдаг).

Хэлний ажиллах хугацаа

Юуны өмнө ирээдүйн програмуудыг өөрийн хэл дээр ажиллуулахын тулд бичих ёстой виртуал машины талаар ярих нь зүйтэй болов уу. Би стек архитектурыг хэрэгжүүлэхээр шийдсэн, магадгүй энэ нь хамгийн хялбар арга байсан юм. Би үүнийг орос хэл дээр хэрхэн хийх талаар нэг ч энгийн нийтлэл олж чадаагүй тул англи хэл дээрх материалтай танилцсаны дараа би дугуйгаа зохион бүтээж, бичихээр суув. Дараа нь би энэ талаар "дэвшилтэт" санаа, боловсруулалтаа танилцуулах болно.

Стекийн хэрэгжилт

Мэдээжийн хэрэг, VM-ийн дээд хэсэгт стек байдаг. Миний хэрэгжилтэд энэ нь блокоор ажилладаг. Үндсэндээ энэ бол заагчуудын энгийн массив бөгөөд стекийн дээд хэсгийн индексийг хадгалах хувьсагч юм.
Үүнийг эхлүүлэх үед 256 элементийн массив үүсдэг. Хэрэв стек дээр илүү олон заагчийг түлхвэл түүний хэмжээ дараагийн 256 элементээр нэмэгдэнэ. Үүний дагуу стекээс элементүүдийг арилгахдаа түүний хэмжээг тохируулна.

VM нь хэд хэдэн стек ашигладаг:

  1. Үндсэн стек.
  2. Буцах цэгүүдийг хадгалах стек.
  3. Хог цуглуулагчийн яндан.
  4. Оролдоод/барьж/ эцэст нь зохицуулагчийн стекийг блоклох.

Тогтмол ба хувьсагчид

Энэ бол энгийн зүйл. Тогтмолуудыг тусдаа жижиг кодын хэсэг болгон зохицуулдаг бөгөөд статик хаягаар дамжуулан ирээдүйн хэрэглээнд ашиглах боломжтой. Хувьсагч нь тодорхой хэмжээний заагчийн массив бөгөөд түүний нүднүүдэд хандах хандалтыг индексээр гүйцэтгэдэг - өөрөөр хэлбэл. статик хаяг. Хувьсагчдыг стекийн дээд талд түлхэж эсвэл тэндээс уншиж болно. Үнэндээ, учир нь Манай хувьсагчид үндсэндээ VM санах ойд заагчийг утгыг хадгалдаг бол хэл нь далд заагчтай ажиллахад давамгайлдаг.

Хог цуглуулагч

Миний VM дээр энэ нь хагас автомат юм. Тэдгээр. Хөгжүүлэгч өөрөө хог цуглуулагч руу хэзээ залгахаа шийддэг. Энэ нь Python, Perl, Ruby, Lua гэх мэт ердийн заагч тоолуур ашиглан ажиллахгүй. Энэ нь маркерын системээр хэрэгждэг. Тэдгээр. хувьсагчд түр зуурын утга оноохоор төлөвлөж байгаа бол энэ утгын заагчийг хог цуглуулагчийн стек дээр нэмдэг. Ирээдүйд цуглуулагч аль хэдийн бэлтгэсэн заагчийн жагсаалтыг хурдан гүйлгэдэг.

try/catch/finally блокуудыг зохицуулах

Орчин үеийн аливаа хэлний нэгэн адил онцгой тохиолдлуудыг зохицуулах нь чухал бүрэлдэхүүн хэсэг юм. VM цөм нь try..catch блок дотор ороосон бөгөөд энэ нь тухайн тохиолдлын талаарх зарим мэдээллийг стек рүү түлхэж, үл хамаарах зүйлийг барьж авсны дараа код гүйцэтгэл рүү буцах боломжтой. Хэрэглээний кодонд та try/catch/finally кодын блокуудыг тодорхойлж, catch (үл хамаарах зохицуулагч) болон эцэст нь/төгсгөл (блокийн төгсгөл) дээр орох цэгүүдийг зааж өгч болно.

Олон урсгалтай

Энэ нь VM түвшинд дэмжигддэг. Энэ нь хэрэглэхэд хялбар бөгөөд тохиромжтой. Энэ нь тасалдалгүй ажилладаг тул кодыг хэд хэдэн хэлхээнд хэд хэдэн удаа хурдан гүйцэтгэх ёстой.

VM-д зориулсан гадаад номын сангууд

Үүнгүйгээр хийх арга байхгүй. VM нь бусад хэл дээр хэрхэн хэрэгждэгтэй адил импортыг дэмждэг. Та кодын нэг хэсгийг Mash дээр, нэг хэсгийг нь эх хэлээр бичиж, дараа нь нэг болгон холбож болно.

Өндөр түвшний Mash хэлнээс VM-д зориулсан байт код руу орчуулагч

Дунд түвшний хэл

Нарийн төвөгтэй хэлнээс VM код руу орчуулагчийг хурдан бичихийн тулд би эхлээд завсрын хэлийг боловсруулсан. Үр дүн нь ассемблер шиг аймшигт үзэгдэл болсон бөгөөд энд авч үзэх ямар ч утгагүй юм. Энэ түвшинд орчуулагч ихэнх тогтмол болон хувьсагчдыг боловсруулж, тэдгээрийн статик хаягууд болон нэвтрэх цэгүүдийн хаягийг тооцдог гэдгийг л хэлье.

Орчуулагчийн архитектур

Би хэрэгжүүлэхийн тулд хамгийн сайн архитектурыг сонгоогүй. Орчуулагч бусад орчуулагчид шиг кодын модыг бүтээдэггүй. Тэр бүтцийн эхлэлийг хардаг. Тэдгээр. Хэрэв задлан шинжилж буй кодын хэсэг нь “while :” шиг харагдаж байвал энэ нь while давталтын бүтэц бөгөөд while давталтын бүтэц болгон боловсруулах шаардлагатай байгаа нь ойлгомжтой. Нарийн төвөгтэй шилжүүлэгчтэй адил зүйл.

Энэхүү архитектурын шийдлийн ачаар орчуулагч тийм ч хурдан биш болсон. Гэсэн хэдий ч түүнийг өөрчлөхөд хялбар байдал мэдэгдэхүйц нэмэгдсэн. Би кофегоо хөргөхөөс илүү хурдан шаардлагатай бүтцийг нэмсэн. Бүрэн OOP дэмжлэгийг долоо хоног хүрэхгүй хугацаанд хэрэгжүүлсэн.

Кодын оновчлол

Энд мэдээж илүү сайн хэрэгжиж болох байсан (мөн хэрэгжих болно, гэхдээ дараа нь, үүнийг тойрч ирмэгц). Одоогоор оновчтой болгогч нь угсралтаас ашиглагдаагүй код, тогтмол болон импортыг хэрхэн таслахыг л мэддэг. Мөн ижил утгатай хэд хэдэн тогтмолыг нэгээр солино. Тэгээд л болоо.

Маш хэл

Хэлний тухай үндсэн ойлголт

Гол санаа нь аль болох энгийн хэлийг хөгжүүлэх явдал байв. Хөгжил нь даалгавраа амжилттай даван туулж байна гэж би бодож байна.

Кодын блок, процедур, функцууд

Хэлний бүх бүтэц нь хоёр цэгээр нээгддэг. : бөгөөд оператор хаагдсан байна Төгсгөл.

Процедур болон функцуудыг тус тус proc болон func гэж зарласан. Аргументуудыг хаалтанд жагсаав. Бүх зүйл бусад хэлтэй адил байдаг.

Оператор буцах та функц, оператороос утгыг буцаах боломжтой завсарлагаа Процедур / функцээс гарах боломжийг танд олгоно (хэрэв энэ нь гогцооноос гадуур байвал).

Жишээ код:

...

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

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

Дэмжигдсэн загварууд

  • Гогцоонууд: for..end, while..end, to.. end
  • Нөхцөл: хэрэв..[else..]төгсгөл, солих..[case..end..][else..]төгсгөл
  • Аргууд: proc ():... төгсгөл, func ():... төгсгөл
  • Шошго & очих: :, рүү үсрэх
  • Тооллогууд болон тогтмол массивуудыг тоолох.

Хувьсагчид

Орчуулагч тэдгээрийг автоматаар тодорхойлох боломжтой, эсвэл хөгжүүлэгч тэдгээрийг тодорхойлохын өмнө var бичдэг бол.

Кодын жишээ:

a ?= 10
b ?= a + 20

var a = 10, b = a + 20

Глобал болон орон нутгийн хувьсагчдыг дэмждэг.

OOP байна

За, бид хамгийн амттай сэдэв дээр ирлээ. Mash нь объект хандалтат програмчлалын бүх парадигмуудыг дэмждэг. Тэдгээр. ангиуд, өв залгамжлал, полиморфизм (динамикийг оруулаад), динамик автомат тусгал ба дотоод ажиглалт (бүрэн).

Дэлгэрэнгүй зүгээр л код жишээ өгөх нь дээр.

Энгийн анги, түүнтэй ажиллах:

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

Гарах: 30.

Удамшил ба полиморфизм:

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

Гарах: 60.

Динамик полиморфизмын талаар юу хэлэх вэ? Тийм ээ, энэ бол тусгал!:

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

Гарах: 60.

Одоо энгийн үнэт зүйлс, ангиудыг судалж үзэцгээе:

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

Гаргах: үнэн, үнэн.

Даалгаврын операторууд болон тодорхой заагчийн тухай

?= оператор нь хувьсагчийг санах ойн утга руу заагчаар хуваарилахад хэрэглэгддэг.
= оператор нь хувьсагчийн заагчийг ашиглан санах ойн утгыг өөрчилдөг.
Тэгээд одоо тодорхой заагчийн талаар бага зэрэг. Би тэдгээрийг хэл дээр нэмсэн бөгөөд ингэснээр тэд оршин тогтнох болно.
@ — хувьсагч руу тодорхой заагч авна.
? — хувьсагчийг заагчаар авна.
@= — хувьсагч руу тодорхой заагчаар утга онооно.

Жишээ код:

uses <bf>
uses <crt>

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

Гаргах: зарим тоо, 10, 11.

Оролдоод үз..[барь..][эцэст нь..]Төгсгөл

Жишээ код:

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

РџР »Р ° РЅС <РЅР ° Р ± САРРґЭсарС ‰ РμРμ

Би GraalVM & Truffle-г үргэлжлүүлэн хайж, харсаар байна. Миний ажиллах орчин JIT хөрвүүлэгчгүй тул гүйцэтгэлийн хувьд одоогоор зөвхөн Python-той өрсөлдөхүйц байна. Би GraalVM эсвэл LLVM дээр суурилсан JIT эмхэтгэлийг хэрэгжүүлж чадна гэж найдаж байна.

хадгалах газар

Та бүтээн байгуулалттай тоглож, төслийг өөрөө дагаж болно.

вэб сайт
GitHub дээрх репозитор

Хэрэв уншсан бол дуустал нь уншсан танд баярлалаа.

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх