所以我正在玩lpeg来取代一个提升精神语法,我必须说boost :: spirit比lpeg更优雅和自然。然而,由于当前C ++编译器技术的限制和C ++中的TMP问题,它是一个麻烦。在这种情况下,类型机制是你的敌人,而不是你的朋友。另一方面,Lpeg虽然丑陋和基本,但会带来更高的生产力。
无论如何,我很离题,我的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(" \t\n")^0,
SPACE_WS = P(" ") * V("WS")
}
return namespace_parser
end
此语法(虽然不完整)与以下namespace foo {}
匹配。我想实现以下语义(这是使用boost精神时常见的用例)。
namespace IDENTIFIER {
匹配后,将名称空间数据结构添加到此本地变量。NAMESPACE_BODY
以进一步构建AST ...依此类推。我确信这个用例是可以实现的。没有例子表明它。我不知道语言或图书馆足以弄清楚如何去做。有人可以显示它的语法。
编辑经过几天尝试与lpeg共舞,并让我的脚步上了,我决定回到灵魂:D显然lpeg意味着要编织具有lua函数,并且这种编织是非常自由的形式(而精神有明确的文档记录)。我还没有正确的lua心理模型。
答案 0 :(得分:1)
尽管“为命名空间规则创建局部变量”听起来像“对上下文敏感的语法”,这对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",
}