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なのに特に実績とかなくてちょっとヘコんでるんだよね・・・