关键字和标识符与编写词法分析器冲突吗? (scala libs)

时间:2018-12-31 10:12:59

标签: scala keyword lex identifier ambiguous-grammar

我已经尝试过fastparse,parboiled2和scala组合器。 在定义LEXER时,他们都有这个问题:

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

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

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

如果输入为"let",则它会通过选择第一个定义的规则来解决歧义,因为它更相关。 如果输入为"leto",则没有歧义,仅产生IDENTIFIER(leto)。 这就是ANTLR

中描述的here的行为

2 个答案:

答案 0 :(得分: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
}

答案 1 :(得分:1)

您的情况与词法分析器在解析器之前暂存的ANTLR情况不具有可比性。在那种情况下,您会看到词法分析器的最长匹配规则具有优先权,这仅仅是因为它首先执行,从而生成了解析器随后可以使用的唯一令牌。

在您的情况下,使用您使用的解析技术,它们在您尝试识别的当前非终端环境中“按需”执行正则表达式。这使得在两种不同的词法解释之间进行选择时会产生上下文无关的选择。您必须将该选择纳入您的定义中。

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