В основном, он медленный и потребляет слишком много памяти, потому что ваша грамматика невероятно неэффективна.
Рассмотрим вторую строку: B = A:(1+2)
. Он попытается проанализировать эту строку следующим образом:
- term4
OR
term4 а затем term4.
- term3
AND
term3 а затем срок3.
- term2
<>
term2, затем =
, затем NE
затем EQ
, а затем term2.
- срок1 8 различные операторы term1, then term1.
- термин
+
срок, срок -
срок, срок :
срок, а затем срок.
- фактор
*
фактор, фактор /
коэффициент, фактор MOD
коэффициент, а затем коэффициент.
- выражение в скобках, одинарный коэффициент, функция, числовой литерал, строковый литерал, идентификатор.
Первая попытка, как это:
ident * factor + term < term1 <> term2 AND term3 OR term4
я пропущу скобка, унарный, функция, числовые и строковые литералы, потому что они не соответствуют A
- хотя function
, вероятно, делает, но это определение недоступно. Теперь, так как :
не соответствует *
, он будет пытаться дальше:
ident/factor + term < term1 <> term2 AND term3 OR term4
ident MOD factor + term < term1 <> term2 AND term3 OR term4
ident + term < term1 <> term2 AND term3 OR term4
Теперь он идет к следующему term1
:
ident * factor - term < term1 <> term2 AND term3 OR term4
ident/factor - term < term1 <> term2 AND term3 OR term4
ident MOD factor - term < term1 <> term2 AND term3 OR term4
ident - term < term1 <> term2 AND term3 OR term4
И дальше:
ident * factor : term < term1 <> term2 AND term3 OR term4
ident/factor : term < term1 <> term2 AND term3 OR term4
ident MOD factor : term < term1 <> term2 AND term3 OR term4
ident : term < term1 <> term2 AND term3 OR term4
Aha! Наконец-то мы получили матч на term1! Но (
не соответствует <
, поэтому он должен попробовать следующий term2:
ident * factor + term > term1 <> term2 AND term3 OR term4
и т.д ...
Все потому, что первый член в каждой строке для каждого члена всегда будет соответствовать! Чтобы соответствовать простому номеру, он должен разобрать factor
2 * 2 * 5 * 9 * 4 * 4 = 2880 раз!
Но это не половина истории! Видите ли, потому что termX повторяется дважды, он будет повторять все это на и сторон.Например, первый матч за A:(1+2)
это:
ident : term < term1 <> term2 AND term3 OR term4
where ident = A
and term = (1+2)
Что неправильно, поэтому он будет пытаться >
вместо <
, а затем <=
и т.д., и т.д.
Я ставлю версию протоколирования этого анализатора ниже. Попробуйте запустить его и увидеть все, что он пытается проанализировать.
Между тем есть хорошие примеры того, как писать эти синтаксические анализаторы. Используя sbaz
, попробуйте:
sbaz install scala-devel-docs
Тогда загляните в doc/scala-devel-docs/examples/parsing
каталоге дистрибутива Scala, и вы найдете несколько примеров.
Вот версия вашего синтаксического анализатора (без function
), который регистрирует все, что пытается:
sealed trait Expression
case class Variable(id: String) extends Expression
case class Literal(s: String) extends Expression
case class Number(x: String) extends Expression
case class UnaryOp(op: String, rhs: Expression) extends Expression
case class BinaryOp(op: String, lhs: Expression, rhs: Expression) extends Expression
object TestParser extends scala.util.parsing.combinator.syntactical.StdTokenParsers {
import scala.util.parsing.combinator.lexical.StdLexical
type Tokens = StdLexical
val lexical = new StdLexical
lexical.delimiters ++= List("(", ")", "+", "-", "*", "/", "=", "OR", "AND", "NE", "EQ", "LT", "GT", "LE", "GE", ":", "MOD")
def stmts: Parser[Any] = log(expr.*)("stmts")
def stmt: Parser[Expression] = log(expr <~ "\n")("stmt")
def expr: Parser[Expression] = log(term5)("expr")
def term5: Parser[Expression] = (
log((term4 ~ "OR" ~ term4) ^^ { case lhs~o~rhs => BinaryOp("OR", lhs, rhs) })("term5 OR")
| log(term4)("term5 term4")
)
def term4: Parser[Expression] = (
log((term3 ~ "AND" ~ term3) ^^ { case lhs~a~rhs => BinaryOp("AND", lhs, rhs) })("term4 AND")
| log(term3)("term4 term3")
)
def term3: Parser[Expression] = (
log((term2 ~ "<>" ~ term2) ^^ { case lhs~ne~rhs => BinaryOp("NE", lhs, rhs) })("term3 <>")
| log((term2 ~ "=" ~ term2) ^^ { case lhs~eq~rhs => BinaryOp("EQ", lhs, rhs) })("term3 =")
| log((term2 ~ "NE" ~ term2) ^^ { case lhs~ne~rhs => BinaryOp("NE", lhs, rhs) })("term3 NE")
| log((term2 ~ "EQ" ~ term2) ^^ { case lhs~eq~rhs => BinaryOp("EQ", lhs, rhs) })("term3 EQ")
| log(term2)("term3 term2")
)
def term2: Parser[Expression] = (
log((term1 ~ "<" ~ term1) ^^ { case lhs~lt~rhs => BinaryOp("LT", lhs, rhs) })("term2 <")
| log((term1 ~ ">" ~ term1) ^^ { case lhs~gt~rhs => BinaryOp("GT", lhs, rhs) })("term2 >")
| log((term1 ~ "<=" ~ term1) ^^ { case lhs~le~rhs => BinaryOp("LE", lhs, rhs) })("term2 <=")
| log((term1 ~ ">=" ~ term1) ^^ { case lhs~ge~rhs => BinaryOp("GE", lhs, rhs) })("term2 >=")
| log((term1 ~ "LT" ~ term1) ^^ { case lhs~lt~rhs => BinaryOp("LT", lhs, rhs) })("term2 LT")
| log((term1 ~ "GT" ~ term1) ^^ { case lhs~gt~rhs => BinaryOp("GT", lhs, rhs) })("term2 GT")
| log((term1 ~ "LE" ~ term1) ^^ { case lhs~le~rhs => BinaryOp("LE", lhs, rhs) })("term2 LE")
| log((term1 ~ "GE" ~ term1) ^^ { case lhs~ge~rhs => BinaryOp("GE", lhs, rhs) })("term2 GE")
| log(term1)("term2 term1")
)
def term1: Parser[Expression] = (
log((term ~ "+" ~ term) ^^ { case lhs~plus~rhs => BinaryOp("+", lhs, rhs) })("term1 +")
| log((term ~ "-" ~ term) ^^ { case lhs~minus~rhs => BinaryOp("-", lhs, rhs) })("term1 -")
| log((term ~ ":" ~ term) ^^ { case lhs~concat~rhs => BinaryOp(":", lhs, rhs) })("term1 :")
| log(term)("term1 term")
)
def term: Parser[Expression] = (
log((factor ~ "*" ~ factor) ^^ { case lhs~times~rhs => BinaryOp("*", lhs, rhs) })("term *")
| log((factor ~ "/" ~ factor) ^^ { case lhs~div~rhs => BinaryOp("/", lhs, rhs) })("term /")
| log((factor ~ "MOD" ~ factor) ^^ { case lhs~div~rhs => BinaryOp("MOD", lhs, rhs) })("term MOD")
| log(factor)("term factor")
)
def factor: Parser[Expression] = (
log("(" ~> expr <~ ")")("factor (expr)")
| log(("+" | "-") ~ factor ^^ { case op~rhs => UnaryOp(op, rhs) })("factor +-")
//| function |
| log(numericLit ^^ { case x => Number(x/*.toFloat*/) })("factor numericLit")
| log(stringLit ^^ { case s => Literal(s) })("factor stringLit")
| log(ident ^^ { case id => Variable(id) })("factor ident")
)
def parse(s: String) = stmts(new lexical.Scanner(s))
}
Что такое тестовый пример? А какой парсер вы используете? –
Я использую StdTokenParsers. –
Тестовый пример: Println (TestParser.parse ( \t "\ нА = \" MY ТЕСТ СТРОКА \ "" + \t "\ пВ = А: (1 + 2)" + \t "\ пС = 3" + \t "\ Nn = -4" + \t "\ п = 3 + 1/(5 - 4)" + \t "\ нФ = -5 + 1" + \t «\ NG = -3 + 1/(-5 - -3) "+ \t" \ nH = 4.99 "+ \t" \ nI = -4.99 ")) –