<jupyter_start><jupyter_text>第６章 スモール言語を作る<jupyter_code># !pip install pegtree
import pegtree as pg
from pegtree.colab import peg, pegtree, example
%%peg

Program = { // 開式非終端記号 Expression*
    #Program
} EOF
EOF = !. // ファイル終端

Expression =
    / FuncDecl // 関数定義
    / VarDecl // 変数定義
    / IfExpr  // if 式
    / Binary  // 二項演算<jupyter_output>UsageError: Cell magic `%%peg` not found.<jupyter_text>import pegtree as pgpeg = pg.grammar('chibi.pegtree') parser = pg.generate(peg)  6.2.5 パーザの生成<jupyter_code>import pegtree as pg
peg = pg.grammar('chibi.pegtree') 
parser = pg.generate(peg)<jupyter_output><empty_output><jupyter_text>トランスコンパイラ<jupyter_code>class Visitor(object):
    def visit(self, tree):
        tag = tree.getTag()
        name = f'accept{tag}'
        if hasattr(self, name): # accept メソッドがあるか調べる
            # メソッド名からメソッドを得る 
            acceptMethod = getattr(self, name) 
            return acceptMethod(tree)
        print(f'TODO: accept{tag}') 
        return None

class Compiler(Visitor): # Visitor クラスの継承 
    def __init__(self):
        self.buffers = []
        peg = pg.grammar('chibi.pegtree') 
        self.parser = pg.generate(peg)

    def compile(self, source):
        tree = self.parser(source) # 構文木に交換
        self.buffers = [] # バッファの初期化
        self.visit(tree)
        return ''.join(self.buffers) # バッファを連結してソースコードにまとめる

    def push(self, s): # コード片をバッファに追加
        self.buffers.append(s)
c = Compiler()
code = c.compile('1+2*3') 
print(code)<jupyter_output>TODO: acceptProgram<jupyter_text>各ノードのコード変換<jupyter_code>BUILTIN_FUNCTIONS = { 
    'print': 'console.log'
}

class Compiler(Visitor): # Visitor クラスの継承 
    def __init__(self):
        self.buffers = []
        peg = pg.grammar('chibi.pegtree') 
        self.parser = pg.generate(peg)

    def compile(self, source):
        tree = self.parser(source) # 構文木に交換
        self.buffers = [] # バッファの初期化
        self.visit(tree)
        return ''.join(self.buffers) # バッファを連結してソースコードにまとめる

    def push(self, s): # コード片をバッファに追加
        self.buffers.append(s)

    def acceptProgram(self, tree):
        for child in tree: # 子ノードのリスト
            self.visit(child) # 子ノードの変換 
            self.push('\n') # 改行をバッファに追加

    def acceptInt(self, tree):
        v = tree.getToken()
        self.push(v)

    def acceptName(self, tree):
        name = tree.getToken()
        self.push(name)

    def acceptAdd(self, tree): 
        self.push('(')
        self.visit(tree[0]) 
        self.push('+') 
        self.visit(tree[1]) 
        self.push(')')

    def acceptEq(self, tree): 
        self.push('(')
        self.visit(tree[0]) 
        self.push('===') 
        self.visit(tree[1]) 
        self.push(') ? 1 : 0')

    def acceptFuncApp(self, tree):
        f = tree.getToken(0)
        self.push(BUILTIN_FUNCTIONS.get(f, f)) 
        self.push('(')
        self.visit(tree[1])
        self.push(')')
    
    def accepterr(self, tree):
        print(repr(tree))

c = Compiler()
code = c.compile('''
f(x) = x+1
print(x)
''')
print(code)<jupyter_output>Syntax Error ((unknown source):2:-1+0)<jupyter_text>インタプリタ<jupyter_code>class Interpreter(Visitor):
    def __init__(self):
        self.env = {} # 空の環境を用意する 
        peg = pg.grammar('chibi.pegtree') 
        self.parser = pg.generate(peg)
    
    def eval(self, source):
        tree = self.parser(source)
        return self.visit(tree)
chibi = Interpreter() 
source = input('>>> ') 
while source != '':
    result = chibi.eval(source) 
    print(result)
source = input('>>> ')
class Interpreter(Visitor):
    def __init__(self):
        self.env = {} # 空の環境を用意する 
        peg = pg.grammar('chibi.pegtree') 
        self.parser = pg.generate(peg)
    
    def eval(self, source):
        tree = self.parser(source)
        return self.visit(tree)

    def acceptProgram(self, tree):
        result = None
        for child in tree:
            result = self.visit(child)
        return result
    
    def acceptInt(self, tree):
        token = tree.getToken()
        return int(token)

    def acceptAdd(self, tree):
        v0 = self.visit(tree[0])
        v1 = self.visit(tree[1])
        return v0 + v1

    def acceptEq(self, tree):
        v0 = self.visit(tree[0])
        v1 = self.visit(tree[1])
        return 1 if v0 == v1 else 0

    def acceptIfExpr(self, tree):
        v0 = self.visit(tree[0])
        if v0 != 0:
            return self.visit(tree[1])
        else:
            return self.visit(tree[2])

    def acceptVarDecl(self, tree):
        v = self.visit(tree[1])
        x = str(tree[0])
        self.env[x] = v
        return v
    
    def acceptName(self, t):
        x = t.getToken()
        if x in self.env:
            return self.env[x]
        else:
            raise NameError(x)

    def acceptFuncDecl(self, tree):
        f = tree.getToken(0)
        x = tree.getToken(1)
        e = tree.get(2)
        self.env[f] = (x, e)
        return self.env[f]

    def acceptFuncApp(self, tree):
        f = tree.getToken(0) # 関数名を得る
        v = self.visit(tree[1]) # 引数を先に評価
        x, e = self.env[f] # 関数名から引数名と関数式を取り出す 
        self.env[x] = v # 環境xをvにする
        v = self.visit(e) # 関数式を評価
        return v
source = '''
fib(n) = if n < 3 then 1 else fib(n-1)+fib(n-2) 
fib(4)
'''
c = Interpreter()
print(c.eval(source))<jupyter_output>TODO: accepterr
None
{'fraction_non_alphanumeric': 0.13866017964071856, 'fraction_numerical': 0.009543413173652695, 'mean_word_length': 2.2671149144254277, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '2601', 'license': 'MIT', 'n_tokens_mistral': 2136, 'n_tokens_neox': 2098, 'n_words': 383, 'path': 'pegbook_chap6.ipynb', 'repo_name': 'kkuramitsu/pegbook2021', 'size': '5344'}