2

我有一个项目,它仍然处于萌芽状态,我正在尝试使用真正的语法编写 wiki 解析器。我发现了一个似乎相当完整的克里奥尔语语法,并由第三方确认可以工作(使用 ANTLR)。

我已经开始将事情向前推进,但是遇到了一些障碍,我假设这些障碍是 pyparsing 的常见绊脚石。

escaped
    :   ESCAPE  STAR  STAR
    |   ESCAPE  .
    // '.' in a parser rule means arbitrary token, not character
    ;

我想出的是:

ESCAPE = Literal('~')
STAR = Literal('*')
escaped = ESCAPE + STAR + STAR | ESCAPE + Word(printables, max=1)

我在 pyparsing 中找不到任何其他内容来匹配单个字符,但这似乎可行。但是,在查看标题内容时,我有这个子表达式:

heading_content
    :   heading_markup  heading_content  ( heading_markup )?
    |   ( ~( EQUAL | ESCAPE | NEWLINE | EOF ) | escaped )+
    ;

我正在使用前锋,但对于第二部分,我最终得到:

OneOrMore(CharsNotIn("=~\r\n") | escaped)('heading_content')

现在这匹配“test”和“test~=”,但不匹配“test~=foo”,它只匹配“test”部分。这是为什么?

其次,我想知道除了 CharsNotIn 是否还有其他方法来指定内容部分?

现在真正让我难过的是试图匹配未格式化的文本部分。这是匹配各种纯文本的核心。现在语法指定:

text_unformatted
  : ( ~(  ITAL
        |   STAR
        |   LINK_OPEN
        |   IMAGE_OPEN
        |   NOWIKI_OPEN
        |   EXTENSION
        |   FORCED_LINEBREAK
        |   ESCAPE
        |   NEWLINE
        |   EOF )
    |  forced_linebreak 
    |  escaped )+

这是我碰壁的地方。现在上面的简单位定义为:

# STAR, ESCAPE and escaped defined above
ITAL = Literal('//')
LINK_OPEN = Literal('[[')
IMAGE_OPEN = Literal('{{')
NOWIKI_OPEN = Literal('{{{')
EXTENSION = Literal('@@')
FORCED_LINEBREAK = Literal(r'\\')
CR = Literal('\r')
LF = Literal('\n')
NEWLINE = Optional(CR) + LF | CR

然而,我的 OneOrMore(NotAny(...) | FORCED_LINEBREAK | escaped) 的幼稚方法不起作用,最终无限循环。多读一点文档表明 NotAny 实际上并没有返回任何匹配项。那么我们如何匹配这个呢?我不能使用 CharNotIn(...) 因为单个 '{' 是完全有效的。

指针表示赞赏。

4

1 回答 1

3

前段时间,我为 antlr 语法编写了一个用 pyparsing 编写的转换器,这可能会有所帮助,我将它作为 pyparsing 票证中的功能请求提交:

http://sourceforge.net/tracker/index.php?func=detail&aid=3060671&group_id=97203&atid=617314

antlr 语法几乎是完整的,所以它可能会完成这项工作,否则,它可能是一个有用信息的来源,用于了解如何对 antlr 语法进行 pyparsing 等价,它还包括一些测试。

希望能帮助到你 :-)

于 2012-09-21T11:25:32.457 回答