使用PEG解析器进行BBCode解析:pegjs还是......什么?

时间:2012-06-29 20:13:35

标签: javascript parsing bbcode peg pegjs

我有一个bbcode - > html转换器响应textarea中的change事件。目前,这是使用一系列正则表达式完成的,并且存在许多病理情况。我一直想在这个语法上磨铅笔,但不想进入牦牛剃须。但是......最近我开始意识到pegjs,这似乎是PEG解析器生成的完全实现。我已经指定了大部分语法,但现在我想知道这是否适合使用完整的解析器。

我的具体问题是:

  1. 由于我的应用程序依赖于将我能够转换为HTML并将其余内容保留为原始文本,使用可能因语法错误而失败的解析器实现bbcode是否有意义?例如:一旦输入关闭标记的结束括号,肯定会预期[url=/foo/bar]click me![/url]成功。但是在此期间用户会看到什么?使用正则表达式,我可以忽略不匹配的东西,并将其视为普通文本以用于预览目的。使用正式语法,我不知道这是否可行,因为我依赖于从解析树创建HTML以及解析失败的原因是什么?

  2. 我不清楚应该在哪里进行转换。在正式的基于lex / yacc的解析器中,我将有头文件和符号表示节点类型。在pegjs中,我得到了带有节点文本的嵌套数组。我可以将翻译后的代码作为pegjs生成的解析器的一个动作发出,但是它似乎是一种将解析器和发射器组合在一起的代码气味。但是,如果我拨打PEG.parse.parse(),我会收到这样的信息:

  3. [
           [
              "[",
              "img",
              "",
              [
                 "/",
                 "f",
                 "o",
                 "o",
                 "/",
                 "b",
                 "a",
                 "r"
              ],
              "",
              "]"
           ],
           [
              "[/",
              "img",
              "]"
           ]
        ]

    给出如下语法:

    document
       = (open_tag / close_tag / new_line / text)*
    
    open_tag
       = ("[" tag_name "="? tag_data? tag_attributes? "]")
    
    
    close_tag
       = ("[/" tag_name "]") 
    
    text
       = non_tag+
    
    non_tag
       = [\n\[\]]
    
    new_line
       = ("\r\n" / "\n")
    

    当然,我正在缩写语法,但你明白了。所以,如果你注意到,数组数组中没有上下文信息告诉我我有什么样的节点,我还要再做字符串比较,甚至认为解析器已经这样做了。我希望在解析期间可以定义回调并使用操作来运行它们,但是网上很少有关于如何做到这一点的信息。

    我是在叫错树吗?我应该回到正则表达式扫描并忘记解析吗?

    由于

3 个答案:

答案 0 :(得分:3)

第一个问题(不完整文本的语法):

您可以添加

incomplete_tag = ("[" tag_name "="? tag_data? tag_attributes?)
//                         the closing bracket is omitted ---^
open_tag之后

并更改document以在最后添加不完整的标记。诀窍在于您为解析器提供了所有需要的产品,以便始终解析,但有效的解析首先出现。然后,您可以在实时预览期间忽略incomplete_tag

第二个问题(如何包含操作):

你在表达式之后编写所谓的动作。一个动作是由大括号括起来的Javascript代码,在pegjs表达式后允许,i。即也是在制作过程中!

在实践中,像{ return result.join("") }这样的动作几乎总是必要的,因为pegjs会分成单个字符。也可以返回复杂的嵌套数组。因此,我通常在语法的开头的pegjs初始化程序中编写辅助函数,以保持较小的操作。如果您仔细选择功能名称,则操作是自我记录的。

有关考试,请参阅PEG for Python style indentation。免责声明:这是我的答案。

答案 1 :(得分:2)

关于你的第一个问题,我认为现场预览会很困难。您指出的解析器无法理解输入是“正在进行中”的问题是正确的。 Peg.js会告诉你错误发生在哪一点,所以也许你可以拿出那些信息然后再说一遍并再次解析,或者如果缺少结束标记,请尝试在最后添加它。

你问题的第二部分比较容易,但之后你的语法看起来不那么好。基本上你所做的就是在每条规则上加上回调,例如

text
   = text:non_tag+ {
     // we captured the text in an array and can manipulate it now
     return text.join("");
   }

目前你必须在语法中内联编写这些回调。我现在正在做很多这样的工作,所以我可以向peg.js做一个pullrequest来解决这个问题。但我不确定我什么时候能找到这个。

答案 2 :(得分:1)

尝试类似此替换规则的内容。你走在正确的轨道上;你只需告诉它汇总结果。

文本   = result:non_tag + {return result.join(''); }