#はじめに
背景
- 言語つくるの面白そうという興味
- 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.