使用lpeg仅捕获字边界

时间:2016-08-01 03:45:00

标签: parsing lua lpeg

我一直致力于使用LPEG实现语法突出显示支持的a text editor。启动和运行非常简单,但我只完成了最低要求。

我已经定义了一堆这样的模式:

 -- Keywords
 local keyword = C(
    P"auto" +
    P"break" +
    P"case" +
    P"char" + 
    P"int" 
    -- more ..
  ) / function() add_syntax( RED, ... )

这正确处理输入,但遗憾的是匹配太多。例如,int匹配printf,这是预期的,因为我使用“P”进行文字匹配。

显然要执行“正确”突出显示我需要匹配单词边界,这样“int”匹配“int”,而不是“printf”,“vsprintf”等。

我尝试使用此功能将匹配限制为仅在“<[{ \n”之后发生,但这不符合我的要求:

  -- space, newline, comma, brackets followed by the keyword
  S(" \n(<{,")^1 * P"auto"  + 

是否有一个简单明了的解决方案,我在这里只缺少匹配由空格或其他字符包围的关键字/标记,这些字符在C代码中是您所期望的?我确实需要捕获的令牌,所以我可以突出显示它,但除此之外,我没有嫁给任何特定的方法。

e.g。这些应该匹配:

 int foo;
 void(int argc,std::list<int,int> ) { .. };

但这不应该:

 fprintf(stderr, "blah.  patterns are hard\n");

2 个答案:

答案 0 :(得分:3)

LPeg构造-pattern(或者更具体地说,在以下示例中为-idchar)可以很好地确保当前匹配未遵循 {{1 (pattern)。幸运的是,这也适用于输入结束时的空字符串,因此我们不需要特殊处理。为了确保匹配不在之前的模式,LPeg提供idchar。不幸的是,这需要一个匹配固定长度字符串的模式,因此在输入的开头不起作用。为了解决这个问题,下面的代码分别尝试在输入开头没有lpeg.B(pattern)的情况下进行匹配,然后再返回到检查字符串其余部分的后缀前缀的模式:

lpeg.B()

答案 1 :(得分:2)

我认为你应该否定匹配模式,类似于documentation中的例子:

  

如果我们只想在字边界处寻找图案,我们可以使用以下变换器:

local t = lpeg.locale()
function atwordboundary (p)
  return lpeg.P{
    [1] = p + t.alpha^0 * (1 - t.alpha)^1 * lpeg.V(1)
  }
end

这个SO answer也讨论了一些类似的解决方案,因此可能会引起关注。

还有another editor component使用LPeg进行语法突出显示的目的,因此您可能希望了解它们如何处理(或者如果它适用于您的设计,则使用它们的词法分析器)。