以前作ったScalaのtoyプログラム色々眺めてたら、なんか発掘されたので、せっかくなので貼っておく。
object ぴーいーじーぱーざこんびねーた { type 構文規則 = 構文解析器[Any] abstract class 構文解析器[+A] extends (String => Option[(A, String)]) { def または[B >: A](that: => 構文解析器[B]): 構文解析器[B] = parserOf{in => this(in) orElse that(in) } def の次に[B](that: => 構文解析器[B]): 構文解析器[(A, B)] = parserOf{in => for((r1, rest1) <- this(in); (r2, rest2) <- that(rest1)) yield ((r1, r2), rest2) } def に次を適用する[B](f: A => B): 構文解析器[B] = parserOf{in => for((r, rest) <- this(in)) yield (f(r), rest) } def が0回または1回 : 構文解析器[Option[A]] = parserOf{in => this(in).map{p => (Some(p._1), p._2)}.orElse(Some(None, in)) } def が0回以上 : 構文解析器[List[A]] = parserOf{in => def parse(in: String) : (List[A], String) = { this(in) match { case Some((r, rest)) => val (r2, rest2) = parse(rest); (r::r2, rest2) case None => (Nil, in) } } Some(parse(in)) } def が1回以上 : 構文解析器[List[A]] = (this の次に (this が0回以上)) に次を適用する {p => p._1::p._2} def 以外を先読み : 構文解析器[Unit] = parserOf{in => this(in) match { case Some(_) => None case None => Some((), in) } } def を先読み: 構文解析器[Unit] = (this 以外を先読み) 以外を先読み } def 文字列(param: String): 構文解析器[String] = parserOf{in => if(in startsWith param) Some(param, (in substring(param length))) else None } lazy val どれでも1文字: 構文解析器[String] = parserOf{in => if(in.length > 0) Some(in substring(0, 1), in substring 1) else None } def parserOf[A](f: String => Option[(A, String)]): 構文解析器[A] = new 構文解析器[A] { def apply(param: String): Option[(A, String)] = f(param) } implicit def 文字列からパーザへ(param: String) = 文字列(param) }
利用側は次のような感じ。あ^n い^n う^n(n > 0)という言語を表現するPEGの構文規則。
import ぴーいーじーぱーざこんびねーた._ object ゆーざ { lazy val あ: 構文規則 = "あ" の次に (あ が0回または1回) の次に "い" lazy val い: 構文規則 = "い" の次に (い が0回または1回) の次に "う" lazy val あいう: 構文規則 = ((あ の次に ("い" 以外を先読み)) を先読み) の次に ("あ" が1回以上) の次に い の次に ("う" 以外を先読み) } println(ゆーざ あいう(args(0)))