0

我尝试过 fastparse、parboiled2 和 scala-combinators。他们在定义 LEXER 时都有这个问题:

LET_KEYWORD ::= "let"
IDENTIFIER  ::= "[a-zA-Z]+".r

当我根据输入运行它们时,"leto"它们会产生[LET_KEYWORD,IDENTIFIER(o)].

我希望其中一些库能给我这样的行为:

如果输入是,"let"那么它通过选择第一个定义的规则来解决歧义,因为它更相关。如果输入是"leto"那么没有歧义并且只产生IDENTIFIER(leto). 就是在 ANTLR 中描述的行为

4

2 回答 2

1

这是我的代码片段

val identifierOrKeyword = letter ~ rep(letter | digit | '_') ^^ {
  case x ~ xs =>
    val ident = x :: xs mkString ""
    keyword.getOrElse(ident.toLowerCase, IDENTIFIER(ident))
}

keyword是从字符串到标记的映射。

使用的定义:

sealed trait SqlToken
object SqlToken {
  case class IDENTIFIER(value: String) extends SqlToken
  case object LET extends SqlToken
}

val keyword = Map(
    "let" -> LET
}
于 2018-12-31T10:19:17.183 回答
1

您的情况无法与 ANTLR 情况相比,其中词法分析器在解析器之前上演。在这种情况下,您会看到词法分析器的最长匹配规则优先,因为它首先执行,生成解析器随后可以使用的唯一标记。

在您的情况下,使用您使用的解析技术,它们会在您尝试识别的当前非终端的上下文中“按需”执行正则表达式。这使得两种不同的词汇解释之间的选择冒泡成为一个与上下文无关的选择。您必须将该选择连接到您的定义中。

我猜想源代码中规则的顺序与这些技术无关,您必须在某处使用声明性有序选择(而不是|),或者重写语法以不再模棱两可。

于 2018-12-31T11:18:27.537 回答