Scalaの勉強をはじめました。
で、なんかパーサーコンビネータというのがあるらしく、パーサーが簡単に作れるらしく、じゃあパーサー作ってみるのがScalaの勉強にいいんじゃないかということで、簡単なパーサーを作ってみることにします。
とりあえず構文定義してみます。
今回つくるのは、整数の計算をするパーサーってことにします。整数と、+/-、*、あと()くらいが使えるものにします。割り算を入れないのは、そこは単純に処理を付け加えれば実現できるから。
式の優先順位と、同じ優先度に複数の演算子があればいいってことにします。あと、単項演算子も使いません。めんどうだから。
実装方針は「ソースコードが増えないこと」です。
JavaTokenParsersを使うと、Javaのリテラル表記がそのまま使えるパーサーが作れるらしいんですけど、構文を全部自分で定義したい病気なので、その一階層上のRegexParsersを使います。
実行して「12-5*3+7*(2+5)+0」をパースするとこんな感じになって、構文の解釈ができてる感じですね。
[1.17] parsed: ( (12~List())~List( (-~(5~List( (*~3)))), (+~(7~List( (*~( ( (~( (2~List())~List( (+~(5~List())))))~)))))), (+~(0~List()))))
というか、Lispに変換されたw
package parser import util.parsing.combinator._ object MiniParserMain { def main(args: Array[String]): Unit = { val parser = new MiniParser println(parser.parse("12-5*3+7*(2+5)+0")) } class MiniParser extends RegexParsers{ //expr ::= term ["+" term | "-" term}. def expr: Parser[Any] = term~rep("+"~term|"-"~term) //term ::= factor {"*" factor} def term : Parser[Any] = factor~rep("*"~factor) //factor ::= intLiteral | "(" expr ")" def factor: Parser[Any] = intLiteral | "("~expr~")" //intLiteral ::= ["1"-"9"] {"0"-"9"} def intLiteral : Parser[Any] = """[1-9][0-9]*|0""".r def parse(str:String) = parseAll(expr, str) } }
参考にしてるのは、このあたり。
多忙な Java 開発者のための Scala ガイド: 電卓を作る、第 2 回
パーサーコンビネータで遊んでみた - じゅんいち☆かとうの技術日誌
読んだほうがよさげなのが水島さんの記事
第17回 Scalaとパーザコンビネータ(基本編) | 日経 xTECH(クロステック)
第18回 Scalaとパーザコンビネータ(実装編) | 日経 xTECH(クロステック)
あと、「コップ本」の2版。初版も持ってたけど放置してるうちに2版でちゃった。
- 作者: Martin Odersky,Lex Spoon,Bill Venners,羽生田栄一,水島宏太,長尾高弘
- 出版社/メーカー: インプレス
- 発売日: 2011/09/27
- メディア: 単行本(ソフトカバー)
- 購入: 12人 クリック: 235回
- この商品を含むブログ (46件) を見る