文法、Scalaの構文解析コンビネータとORDERLESSセット
質問
私は、様々な「コマンド」の文字列になりますアプリケーションを書いています。私は、コマンドをトークン化するためにScalaのコンビネータライブラリを見てきました。私が言いたいの例多くで見つける:「これらのトークンはORDERLESSセットであり、それらがどのような順序で表示することができ、そしていくつかが表示されない場合がありますので、」
私は、このような(擬似文法)として配列の全ての組み合わせを定義しなければならない文法の私の現在の知識では、
command = action~content
action = alphanum
content = (tokenA~tokenB~tokenC | tokenB~tokenC~tokenA | tokenC~tokenB~tokenA ....... )
私の質問があるので、、tokenA-Cがユニークである考えると、文法を使用して、任意の順序のセットを定義するために短い方法はありますか?
解決
これを回避する方法があります。例えば、をここパーサを見てみましょう。それは一度だけ、他に表示される場合がありますが、一度現れなければならない、と4事前定義された数字を、受け入れます。
このパターンが頻繁に起こる場合OTOH、あなたは、コンビネータを書くことができます:
def comb3[A](a: Parser[A], b: Parser[A], c: Parser[A]) =
a ~ b ~ c | a ~ c ~ b | b ~ a ~ c | b ~ c ~ a | c ~ a ~ b | c ~ b ~ a
他のヒント
あなたは "パーサー。^?" を使用することができますオペレータは重複を解析要素のグループを確認する。
def tokens = tokenA | tokenB | tokenC
def uniqueTokens = (tokens*) ^? (
{ case t if (t == t.removeDuplicates) => t },
{ "duplicate tokens found: " + _ })
ここでは、任意の順序で4人の大将のいずれかを入力することができますが、重複が発生した場合の解析に失敗した例です。
package blevins.example
import scala.util.parsing.combinator._
case class Stooge(name: String)
object StoogesParser extends RegexParsers {
def moe = "Moe".r
def larry = "Larry".r
def curly = "Curly".r
def shemp = "Shemp".r
def stooge = ( moe | larry | curly | shemp ) ^^ { case s => Stooge(s) }
def certifiedStooge = stooge | """\w+""".r ^? (
{ case s: Stooge => s },
{ "not a stooge: " + _ })
def stooges = (certifiedStooge*) ^? (
{ case x if (x == x.removeDuplicates) => x.toSet },
{ "duplicate stooge in: " + _ })
def parse(s: String): String = {
parseAll(stooges, new scala.util.parsing.input.CharSequenceReader(s)) match {
case Success(r,_) => r.mkString(" ")
case Failure(r,_) => "failure: " + r
case Error(r,_) => "error: " + r
}
}
}
そして、いくつかの使用例:
package blevins.example
object App extends Application {
def printParse(s: String): Unit = println(StoogesParser.parse(s))
printParse("Moe Shemp Larry")
printParse("Moe Shemp Shemp")
printParse("Curly Beyonce")
/* Output:
Stooge(Moe) Stooge(Shemp) Stooge(Larry)
failure: duplicate stooge in: List(Stooge(Moe), Stooge(Shemp), Stooge(Shemp))
failure: not a stooge: Beyonce
*/
}
私は、構文的にこの要件を強制しようとしないでしょう。私は、許可されたセットから複数のトークンを認めている生産を書き、その後、実際に与えられたキーワードの受容性を確認する非解析するアプローチを使用すると思います。シンプルな文法を可能にすることに加えて、それはあなたがより簡単に、誤った使い方に関する診断を放出した後に解析し続けることができるようになります。
ランドール・シュルツ
私はあなたがサポートしたいが、私はあなたがより具体的な文法を指定する必要があり集める構造の種類を知りません。
:別の答えにあなたのコメントからTODOメッセージ:データベースへのリンク藤堂クラス
私はあなたのような何かを受け入れるようにしたくないと思います。
TODOメッセージ:リンククラスにデータベース藤堂
あなたはおそらく...
「に」「リンク」など、いくつかのメッセージレベルのキーワードを定義したいのでdef token = alphanum~':'~ "link" ~ alphanum ~ "class" ~ "to" ~ alphanum
^^ { (a:String,b:String,c:String) => /* a == "message", b="Todo", c="database" */ }
私はあなたがそのレベルであなたの文法を定義しなければならないと思います。
あなたはもちろん、あなたが頻繁にこのような状況が発生した場合、あなたのためにこれを行い組み合わせルールを書くことができます。
一方、多分オプションは「tokenA..Cは」単なる「トークン」にし、その後、
「トークン」のハンドラ内で区別するために存在します