【问题标题】:Error message on match fail in Rebol ParseRebol Parse 中匹配失败的错误消息
【发布时间】:2013-07-02 20:45:44
【问题描述】:

基于 PEG 的解析器生成器通常对无效输入提供有限的错误报告。根据我的阅读,rebol 的解析方言受到了用正则表达式扩展的 PEG 语法的启发。

例如,在 JavaScript 中键入以下内容:

d8> function () {}

给出以下错误,因为在声明全局函数时没有提供标识符:

(d8):1: SyntaxError: Unexpected token (
function () {}
         ^

解析器能够在解析过程中准确指出缺少预期标记的位置。预期标记的字符位置用于定位错误消息中的箭头。

rebol 中的 parse dialect 是否提供内置工具来报告无效输入的行和列错误?

否则,是否有自定义推出的解析规则提供此类错误报告的示例?

【问题讨论】:

  • 您询问“无效令牌/规则的行和列”。您是否在询问如何判断您传入的方言规则块何时存在问题,或者这些规则可用于报告解析过程本身输入中的问题的工具?编辑此问题以添加您正在寻找的理想化示例可能会有所帮助。
  • @HostileFork 我要的是第二种情况,当输入无效时。

标签: parsing error-handling rebol peg


【解决方案1】:

我已经完成了非常先进的 Rebol 解析器,它可以管理实时和关键任务 TCP 服务器,并且需要进行适当的错误报告。所以这很重要!

Rebol 的 PARSE 最独特的方面之一可能是您可以在规则中包含直接评估。所以你可以设置变量来跟踪解析位置,或者错误消息等。(这很容易,因为 Rebol 的本质是将代码和数据混合为同一事物是一个核心思想。)

这就是我的做法。在尝试每个匹配规则之前,我将解析位置保存到“这里”(通过编写 here:),然后还使用代码执行将错误保存到变量中(通过将 (error: {some error string}) 放在括号中,以便解析方言运行它)。如果匹配规则成功,我们不需要使用错误或位置......我们只需继续下一条规则。但是如果它失败了,我们将在失败后获得我们设置的最后一个状态报告。

因此解析方言中的模式很简单:

; use PARSE dialect handling of "set-word!" instances to save parse
; position into variable named "here"

here:

; escape out of the parse dialect using parentheses, and into the DO 
; dialect to run arbitrary code.  Here we run code that saves an error
; message string into a variable named "error"

(error: "<some error message relating to rule that follows>")

; back into the PARSE dialect again, express whatever your rule is,
; and if it fails then we will have the above to use in error reporting

what: (ever your) [rule | {is}]

这基本上就是您需要做的。以下是电话号码的示例:

digit: charset "012345689"

phone-number-rule: [
    here:
    (error: "invalid area code")
    ["514" | "800" | "888" | "916" "877"]

    here:
    (error: "expecting dash")
    "-"

    here:
    (error: "expecting 3 digits")
    3 digit

    here:
    (error: "expecting dash")
    "-"

    here:
    (error: "expecting 4 digits")
    4 digit

    (error: none)
]

然后你就可以看到它的作用了。请注意,如果我们到达解析规则的末尾,我们将 error 设置为 none。如果还有更多输入要处理,PARSE 将返回 false,所以如果我们注意到没有设置错误但 PARSE 仍然返回 false...我们失败了,因为有太多额外的输入:

input: "800-22r2-3333"

if not parse input phone-number-rule [
   if none? error [
        error: "too much data for phone number"
    ]
]

either error [
    column: length? copy/part input here newline
    print rejoin ["error at position:" space column]
    print error
    print input
    print rejoin [head insert/dup "" space column "^^"}
    print newline
][
    print {all good}
]

上面将打印以下内容:

error at position: 4

expecting 3 digits
800-22r2-3333
    ^

显然,您可以做更有效的事情,因为您放入括号中的任何内容都将像正常的 Rebol 源代码一样被评估。它真的很灵活。我什至有在加载大量数据集时更新进度条的解析器...... :-)

【讨论】:

  • 抱歉所有的重写,但我认为这是一个足够好的例子来解释更多。 :-)
  • 我知道你来自一种很自然的语言,请不要开始添加双分号,它既丑陋又不需要。
  • 老实说,我试图保持简单直接。它故意简短而甜美,文本过多,有时变得难以访问(这使得解析看起来很复杂)。我会在你编辑时留下它......这次(骄傲受伤;-)(尽管删除了双分号);-P
  • 谢谢,所以基本上关键是方言足够灵活,可以添加手动错误支持。鉴于该语言的元编程设施,应该可以通过解析规则自动插入基本错误处理。有记录的例子吗?
  • 如果你环顾四周,你会发现很多 PARSE 引物和一两个深入的研究。但是 PARSE 尽管有用,但仍然被普通的 Rebol 程序员误解了。它缺乏核心文档。
【解决方案2】:

这是一个在解析字符串期间查找位置的简单示例,可用于执行您所要求的操作。

假设我们的代码只有在包含 a 和 b 字符时才有效,否则任何内容都是非法输入。

code-rule: [
    some [
        "a" |
        "b"
    ] 
    [ end | mark: (print [ "Failed at position" index? mark ]) ]
]

让我们用一些有效的代码检查一下

>> parse "aaaabbabb" code-rule
== true

现在我们可以用一些无效的输入再试一次

>> parse "aaaabbXabb" code-rule
Failed at position 7
== false

这是一种相当简化的示例语言,但应该很容易扩展到更复杂的示例。

【讨论】:

猜你喜欢
  • 2019-04-28
  • 2012-08-29
  • 1970-01-01
  • 1970-01-01
  • 2014-04-30
  • 1970-01-01
  • 1970-01-01
  • 2017-05-26
  • 2011-01-31
相关资源
最近更新 更多