几年来,我一直在尝试开发自己的编程语言。 我认为我想创造最简单,功能最全,最方便的语言。
在本文中,我想强调我的工作的主要阶段,并首先描述该语言的创建概念及其当前正在使用的第一个实现。
我会事先说我用Free Pascal编写了整个项目,因为 它上的程序可以为大量平台组装,并且编译器本身会生成非常优化的二进制文件(我使用O2标志收集项目的所有组件)。
语言运行时
首先要谈的是虚拟机,我必须编写该虚拟机才能使用我的语言运行将来的应用程序。 我决定实施一个堆栈体系结构,也许是因为这是最简单的方法。 我没有找到一篇普通的俄语文章,所以在阅读了英语材料之后,我坐下来设计和编写了我的自行车。 此外,我将在这件事上给出我的“高级”思想和发展。
堆栈实施
显然,虚拟机位于堆栈的顶部。 在我的实现中,它按块工作。 本质上,这是一个简单的指针数组和一个用于存储栈顶索引的变量。
初始化后,将创建一个包含256个元素的数组。 如果将更多的指针抛出到堆栈上,则其大小将增加下一个256个元素。 因此,当从堆叠中取出物品时,其尺寸是可调节的。
VM使用多个堆栈:
- 主堆栈。
- 用于存储返回点的堆栈。
- 堆栈的垃圾收集器。
- try / catch / finally块的堆栈处理程序。
常量和变量
这样,一切都很简单。 常数在单独的一小段代码中进行处理,以后可在应用程序中以静态地址使用。 变量是一定大小的指针数组,通过索引来访问其单元格-即 静态地址。 变量可以放在堆栈的顶部或从堆栈的顶部读取。 其实是因为 我们的变量实际上将指向值的指针存储在VM的内存中,然后使用该语言中占主导地位的隐式指针。
垃圾收集器
在我的VM中,它是半自动的。 即 开发人员决定何时调用垃圾回收器。 根据相同的Python,Perl,Ruby,Lua等指针指针,它无法正常工作。 它是通过标记系统实现的。 即 当理解为变量分配了一个临时值时,会将指向该值的指针添加到垃圾回收器堆栈中。 将来,收集器会快速浏览一个已经准备好的指针列表。
处理try / catch / finally块
与任何现代语言一样,异常处理是其中的重要组成部分。 VM的内核包装在try..catch块中,该块可以在捕获异常之后通过在堆栈上放置一些有关它的信息来返回代码的执行。 在应用程序代码中,您可以指定try / catch / finally代码块,指示要捕获的入口点(异常处理程序)和finally / end(块结束)。
多线程
在VM级别受支持。 它简单易用。 它无需中断系统即可工作,因此代码必须分别在多个线程中运行快几倍。
VM的外部库
没有它是没有办法的。 VM支持导入,就像它以其他语言实现一样。 您可以使用Mash编写部分代码,也可以使用本地语言编写部分代码,然后将它们链接在一起。
从高级语言Mash转换为VM的字节码
中级语言
为了快速将翻译器从复杂的语言编写为VM代码,我首先开发了一种中间语言。 原来,这是一个类似于汇编程序的可怕外观,在这里没有特殊的意义。 我只能说,在此级别上,转换器处理大多数常量,变量,计算其静态地址和入口点的地址。
翻译器架构
我选择的不是最佳实施架构。 转换器不像其他转换器那样构建代码树。 他看着施工的开始。 即 如果解析的代码看起来像“ while <condition>:”,那么很明显这是循环的while结构,需要将其作为while循环结构进行处理。 有点像复杂的开关盒。
由于采用了这种架构解决方案,翻译器的速度不是很快。 但是,其改进的简单性已大大提高。 我添加了必要的设计,速度比咖啡冷却的速度还快。 在不到一周的时间内就实现了对OOP的全面支持。
代码优化
当然,在这里,可以实现得更好(并且可以实现,但是稍后,随着手的伸出)。 到目前为止,优化器只知道如何从程序集中切断未使用的代码,常量和导入。 同样,几个具有相同值的常量将替换为一个。 仅此而已。
混搭语言
语言的基本概念
主要思想是开发功能最简单的语言。 我认为,发展可以应付其任务。
代码块,过程和功能
语言中的所有构造都以冒号
:开头,并由
最终运算符关闭。
过程和函数分别声明为proc和func。 参数在括号中列出。 就像大多数其他语言一样。
return语句可以从函数返回值,
break语句使您可以退出过程/函数(如果它在循环之外)。
代码示例:
...
func summ(a, b):
return a + b
end
proc main():
println(summ(inputln(), inputln()))
end
- : for..end, while..end, until..end
- : if..[else..]end, switch..[case..end..][else..]end
- : proc <>():… end, func <>():… end
- Label & goto: <>:, jump <>
- Enum .
, var .
:
a ?= 10
b ?= a + 20
var a = 10, b = a + 20
.
. 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
: true, true.
?= .
= .
. .
@<> — .
?<> — .
@= — .
:
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.
Try..[catch..][finally..]end
:
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 , . , JIT GraalVM LLVM.
.
GitHub, , .