是否可以在C ++中编写一个将值绑定到变量名称的edsl?例如,我可以在Haskell中编写一个edsl,允许我编写以下(see also this question):
prog3 :: StackProg Expr
prog3 = do
push (IntL 3)
push (IntL 4)
a <- pop
b <- pop
return (Plus a b)
这会产生一个AST,其中a
和b
是变量。 C ++中有类似的东西吗?我希望(按重要性顺序)
答案 0 :(得分:2)
不,你不能用C ++直接建模。但是,在C ++中,您可以嵌入其他引擎,例如Lua,它通常用作扩展引擎,适用于DSL。
Check out this answer, also in StackOVerflow
在C ++中嵌入Lua的步骤:
答案 1 :(得分:2)
如果要生成有效C ++表达式的语法(可能作为所有C ++表达式的子集,就像do-notation将自身限制为monad操作一样),静态验证它们并使用它们,那么最好的选择是{{3 }}。为了简洁地描述它,它本身就是编写和描述EDSL的EDSL。
我不会详细介绍如何使用它。虽然可能很难学会使用,特别是如果你不习惯C ++元编程,文档很棒,如果你曾经写过语法我相信你会找到你的分数。在Boost.Proto中,我向某人介绍了如何使用只接受简单算术表达式的语法来编写EDSL,并使用它们来计算它们的导数,因此您可能需要检查它。
至于你的确切问题,我担心答案必须是短暂的“不,你不能那样做”,或者说“你可以做到这一点,就像Boost.Phoenix所展示的那样,但是考虑到您的EDSL用户的神秘错误和/或额外的编译时间,它可能不值得您花时间实现它“。我的理由是你想做的事情适合两个层面:do-notation是一个Haskell特定的功能,同时消耗语法树并在EDSL本身的层面上给它语义。
正如它所发生的那样,典型的Proto风格的EDSL是有效的C ++表达式,并且该语言不提供该级别的范围,变量在单独的语句中声明。例如,_a + _b
是一个有效的C ++片段,因为_a
和_b
是由Phoenix提供的C ++变量,但不是EDSL中的有效程序,因为_a
和{{ 1}}未绑定。是的,错误将被捕获,但您必须自己实现。相比之下,do-notation是Haskell的一部分,因此任何EDSL都可以免费继承它。也就是说,_b
本身永远无效 - 需要有一些return (a + b)
和一些a
。
但有些事情要记住。 C ++ 11提供了lambda表达式,所以你实际上可以在这里得到一些范围 - 但是在EDSL中它们是不透明的,语法树只会显示一个变量。一些内省可能会发现该变量对于某些类型是可调用的,但就是这样。即使你要求lambda在EDSL中返回一个值,也没有告诉他们可以做什么。这并不总是值得担心,我会说它非常适合某些EDSL。
类似地,C ++ 11使得“分解”EDSL表达式的部分变得更加容易。这并不等同于符号的b
糖,但它相当于a <- foo
。所以你可以毫无困难地让下面的事情做'正确的事':
let a = foo
这可能相当于单一和人为的以下内容:
auto double_pop = make_tuple(pop(), pop());
auto program = (push(3), push(4), consume(double_pop));
(因为Boost.Proto最初是作为C ++ 03库开始的,所以在使用C ++ 11 program = do
let a = pop
return consume `ap` a `ap` a
之前一定要仔细检查文档,IIRC有一个警告。)