一个辣鸡的解释器

唔,超过半年没写文章了,懒癌晚期没救了……

这半年还是玩了不少东西的

  • 想学OpenGL,于是从WebGL开始入手

  • 入坑了Haskell,函数式有时候写起来真的很舒服

  • 尝试写一个Parser,就是等下要讲的

总之是学了不少东西,然而每一个都只是浅尝辄止,看到有趣的东西想写点什么又拿不出干货

Lang

最近写了一个解释器,尝试加了一些自己喜欢的语法,兼有 Kotlin 及 Javascript 的一些特征。运行在这个解释器上的语言,就成为 Lang 吧。因为是一个试验性的东西,所以我也懒得给它取名了。

目前已经实现的语法像这样

var a = 4
var b = 6
var c = 5
print(3 * - if(a > b && a > c) a else if(b > c) b else c)
print(abs(-9))

function add(a, b){
   a + b
}
print(add(7, 8))

这是解析出来的语法树及运行结果

var <Name a> = <Number 4>
var <Name b> = <Number 6>
var <Name c> = <Number 5>
<Name print>([<
              <Number 3> * 
              <-if (<<<Name a> > <Name b>> && <<Name a> > <Name c>>>) { <Name a> }
                  else if (<<Name b> > <Name c>>) { <Name b> }
                  else { <Name c> }>
>])
<Name print>([<Name abs>([<-<Number 9>>])])
function add(a, b) {<<Name a> + <Name b>>}
<Name print>([<Name add>([<Number 7>, <Number 8>])])
--------result--------
-18
9
15

从中已经能看出不少语法了

  • 用var声明变量
  • 行末不需要封号,这里有点bug,可能会出现 javascript 不写封号导致解析错误的情况
  • 支持了函数调用
  • if 可以作为一个表达式,我在上一篇文章谈 Kotlin 的时候提到过我很喜欢这种语法
  • 支持了函数定义,不过我还没能实现 return 语句,只能把函数最后一个表达式的值当返回值

其他的从代码中看不出来的

  • 支持单行注释和多行注释
  • 有了类型系统,变量本质上就是个Map,支持从类型上寻找默认值
  • 支持运算符重载,比如 a + b实际上会被解释成a.plus(b),实际上数字的二元运算也是通过这种方式
  • 详细解释一下上面两条,比如 5 + 8,会先被解释成 5.plus(8),由于 5 并没有名为 plus 这个值,因此从 5 的类型 Int 上找,最后在 Int 的父类 Number上找到了 plus,所以最后执行的实际上是 Number.plus.call(5, 8),call同 js ,第一个参数作为 this

作为一个模型来说,我觉得实现了这些功能已经足够了,实际上有好多功能想做暂时做不出来

  • 强类型的匹配,(赋值、函数调用)类型不符合直接报错
  • return语句,要实现这个的话我得先把函数调用栈做了
  • 数组或者 list 的功能
  • 连续的逻辑运算符,比如 0 < a < 10a == b == c
  • 面向对象的支持
  • Lambda

最后

短时间内应该不会再动这个项目了,我感觉Parser这块做的很难看,功能也很差。实现个新的语法让Parser生成抽象语法树得写好多文法,if 表达式的文法就写的很繁琐难以维护。如果下次写的话这一块肯定会重新写一遍Parser的,不过,懒……

恩,祝大家新年快乐。

新年快乐~pid67315228

本文根据 CC BY-NC-SA 4.0 License 协议授权
本文链接:https://blog.gogo.moe/20180218_%E4%B8%80%E4%B8%AA%E8%BE%A3%E9%B8%A1%E7%9A%84%E8%A7%A3%E9%87%8A%E5%99%A8/