2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonで実現するInterpreterパターン:独自言語・DSLの構文解析と評価

Posted at

概要

Interpreterパターンは、
特定の文法ルールを持つ言語(または式)を、構造として解釈し、実行・評価できる仕組みを構築するパターンである。

本パターンは、DSL(ドメイン固有言語)や構文木の構築、
ミニスクリプト、ルールエンジンの実装など、「言語のような構造」を定義する際に非常に有効である。


1. なぜInterpreterが必要か?

❌ if/elif/else で全てを解析・評価

if expr == "a + b":
    return a + b
elif expr == "a - b":
    return a - b

→ 条件分岐の羅列でロジックが硬直化し、拡張不能・再利用不能


✅ 「構文ルール」「構文木」「解釈」を構造として分離

Expression = Add(Variable("a"), Variable("b"))
context = {"a": 3, "b": 5}
result = Expression.interpret(context)  # 8

ルールベースで柔軟に解釈可能な言語構造が完成


2. 基本構成

✅ 抽象構文(Expressionインタフェース)

class Expression:
    def interpret(self, context):
        raise NotImplementedError

✅ 具体的構文ノード

class Number(Expression):
    def __init__(self, value):
        self.value = value

    def interpret(self, context):
        return self.value

class Variable(Expression):
    def __init__(self, name):
        self.name = name

    def interpret(self, context):
        return context[self.name]

class Add(Expression):
    def __init__(self, left, right):
        self.left = left
        self.right = right

    def interpret(self, context):
        return self.left.interpret(context) + self.right.interpret(context)

class Subtract(Expression):
    def __init__(self, left, right):
        self.left = left
        self.right = right

    def interpret(self, context):
        return self.left.interpret(context) - self.right.interpret(context)

✅ 実行例:式の構築と評価

# 式: (a + 5) - b
expr = Subtract(
    Add(Variable("a"), Number(5)),
    Variable("b")
)

context = {"a": 10, "b": 3}
print(expr.interpret(context))  # → 12

3. Python的応用:再帰構文評価と構造の自動生成

✅ 再帰評価により、入れ子の式にも対応可能

expr = Add(
    Add(Number(1), Number(2)),
    Subtract(Number(10), Number(4))
)
print(expr.interpret({}))  # → 1+2+(10-4) = 9

✅ 構文ツリーの自動構築(例:簡易パーサー)

def parse(tokens):
    stack = []
    for token in tokens:
        if token.isdigit():
            stack.append(Number(int(token)))
        elif token in ["+", "-"]:
            right = stack.pop()
            left = stack.pop()
            if token == "+":
                stack.append(Add(left, right))
            else:
                stack.append(Subtract(left, right))
    return stack[0]
expr = parse(["3", "4", "+", "2", "-"])
print(expr.interpret({}))  # → 3 + 4 - 2 = 5

4. 実務ユースケース

✅ DSL(ドメイン固有言語)の構文解釈

  • ワークフロー定義、UI条件記述、データ変換DSLの解析器に応用可能

✅ ルールベースのフィルタ・スクリプト実行

expr = And(Equals(Variable("type"), Number(1)), GreaterThan(Variable("score"), Number(80)))

→ 組織内評価ロジックや検閲フィルターの柔軟定義が可能


✅ SQL風構文の解釈・トランスパイル基盤

→ SELECTやWHERE節のような構文をクラス構造として再現・評価


5. よくある誤用と対策

❌ 構文ノードに解釈以外の責務が混在

→ ✅ interpret() のみに責務を集中し、出力や副作用は他に委譲


❌ ノード数が膨大になりメンテ困難

→ ✅ 共通演算を Mixin などで抽象化し、構文木設計をモジュール化


❌ 表現力を追い求めすぎて本末転倒

→ ✅ Interpreterパターンはあくまで「小さな言語」向き
→ 巨大な構文は パーサジェネレータやAST解析ツールの方が適切


結語

Interpreterパターンとは、「ロジックをコードではなく構文として記述する」ための設計哲学である。

  • DSLの実行基盤や構文木の定義が容易に
  • 柔軟かつテスト可能な評価機構の構築
  • 複雑なロジックも、「構文」としての操作対象に抽象化可能

Pythonicとは、“振る舞いを操作可能な構造に変える”ことであり、
Interpreterパターンはその構造設計において、柔らかくも強靭な言語的解釈力を与える。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?