7

さまざまな「コマンド」文字列を取り込むアプリケーションを作成しています。コマンドをトークン化するためにScalaコンビネータライブラリを調べてきました。多くの場合、「これらのトークンは順序のないセットであるため、任意の順序で表示でき、一部は表示されない可能性があります」と言いたいことがあります。

文法に関する私の現在の知識では、シーケンスのすべての組み合わせをそのように定義する必要があります(疑似文法)。

command = action~content
action = alphanum
content  = (tokenA~tokenB~tokenC | tokenB~tokenC~tokenA | tokenC~tokenB~tokenA ....... )

だから私の質問は、tokenA-Cがユニークであることを考えると、文法を使用して任意の順序のセットを定義するより短い方法はありますか?

4

5 に答える 5

4

「パーサー。^?」を使用できます。解析要素のグループに重複がないかチェックする演算子。

  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
  */
}
于 2009-11-23T23:11:43.763 に答える
3

それを回避する方法があります。たとえば、ここでパーサーを見てください。4つの事前定義された番号を受け入れます。これは他の番号に表示される場合がありますが、1回だけ表示する必要があります。

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
于 2009-11-23T11:09:40.270 に答える
1

私はこの要件を構文的に強制しようとはしません。許可されたセットから複数のトークンを許可するプロダクションを作成し、解析しないアプローチを使用して、実際に指定されたキーワードの受け入れ可能性を確認します。より単純な文法を可能にすることに加えて、それはあなたが誤った使用法についての診断を発した後、より簡単に構文解析を続けることを可能にします。

ランドール・シュルツ

于 2009-11-23T14:40:45.633 に答える
0

もちろん、このような状況が頻繁に発生する場合は、これを行う組み合わせルールを作成することもできます。

一方、「tokenA..C」を単に「token」にして、「token」のハンドラー内で区別するオプションが存在する可能性があります。

于 2009-11-23T08:11:32.000 に答える
0

どのような構成をサポートしたいかはわかりませんが、より具体的な文法を指定する必要があると思います。あなたのコメントから別の答えへ:

todoメッセージ:Todoクラスをデータベースにリンクする

私はあなたがのようなものを受け入れたくないと思います

todoメッセージ:データベースTodo to link class

したがって、「link」や「to」などのメッセージレベルのキーワードを定義することをお勧めします。

def token = alphanum~':'~ "link" ~ alphanum ~ "class" ~ "to" ~ alphanum 
  ^^ { (a:String,b:String,c:String) => /* a == "message", b="Todo", c="database" */ }

そのレベルで文法を定義する必要があると思います。

于 2009-11-23T10:59:45.447 に答える