最简单的嵌套块解析器

时间:2013-02-21 00:13:48

标签: lexer

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

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个工作实现,但它们过于复杂。我尝试了全文正则表达式匹配和流式化char-by-char分析。

我必须向人们传授它的运作方式,因此简单性至关重要。我不想引入依赖于Lex / Yacc Flex / Bison(或PEGjs / Jison,实际上,这是javascript)。

3 个答案:

答案 0 :(得分:1)

好的选择可能归结如下:

  • 鉴于你的遗体,它将是递归下降的。即使没有限制,这也是一个很好的方式。
  • 您可以解析char-by-char(传统)或编写使用本地字符串库扫描{}的词法层。无论哪种方式,您可能希望返回三个终端符号加上EOF:BLOCK_OF_TEXT,LEFT_BRACE和RIGHT_BRACE。

答案 1 :(得分: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
     }

答案 2 :(得分:1)

最近,我一直在纯JavaScript中使用解析器组合器进行某些项目。我将代码拉出到一个单独的项目中; you can find it here。这种方法类似于@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)有不匹配的支具类型 - 即(...]{...); 3)没有匹配打开的紧密支撑。