ardggy's blog

Esc - Meta - Alt - Ctrl - Shift

範囲を生成するようなあれ(パース編)

きのうのつづきで範囲構文を解析することにする。

パーサはさくっと構文解析ライブラリにまかせる。 python パーサ で検索しただけだけど、BNF っぽく書けることで雑に採用。 もっとも BNF がこれでいいのかは自信がないが、doctest が通ってるしいいことにしよう。

github.com

$ sudo easy_install pip
$ sudo pip install lark-parser

チュートリアルを眺めつつ、こんなかんじで書けた。

#!/usr/bin/env python
# coding: utf-8
'''
>>> list(parse("1"))
[1]

>>> list(parse("1,2"))
[1, 2]

>>> list(parse("1,2,5-7"))
[1, 2, 5, 6, 7]

>>> list(parse("1,2,5-7,9-10,13"))
[1, 2, 5, 6, 7, 9, 10, 13]
'''

import itertools
from lark import Lark, Transformer, v_args

@v_args(inline=True)
class RangeSyntax(Transformer):
    concat = itertools.chain

    def constant(self, x):
        return itertools.repeat(int(x), 1)

    def range(self, start, end):
        return xrange(int(start), int(end) + 1)

parser = Lark('''
?expr : expr "," expr     -> concat
      | NUMBER "-" NUMBER -> range
      | NUMBER            -> constant

%import common.NUMBER
%import common.WS
%ignore WS
''', start='expr', parser='lalr', transformer=RangeSyntax())

parse = parser.parse

if __name__ == '__main__':
    import doctest
    doctest.testmod()