LoginSignup
6
7

More than 3 years have passed since last update.

Lark基本解説 (Python, Larkでシェルっぽいやつをつくる)

Last updated at Posted at 2019-12-10

まず

筆者はプログラミング初心者、かなり無知マンなので、様々な名称を知らず、"***なやつ"等曖昧な表現が用いられますがご容赦ください。

やることとか

bashライクな書き方で動作するやつ(なんて言うのかしらない)をつくりたい!のでつくりました。

作成したプログラムは、例えば次のようなスクリプトを解析・実行して結果を返します

rand -s3 a b c + say def | replace e E

(結果は例えばb a cdEfのようになります)

この記事では、具体的な処理は割愛し、簡単にLarkの使い方を解説していこうと思います。


使用しているライブラリ
Lark - a modern parsing library for Python


文法規則ファイルの作成

まずパーサジェネレータに渡す、文法規則を記述したテキストファイルを作成します。
今回の場合は、
scriptは1つ以上のchunkjoinで繋がれたもので、
chunkは1つ以上のsentencepipeで繋がれたもので...
といった具合に記述していきます。

Grammar.lark
script : [chunk join] chunk

chunk : [(sentence pipe)+] sentence

sentence : command [space option] [(space arg)+] [/\n+/]

command : chars
        | ([chars] subshell [chars])+
option : "-" (chars|subshell)+
arg : chars
    | "'" allchars "'"
    | ([chars] subshell [chars])+

subshell : "(" script ")" [/\n+/]

chars : /[^\+\|\s\(\)']+/[/\n+/]
allchars : /[^']+/[/\n+/]
space : " "
join : [space] "+" [space]
pipe : [space] "|" [space]

パーサの作成

パーサの作成の仕方です。先ほど作成したテキストファイルを読み込んで、Larkに渡すだけです。

パーサ作成部分
from lark import Lark

with open("Grammar.lark",encoding="utf-8") as grammar:
    LP = Lark(grammar.read(),start="script")

Lark()の第2引数start=には、いちばん外側の構成要素を書いておきます(たぶん)。

このパーサで試しにrand -s3 a b c + say def | replace e Eを解析してみましょう。
解析結果ツリーのpretty()メソッドで、可読性を高く表示できますので、これを使いましょう。

パーサのテスト
tree = LP.parse("rand -s3 a b c + say def | replace e E")
print(tree.pretty())
結果
script
  chunk
    sentence
      command
        chars   rand
      space
      option
        chars   s3
      space
      arg
        chars   a
      space
      arg
        chars   b
      space
      arg
        chars   c
  join
    space
    space
  chunk
    sentence
      command
        chars   say
      space
      arg
        chars   def
    pipe
      space
      space
    sentence
      command
        chars   replace
      space
      arg
        chars   e
      space
      arg
        chars   E

(あれ?spaceなんかおかしくね?まいっか処理に使わないし...)

トランスフォーマの作成

では、解析したツリーの様子に応じて処理を実行する部分を作っていきましょう。

トランスフォーマ作成部分
from lark import Transformer

class mytransformer(Transformer):
    def __init__(self): # 適宜使用する変数などを初期化
        self.var1 = None
        self.var2 = []

    def sentence(self,tree): # 第二引数を取るとsentence以深のツリーが使える!
        print("sentence") # example

    def command(self,tree):
        print("command")

    def option(self,tree):
        print("option")

argchunkなどの処理は省略して記載しました。
mytransformer内で定義したsentencecommandoptionなどは、深度優先で呼び出されます。なので、この例では
command -> option -> sentenceといった順に処理が行われます。

トランスフォーマの使い方ですが、

トランスフォーマの使い方
tree = LP.parse("rand -s3 a b c + say def | replace e E")
mytransformer().transform(tree)

のようにして使用します。

最後に

以上、簡単にLarkについて解説させて頂きました。

初心者がどうにかこうにか頑張ったものなので、誤り等あるかと思います。誤りを発見した場合はコメント等いただけると助かります。

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