加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 如何创建一个解析器组合器,其中行结尾是重要的?

发布时间:2020-12-16 09:32:07 所属栏目:安全 来源:网络整理
导读:我正在创建DSL,并使用Scala的解析器组合器库来解析DSL。 DSL遵循简单的类似Ruby的语法。源文件可以包含一系列如下所示的块: create_model do at 0,0end 线路结束在DSL中是重要的,因为它们被有效地用作语句终止符。 我写了一个Scala解析器,看起来像这样:
我正在创建DSL,并使用Scala的解析器组合器库来解析DSL。 DSL遵循简单的类似Ruby的语法。源文件可以包含一系列如下所示的块:

create_model do
  at 0,0
end

线路结束在DSL中是重要的,因为它们被有效地用作语句终止符。

我写了一个Scala解析器,看起来像这样:

class ML3D extends JavaTokenParsers {
  override val whiteSpace = """[ t]+""".r

  def model: Parser[Any] = commandList
  def commandList: Parser[Any] = rep(commandBlock)
  def commandBlock: Parser[Any] = command~"do"~eol~statementList~"end"
  def eol: Parser[Any] = """(r?n)+""".r
  def command: Parser[Any] = commandName~opt(commandLabel)
  def commandName: Parser[Any] = ident
  def commandLabel: Parser[Any] = stringLiteral
  def statementList: Parser[Any] = rep(statement)
  def statement: Parser[Any] = functionName~argumentList~eol
  def functionName: Parser[Any] = ident
  def argumentList: Parser[Any] = repsep(argument,",")
  def argument: Parser[Any] = stringLiteral | constant
  def constant: Parser[Any] = wholeNumber | floatingPointNumber
}

由于行结束很重要,我忽略了whiteSpace,因此它只会将空格和制表符视为空格(而不是将新行视为空格,从而忽略它们)。

这有效,除了commandBlock的“end”语句。由于我的源文件包含一个尾随的新行,解析器抱怨说它只是一个结束,但在end关键字后面有一行。

所以我改变了commandBlock的定义:

def commandBlock: Parser[Any] = command~"do"~eol~statementList~"end"~opt(eol)

(也就是说,我在“结束”之后添加了一个可选的新行)。

但现在,当解析源文件时,我会收到以下错误:

[4.1] failure: `end' expected but `' found

我认为这是因为,它吸引了尾随的新行,解析器遇到一个空字符串,它认为是无效的,但我不知道为什么这样做。

有关如何解决这个问题的任何提示?我可能会从Scala的解析器组合程序库扩展错误的解析器,所以关于如何创建具有重要新行字符的语言定义的任何建议也是受欢迎的。

解决方法

我以两种方式得到同样的错误,但我认为你是误解了它。它的意思是它预计会结束,但已经达到了输入的最后。

而正在发生的原因是这样的结局被看作是一个声明。现在,我确定有一个很好的方法来解决这个问题,但是我没有足够的Scala解析器经验。看起来去的方式是使用带有扫描部分的令牌解析器,但是我无法想象出使标准令牌解析器不将换行符视为空格。

所以,这里有一个选择:

import scala.util.parsing.combinator.JavaTokenParsers

class ML3D extends JavaTokenParsers {
  override val whiteSpace = """[ t]+""".r
  def keywords: Parser[Any] = "do" | "end"
  def identifier: Parser[Any] = not(keywords)~ident

  def model: Parser[Any] = commandList
  def commandList: Parser[Any] = rep(commandBlock)
  def commandBlock: Parser[Any] = command~"do"~eol~statementList~"end"~opt(eol)
  def eol: Parser[Any] = """(r?n)+""".r
  def command: Parser[Any] = commandName~opt(commandLabel)
  def commandName: Parser[Any] = identifier
  def commandLabel: Parser[Any] = stringLiteral
  def statementList: Parser[Any] = rep(statement)
  def statement: Parser[Any] = functionName~argumentList~eol
  def functionName: Parser[Any] = identifier
  def argumentList: Parser[Any] = repsep(argument,")
  def argument: Parser[Any] = stringLiteral | constant
  def constant: Parser[Any] = wholeNumber | floatingPointNumber
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读