Go言語でつくるインタプリタを写経した話

公開日

2025-01-10 10:44

トピック

インタープリタ, プログミング

Zenn

https://zenn.dev/fkzwsoftwaredev/articles/e7844d09397564

本

レポジトリ

動機

  • OS、コンパイラ作れるってかっこいい

  • 趣味なので、WEB以外のプログミングがしたい

  • 2018年プログラミング言語Goを読んだ直後あたりに発売されて飛びついた。

    • その後、仕事が忙しくなったり、途中で理解できなくなって断念。

    • 今回は、まず完走することを最優先とした

      • 何度かレポジトリを新しくして、2024年年末に完走。

本書でやること

  • Go言語を用いて、C言語風(JS風?)な構文のMonkeyプログミング言語を実行できるインタープリタを作っていく

    • Go言語のサードパーティライブラリは使用していない

    • テスト駆動で開発を進めていく

  • Monkeyプログミング言語の特徴

    • C言語風(JS風?)な構文

    • 変数束縛

    • サポートするデータ型

      • 整数

      • 真偽値

      • 文字列

      • 配列

      • ハッシュ(辞書)

    • 算術式

    • 組み込み関数

    • 変数に束縛する形での関数定義

    • クロージャ

  • インタープリタの機能を実装していく

    • トークン(データ型、予約語やソースコードの中に出てくる記号(+,-))などの定義

    const (
        ILLEGAL = "ILLEGAL" // 規則違反
        EOF     = "EOF"     // ファイルの終端
    
        // 識別子(変数名・関数名) : ユーザが宣言する名前
        IDENT = "IDENT"
    
        // リテラル : 扱うデータの型
        INT    = "INT"
        STRING = "STRING"
    
        // 演算子 : 使用できる演算子
        ASSIGN   = "="
        PLUS     = "+"
        MINUS    = "-"
        BANG     = "!"
        ASTERISK = "*"
        SLASH    = "/"
    
        // 比較演算子 : 使用できる比較演算子
        EQ     = "=="
        NOT_EQ = "!="
        LT     = "<"
        GT     = ">"
    
        // デリミタ(区切り文字) : コード上の区切り文字
        COMMA     = ","
        SEMICOLON = ";"
    
        LPAREN = "("
        RPAREN = ")"
    
        LBRACE = "{"
        RBRACE = "}"
    
        LBRACKET = "["
        RBRACKET = "]"
    
        COLON = ":"
    
        // キーワード : コード上で使用する予約語
        FUNCTION = "FUNCTION" // 関数定義
        LET      = "LET"      // 変数定義
        TRUE     = "TRUE"     // 真
        FALSE    = "FALSE"    // 偽
        IF       = "IF"       // 構文構造使用: 条件分岐
        ELSE     = "ELSE"     // 構文構造使用: 条件分岐
        RETURN   = "RETURN"   // 構文構造使用: 関数からの戻り値
    )
    
    // トークンを表す構造体
    type Token struct {
        Type    TokenType // トークンの種類
        Literal string    // トークン文字列( 変数名 や + , - などの文字列 )
    }
    
    // 予約語のマップ
    // .. 予約語は、言語の構文構造に使用するキーワード
    // .. 予約語は、変数名や関数名として使用できない
    var keywords = map[string]TokenType{
        "fn":     FUNCTION,
        "let":    LET,
        "true":   TRUE,
        "false":  FALSE,
        "if":     IF,
        "else":   ELSE,
        "return": RETURN,
    }
    
    • 字句解析器の実装

      • 入力 : ソースコード

      • 出力 : トークン列

    • 構文解析器の実装

      • 入力 : トークン列

      • 出力 : 抽象構文木

    • 評価器の実装

      • 入力 : 抽象構文木

      • 出力 : ソースコードの命令の実行

2025年〜2026年 でやりたこと