gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 04:27:55 28 4
gpt4 key购买 nike

我正在创建一个 DSL,并使用 Scala 的解析器组合器库来解析 DSL。 DSL 遵循简单的、类似 Ruby 的语法。源文件可以包含一系列如下所示的 block :

create_model do
at 0,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,但在 end 关键字之后得到了一个新行。

所以我将 commandBlock 的定义更改为:

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

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

但是现在,在解析源文件时,出现以下错误:

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

认为这是因为,在它吸收了尾随的新行之后,解析器遇到了一个它认为无效的空字符串,但我不确定它为什么这样做。

关于如何解决这个问题有什么建议吗?我可能会从 Scala 的解析器组合器库中扩展错误的解析器,因此也欢迎任何有关如何创建具有重要换行符的语言定义的建议。

最佳答案

我在两种方式中都遇到了相同的错误,但我认为您误解了它。它的意思是它正在等待 end,但它已经到达输入的末尾。

发生这种情况的原因是 end 被读取为语句。现在,我确信有一个很好的方法来解决这个问题,但我对 Scala 解析器的经验还不够。似乎要采取的方法是使用带有扫描部分的 token 解析器,但我无法找到一种方法使标准 token 解析器不将换行符视为空格。

所以,这是一个替代方案:

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
}

关于scala - 如何创建一个解析器组合器,其中行结尾很重要?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2382644/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com