LoginSignup
0
0

More than 5 years have passed since last update.

CPythonに後置インクリメントを加えてみた 番外編

Last updated at Posted at 2015-11-25

リンクリスト

全三回プラス番外編になっています。
CPythonに後置インクリメントを加えてみた 概要とまとめ
CPythonに後置インクリメントを加えてみた 実装編
CPythonに後置インクリメントを加えてみた 全変更点一覧
CPythonに後置インクリメントを加えてみた 番外編

番外編:リスト内包表記をHaskellっぽくする

本来インクリメントはリスト内包表記の変更の練習のための課題であった。しかし、インクリメントが設計思想にそぐわないという背景もあってか予想以上にその実装には苦労した。リスト内包表記の変更は構想はともかく、いままでの知識があれば五分ほどで終了する。

まず、変更を独立させるためにこちらはDOSS_INCREMENTではなく、DOSS_HASKELLを用いる。したがってconfigureは以下のようになる。

CFLAGS="-O0 -g -DDOSS_INCREMENT=1 -DDOSS_HASKELL=1" ./configure --prefix="/home/denjo/piyothon_install"

仕様

現状のPythonのリスト内包表記は以下である。

lst = [x for x in range(10) if x >= 5]

一方Haskellは以下である。

lst = [x | x <- [0..9], x >= 5]

改造後のPythonは以下のように表せるようにする。

lst = [x $ x <- range(10), x >= 5]

なおここで|ではなく$を用いているのは、|は論理和としての演算を持っているので、そちらとして認識されてしまうからである。

変更箇所

変更箇所は以下の三箇所のみである。

Grammar
comp_iter: comp_for | comp_if
#ifdef DOSS_HASKELL
comp_for: ('for' | '$') exprlist ('in' | '<-') or_test [comp_iter]
#endif
comp_if: ('if' | ',') test_nocond [comp_iter]
token.h
#ifdef DOSS_INCREMENT
#define INCREMENT 58
#define PRE_INCREMENT 61
#endif
#ifdef DOSS_HASKELL
#define LARROW 59
#define DOLLAR 60
#endif
toknizer.c
case '<':
        switch (c2) {
        case '>':               return NOTEQUAL;
        case '=':               return LESSEQUAL;
        case '<':               return LEFTSHIFT;
        #ifdef DOSS_HASKELL
        case '-':               return LARROW;
        #endif
        }
        break;

変更内容

結局やったことはfor,in,ifの代わりに$,<-,”,”をも許容するようにGrammarを書き換え、トークンを登録しただけである。
因みにこれだけだと、[x**2 $ x in range(10), x % 2 == 0]などという気持ちの悪い書き方もできる。また、,のあとの条件式は,で区切って並べるのではなくandで繋げなければならないのもご愛嬌。

解説

Q. なぜforやinに対して意味を定義していないのに動くのか。forやinのエイリアスになっているのか?

A. そもそもforやinに対して意味は定義されていない。forに対して、forの後にくるトークンは繰り返しに用いる変数で、そのあとにくるトークンは…、と言ったふうに文法の定義がなされているわけではない。forは単なる区切り文字に過ぎず、その後にくるトークンに対していかなる操作を行うか、ということはforに対してではなく、Grammarにおいてforの次にくるもので定義されている。

Grammar
comp_iter: comp_for | comp_if
comp_for: 'for' exprlist 'in' or_test [comp_iter]
comp_if: 'if' test_nocond [comp_iter]

上は書き換える前のリスト内包表記に当たるGrammarの部分である。comp_forを見ると’for’の後にくる語はexprlistとして呼び出されていることが定義されている。また’in’の後はor_testが呼び出されることになっている。したがってどのような定義(構文木がどのように作られ、どのようなバイトコードが実行されるか)は、forやinよりもむしろexprlistor_test、そしてcomp_forに対して定まっていると言える。

余興:前置インクリメントも実装してみる

新たなオペコードUNARY_PRE_INCREMENTを作成し、ceval.cにおいてスタックに積む順番に注意すれば30分もあれば作成することができる。

0
0
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
0
0