使用LPEG (Lua解析器表达式语法),如boost::spirit



所以我用lpeg来代替boost spirit语法,我必须说boost::spirit远比lpeg更优雅和自然。然而,由于当前c++编译器技术的限制和c++中TMP的问题,它很难使用。在这种情况下,类型机制是你的敌人而不是朋友。另一方面,虽然丑陋和基本的结果是更高的生产力。

不管怎样,我离题了,我的lpeg语法的一部分看起来像这样:

function get_namespace_parser()
  local P, R, S, C, V =
    lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.V
namespace_parser = 
lpeg.P{
    "NAMESPACE";
    NAMESPACE   = V("WS") * P("namespace") * V("SPACE_WS") * V("NAMESPACE_IDENTIFIER") 
                  * V("WS") * V("NAMESPACE_BODY") * V("WS"),
    NAMESPACE_IDENTIFIER = V("IDENTIFIER") / print_string ,
    NAMESPACE_BODY =  "{" * V("WS") *   
                      V("ENTRIES")^0 * V("WS") * "}",

    WS = S(" tn")^0,
    SPACE_WS = P(" ") * V("WS") 
}
  return namespace_parser
end 

这个语法(虽然不完整)匹配下面的namespace foo {}。我想实现以下语义(这是使用boost spirit时常见的用例)。

  1. 为命名空间规则创建一个本地变量
  2. namespace IDENTIFIER {被匹配时,为这个局部变量添加一个命名空间数据结构
  3. 将新创建的命名空间数据结构传递给NAMESPACE_BODY以进一步构建AST…

我确信这个用例是可以实现的。没有例子可以证明这一点。我对语言和库都不太了解,不知道怎么做。有人能告诉我它的语法吗?

edit:经过几天尝试与lpeg跳舞,并得到我的脚踩,我决定回到spirit:D很明显,lpeg是指与lua函数编织,这种编织是非常自由的形式(而spirit有明确的非常好的文档语义)。我只是还没有正确的lua心智模型。

尽管为命名空间规则创建一个局部变量"听起来像"上下文敏感语法",这并不适合LPEG,我将假设您想要构建一个抽象语法树。

在Lua中,AST可以表示为嵌套的(带有命名和索引字段)或闭包,执行该树的任何任务。

两者都可以通过嵌套的LPEG 捕获的组合产生。

我将把这个答案限制为AST作为一个Lua表。

在这种情况下,最有用的LPEG捕获将是:
  • lpeg.C( pattern )—简单捕获,
  • lpeg.Ct( pattern )——表捕获,
  • lpeg.Cg( pattern, name )——命名组捕获。
以下基于代码的示例将生成一个简单的语法树作为Lua表:
local lpeg = require'lpeg'
local P, V = lpeg.P, lpeg.V
local C, Ct, Cg = lpeg.C, lpeg.Ct, lpeg.Cg
local locale = lpeg.locale()
local blank = locale.space ^ 0
local space = P' ' * blank
local id = P'_' ^ 0 * locale.alpha * (locale.alnum + '_') ^ 0
local NS = P{ 'ns',
                  -- The upper level table with two fields: 'id' and 'entries':
    ns          = Ct( blank * 'namespace' * space * Cg( V'ns_id', 'id' )
                    * blank * Cg( V'ns_body', 'entries' ) * blank ),
    ns_id       = id,
    ns_body     = P'{' * blank
                         -- The field 'entries' is, in turn, an indexed table:
                       * Ct( (C( V'ns_entry' )
                       * (blank * P',' * blank * C( V'ns_entry') ) ^ 0) ^ -1 )
                       * blank * P'}',
    ns_entry    = id
}
  • lpeg.match( NS, 'namespace foo {}' )将给出:
    table#1 {
        ["entries"] = table#2 {
        },
       ["id"] = "foo",
    }
    
  • lpeg.match( NS, 'namespace foo {AA}' )将给出:
    table#1 {
        ["entries"] = table#2 {
            "AA"
        },
       ["id"] = "foo",
    }
    
  • lpeg.match( NS, 'namespace foo {AA, _BB}' )将给出:
    table#1 {
        ["entries"] = table#2 {
            "AA",
            "_BB"
        },
       ["id"] = "foo",
    }
    
  • lpeg.match( NS, 'namespace foo {AA, _BB, CC1}' )给出:
    table#1 {
        ["entries"] = table#2 {
            "AA",
            "_BB",
            "CC1"
        },
       ["id"] = "foo",
    }
    

相关内容

  • 没有找到相关文章

最新更新