参照《Writing An Interpreter/Compiler In Go》,改用C++实现。

项目源码: https://github.com/LeslieZhu/monkey-cpp

引言

实现解释器有很多教程,看了这个基于Go语言的版本后,将采用C++17来重新实现一遍,以体验两种不同编程语言的风格差异。

将采用测试驱动开发(TDD)形式,先写测试用例,再实现代码。

使用的是来自谷歌的gtest(GoogleTest)开源测试框架。

gtest测试框架

安装gtest

把它作为一个单独的第三方库来安装:

$ git clone https://github.com/google/googletest.git # version 1.10.0
$ cd googletest/
$ mkdir build/
$ cd build/
$ cmake ..
$ make 
$ make install

使用gtest

通过CMake来使用(CMakeLists.txt):

cmake_minimum_required(VERSION 3.14)
project(waiicpp)

# GoogleTest requires at least C++14
set(CMAKE_CXX_STANDARD 17)

find_package(GTest)
include_directories(${GTEST_INCLUDE_DIRS})


add_executable(
  hello_test
  test/hello_test.cpp
)

target_link_libraries(
  hello_test
  ${GTEST_BOTH_LIBRARIES}
)

一个简单的测试用例(test/hello_test.cpp):

#include <gtest/gtest.h>

// Demonstrate some basic assertions.
TEST(HelloTest, BasicAssertions) {
    // Expect two strings not to be equal.
    EXPECT_STRNE("hello", "world");
    // Expect equality.
    EXPECT_EQ(7 * 6, 42);
}

直接使用框架定义的一些测试宏,运行:

Running main() from ~/waiicpp/third_party/googletest/src/gtest_main.cc
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from HelloTest
[ RUN      ] HelloTest.BasicAssertions
[       OK ] HelloTest.BasicAssertions (0 ms)
[----------] 1 test from HelloTest (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[  PASSED  ] 1 test.

树遍历解释器

构建的解释性编程语言叫Monkey-CPP,有如下特性:

  • 类C语法
  • 变量绑定
  • 整形和布尔类型
  • 算术表达式
  • 内置函数
  • 头等函数和高阶函数
  • 闭包
  • 字符串
  • 数组
  • 哈希

大概会是这样子:

let age = 1;
let name = "Monkey";
let result = 10 * (20 / 2);

let myArray = [1,2,3,4,5];
let myMap = {"name": "Leslie", "age": 18};

myArray[0]; // => 1
myMap["name"]; // => "Leslie"

// 函数
let add = fn(a, b){ return a + b; };
add(1, 2);

// 递归
let fibonacci = fn(x){
    if(x == 0){
        0 // 分号可以省略
    } else {
        if(x == 1){
            1 // return可以省略
        } else {
            fibonacci(x - 1) + fibonacci(x - 2);
        }
    }
};

//高阶函数
let twice = fn(f, x){
    return f(f(x));
};

let addTwo = fn(x){
    retur x+2;
};

twice(addTwo, 2); // => 6

解释器由如下部分组成:

  • 词法分析器
  • 语法分析器
  • 抽象语法树(AST)
  • 内部对象系统
  • 求值器(Evaluator)

资料