Help us understand the problem. What is going on with this article?

PLYで簡単な言語をつくってみるよ1

More than 3 years have passed since last update.

はじめに

背景

  • 言語つくるの面白そうという興味
  • LLVMに今興味を持っていて字句解析・構文解析は興味があった
  • CもC++も書けなかったがpythonは触ったことがあった

 PLYとは

  • Pythonの字句解析/構文解析ライブラリ
  • 以下をpythonで実装し、まとめたもの
    • 字句解析器lex
    • 構文解析器yacc

準備

PLYのインストール

$ pip install ply
  • python3・python2両方に対応してるっぽい
  • python3.6では問題があるっぽい?githubのissueにそれっぽいことが...

今回実装するものを決める

  • 変数
  • コンソールを終了する関数
    • とりあえず名前はexitとする
  • 文字をコンソールに表示する関数
    • とりあえずputとする
  • コメントは#から
  • タブ・スペースは無視する

実装

字句解析

  • 今回作成したコードを以下に示す
lex.py
import ply.lex as lex

tokens = (
  # Literals
  'ID',

  # Function
  'PUT', 'EXIT',
)

# Identifiers at var
t_ID = r'(?!put|exit)[A-Za-z_][A-Za-z0-9_]*'

# Function
t_PUT = r'put'
t_EXIT = r'exit'
# space is ignore

# space and tab is ignore
t_ignore = ' \t'

# comment  
t_ignore_COMMENT = r'\#.*'

# error handling
def t_error(t):
    print("不正な文字 '%s'" % t.value[0])
    t.lexer.skip(1)

#
lex.lex(debug=0)

  • token = ( )
    • カッコの中に解析したい要素を
  • 字句解析のルール
    • 正規表現で表す
    • 命名規則はt_トークン名
    • t_ignoreは文字列をスキップ
    • t_ignore_COMMENTはコメントを定義できる
    • t_errorはマッチしなかったとき呼び出される
    • lex.lex()でビルド
  • 正規表現がよくわかっていないので割とごり押しになってます
    • 綺麗に正規表現で書けるようになりたい(勉強するする詐欺)

構文解析

以下に作成したコードを示す

yacc.py
import ply.yacc as yacc
from lex import tokens
import sys

names = {}

# var (id)
def p_expr_id(p):
    'expr : ID'
    try:
        p[0] = names[p[1]]
    except LookupError:
        print('Undefine var name %s' %p)
        p[0] = 0

# exit function
def p_exit(p):
    'expr : EXIT'   
    print('See You!')
    sys.exit()

# empty
def p_empty(p):
    'empty :'
    pass

# syntax error
def p_error(p):
    print ('Syntax error in input %s' %p)

parser = yacc.yacc()

# Debug
def parse(data, debug=0):  
    return yacc.parse(data, debug=debug)

if __name__ == '__main__':  
    while True:
        try:
            s = input('>>> ')
        except EOFError:
            break
        if not s:
            continue
        result = parser.parse(s)
        print (result)
  • names = {}
    • 変数名と値を格納するためのdictionary
  • p_expr_id
    • ID(p[1])を変数名としてexpr(p[0])に
    • 'expr : ID は p[0]: p[1]で渡される
  • p_exit
    • See You!と表示してコンソールを終了する
    • pythonのsys.exit()関数が使える
  • Debug
    • 割愛

動かしてみる

実は変数を定義したが現状何もできない
できるのはexit関数を試すぐらいだ

実行は

$ python yacc.py
>>> exit
See You!
$

おわりに

何となくそれっぽい画面になってexitで抜けれた
最後のほう説明がざつになってきた

参考にしたもの

PythonでPPAP(ペンパイナッポーアッポーペン)をイメージしたオリジナル言語 「PPAPScript」を作ってみたryo-ma.

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away