2018年も終わろうとしているし平成ももうすぐ終わるのだが,いまだに俺の開発環境(emacs)ではperlをうまく補完することができない.
とはいえdabbrevの類を使っているのでそこそこの補完は動いているのでそこはいいのだが,Smart::Argsの引数をよく間違えて時間をとられる,といった事がよくあった.
Emacs上に,これから呼ぼうとしているサブルーチンの引数をうまく表示してやれたらいいなと思い,ひとまず今はS::Argsを使ったサブルーチンをパースするコードを書いている.
言語
Common Lispを使っている.言語処理に使われた実績があるし,パーサも豊富だ.そもそも俺の好みだというのが一番大きそう.
今回はESRAP-PEGパッケージを使って,PEG文法ファイルからPEGパーサジェネレータを介してパーサを作成し,これに読み取らせようとしている.
なにやら大袈裟かもしれないが敢えて正規表現を使わないのは,正規表現だと複雑になりすぎてメンテナンスできそうもないと思ったからだ.
コードのサンプルとして以下のサイトを参考にした.
PEG文法ファイル
こういった内容になっている.このファイルをESRAP-PEGに食わせると,ESRAPが理解可能なPEG文法のインスタンスが作成され,ESRAPがパーサを生成する.
このファイルを使わない場合は,ESRAPに直にS式でPEG文法を指示する必要があり,ちょっと面倒.
alpha <- [a-zA-Z]
number <- [0-9]
colon <- ':'
semicolon <- ';'
comma <- ','
spaces <- [ \t\n]+
fatcomma <- '=>'
leftbracket <- '['
rightbracket <- ']'
leftbrace <- '{'
rightbrace <- '}'
dollar <- '$'
string <- (["] (!["] .)* ["]) / (['] (!['] .)* ['])
...
argsdefinition <- spaces? (argsheading / argsposheading) spaces? (onearg spaces? comma spaces?)* (onearg spaces?)? semicolon spaces?
argsheading <- 'args'
argsposheading <- 'args_pos'
my <- 'my'
onearg <- my spaces? variable spaces? fatcomma spaces? argtype
variable <- dollar (alnumsign)+
alnumsign <- alpha / number / underscore
underscore <- '_'
argtype <- simpleargtype / argtypeobject
simpleargtype <- '\'' type '\''
type <- (alpha / colon colon / leftbracket / rightbracket)+
argtypeobject <- leftbrace spaces? (argtypedefinition spaces? comma spaces?)* argtypedefinition spaces? rightbrace
argtypedefinition <- alpha+ spaces? fatcomma spaces? (string / number+)
パースするコード
まだ未完なので完動するコードはまだないが,完成したら動くものをどこかに公開したい.以下に示しているのは,ファイルのストリームからサブルーチンをとりだそうとしているコード.きたねーッ!!
(defun extract-subs-from-stream (s) (let ((sub nil) (lines nil) (sub-string-map nil)) (flet ((after-sub-p () sub) (pack-lines () (setf sub-string-map (acons sub (format nil "~{~A~^ ~}" (take-to-last-argument (reverse lines))) sub-string-map)) (setf lines nil)) (wipe-lines () (setf lines nil)) (enter-sub (sub-now) (setf sub sub-now)) (append-line (line) (setf lines (cons line lines)))) (iter (initially line nil) (for line next (read-line s nil :eof nil)) (when (eq line :eof) (when (after-sub-p) (pack-lines)) (return-from extract-subs-from-stream sub-string-map)) (let ((subname-or-nil (extract-sub-heading-line line))) (if subname-or-nil (progn (if (after-sub-p) (pack-lines) (wipe-lines)) (enter-sub subname-or-nil)) (append-line line)))))))
想い
lispで何か書いてもあまり注目されないんだよね・・・
まあそもそもパーサ書いてもそんな注目されなくて,サービスを作って公開するのがいいのかなって思うんだよね・・・
フォロワーのポートフォリオ見てビビっちゃったよ・・・俺25なのに特に実績とかなくてちょっとヘコんでるんだよね・・・