3

我想为嵌套块语法编写一个简单的解析器,只是分层纯文本。例如:

Some regular text.
This is outputted as-is, foo{but THIS
is inside a foo block}.

bar{
  Blocks can be multi-line
  and baz{nested}
}

最简单的方法是什么?我已经编写了 2 个工作实现,但它们过于复杂。我尝试了全文正则表达式匹配和逐个字符的流式分析。

我必须向人们传授它的工作原理,所以简单是最重要的。我不想引入对 Lex/Yacc Flex/Bison(或 PEGjs/Jison,实际上,这是 javascript)的依赖。

4

3 回答 3

1

最近,我一直在为一些纯 Javascript 的项目使用解析器组合器。我将代码提取到一个单独的项目中;你可以在这里找到它。这种方法类似于@DigitalRoss 建议的递归下降解析器,但在特定于您的解析器的代码和一般的解析器簿记代码之间有更清晰的划分。

满足您需求的解析器​​(如果我正确理解了您的要求)将如下所示:

var open  = literal("{"),                 // matches only '{'
    close = literal("}"),                 // matches only '}'
    normalChar = not1(alt(open, close));  // matches any char but '{' and '}'

var form = new Parser(function() {}); // forward declaration for mutual recursion

var block = node('block',
                 ['open',  open       ],
                 ['body',  many0(form)],
                 ['close', close      ]);

form.parse = alt(normalChar, block).parse; // set 'form' to its actual value

var parser = many0(form);

你会像这样使用它:

// assuming 'parser' is the parser
var parseResult = parser.parse("abc{def{ghi{}oop}javascript}is great");

解析结果是一个语法树。

除了回溯之外,该库还可以帮助您在解析器调用之间生成漂亮的错误消息和线程用户状态。我发现后两者对于生成大括号错误消息非常有用,在以下情况下报告问题和有问题的大括号标记的位置:1)有一个打开的大括号但没有关闭;2) 大括号类型不匹配——即(...]or {...); 3) 没有匹配的开括号的闭括号。

于 2013-02-21T21:56:18.053 回答
1

好的选择可能归结为如下:

  • 鉴于您的约束,它将是递归下降的。即使没有限制,这也是一个很好的方法。
  • 您可以逐个字符地解析(传统)或编写一个词法层,使用本地字符串库来扫描{}。无论哪种方式,您都可能希望返回三个终端符号加上 EOF:BLOCK_OF_TEXT、LEFT_BRACE 和 RIGHT_BRACE。
于 2013-02-21T00:23:11.807 回答
1
   char c; 

   boolean ParseNestedBlocks(InputStream i)
      {  if ParseStreamContent(i)
         then {  if c=="}" then return false
                            else return true
              }
         else return false;

   boolean ParseSteamContent(InputStream i)
    {  loop:
         c = GetCharacter(i);
         if c =="}" then return true;
         if c== EOF then return true;
         if c=="{"
             {  if ParseStreamContent(i)
                  {  if c!="}" return false; }
                else return false;
             }
         goto loop
     }
于 2013-02-21T03:44:54.290 回答