这两个阶段的词法和语法解析通常指的是作为前端的编译器和解释器。现在,让我们开始写一些代码,我将使用GO来编写。所有的源代码将公布在我的 Github页面上。如果你接着使用GO来编写,首先为你的项目建立一个新的目录并且设置好你的main go文件。刚好,我编写了一个简单的hello world文件来进行测试。GO拥有一个神奇的工作空间系统,因此一开始,你就需要创建你的工作空间,我一直使用Linux来作为我的工作空间,因此我使用GO设置$HOME/go 的环境变量。为方便起见,GO推荐我们增加这个设置到达我们的路径: mkdir $HOME/go export PATH=$PATH:$GOPATH/bin 我的项目的基本路径是在 github.com/felixangell。 你可以找到你想要的,或者你的 github 用户名: mkdir -p $GOPATH/src/github.com/yourusername 现在开始设置我们的解释器程序,我们在个人目录下创建一个文件夹,名字可以是你给这个解释器起的任何名字,我叫它 vident。我们进入这个目录。
然后我们创建一个简单的文件作为测试用,可以直接拷贝这一部分:
把他保存到我们刚刚建立的文件夹 vident 中,名字为 main.go。现在我们编译并运行它:
因为我们正在用工程目录结构系统,我们需要添加 bin 目录到我们的目录,然后简单的运行上面的代码。当你运行时,你应该可以看到输出了“hello, world”。 那么接下来我们要定义我们的语言。Vident 是一门简单的语言,我们从一些小的特性入手,然后我们再转移到复杂的示例。下面是 Vident 的一个代码实例: let x = 5 + 5 print: x, "hello", x 我需要把->改为:,否则熟悉 Tumblr 格式的人对它很多抱怨,抱歉!我们语言的 EBNF 语法: letter = "A" | "a" | ... "Z" | "z" | "_"; digit = { "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" }; identifier = letter { letter | digit }; number_literal = digit | [ "." digit ]; string_literal = """ letter { letter } """; char_literal = "'" letter "'"; literal = number_literal | string_literal | char_literal; binaryOp = "+" | "-" | "/" | "*"; binary_expr = expression binaryOp expression; expression = binary_expr | function_call | identifier | literal; let_stat = "let" identifier [ "=" expression ]; arguments = { expression "," }; function_call = identifier [ ":" arguments ]; statement = let_stat | function_call; 目前我们已经为这门语言引入了一些东西,最明显的是方括号。方括号表示一个可选值,例如: let_stat = "let" identifier [ "=" expression ]; 这代表 let x 和 let x = 5 + 5 都是有效的,第一个是一个定义,比如定义变量,第二是显示的变量声明,即定义变量并声明值。 现在看上面的语法可能会有点复杂,但如果你一点点的靠近去理解它,它就会比你想象的更加简单. 注意,我们不会一下就全部实现它,而是按阶段分部分去着重于语法的每一个部分并进行实现! 不管怎么样,如上就是第一部分! 敬请关注接下来的章节,我们将会编写词法分析器,而我们也会讨论更多有关解释器后端的内容. |