2

是否可以在 C++ 中编写将值绑定到变量名的 edsl?例如,我可以在 Haskell 中编写一个 edsl,它允许我编写以下内容(另请参阅此问题)

prog3 :: StackProg Expr
prog3 = do
  push (IntL 3)
  push (IntL 4)
  a <- pop
  b <- pop
  return (Plus a b)

这会产生一个 AST whereabare 变量。在 C++ 中是否有类似的可能?我想要(按重要性排序)

  • 生成的 edsl 可接受的语法,
  • 明智的 AST
  • 对象 (dsl) 语言中的类型安全
  • 可理解的力学。
4

2 回答 2

2

不,你不能直接用 C++ 建模。但是,在 C++ 中,您可以嵌入其他引擎,例如 Lua,它通常用作扩展引擎,适用于 DSL。

查看这个答案,也在 StackOverflow 中

在 C++ 中嵌入 Lua 的步骤:

  1. 这是 Lua 的网页
  2. 在此处下载源代码
  3. 将 Lua 集成到您的 C++ 应用程序中。
于 2013-02-21T09:07:17.797 回答
2

如果您想生成有效 C++ 表达式的语法(可能作为所有 C++ 表达式的子集,就像 do-notation 将自身限制为 monad 操作一样),静态验证它们并使用它们,那么您最好的选择是Boost.Proto。简而言之,它本身就是一个 EDSL 来编写和描述 EDSL。

我不会详细介绍如何使用它。虽然它可能很难学会使用,特别是如果你不习惯 C++ 元编程,文档很棒,如果你曾经写过语法,我相信你会找到你的标记。在我的另一个答案中,我向某人介绍了如何使用仅接受简单算术表达式并消耗它们来计算它们的导数的语法编写 EDSL,因此您可能需要检查一下。

至于您的确切问题,恐怕答案必须是简短的“不,您不能那样做”,或者是长的“您可以在 Boost.Phoenix 显示的范围内做到这一点,但可能不是考虑到您的 EDSL 用户的隐秘错误和/或额外的编译时间,值得您花时间实施它”。我对此的推理是您想要做的事情适合两个级别:do-notation 是 Haskell 的特定功能,同时在 EDSL 本身的级别上使用语法树并为其赋予语义。

碰巧的是,典型的 Proto 风格的 EDSL 是有效的 C++ 表达式,并且该语言不提供该级别的范围,变量在单独的语句中声明。例如,_a + _b是一个有效的 C++ 片段,因为_a_b是由 Phoenix 提供的声明的 C++ 变量,但在 EDSL 中不是一个有效的程序,因为_a_b未绑定。是的,错误将被捕获,但您必须自己实现。相比之下,do-notation 是 Haskell 的一部分,因此任何 EDSL 都免费继承它。也就是说,return (a + b)它本身永远不会有效 - 需要有 somea和 some b

不过有一些事情要记住。C++11 提供了 lambda 表达式,因此您实际上可以在这里获得一些作用域——但这些在 EDSL 中是不透明的,语法树只会显示一个变量。一些自省可能会揭示该变量对于某些类型是可调用的,但仅此而已。即使您要求 lambda 在 EDSL 中返回一个值,也不知道它们还能做什么。这并不总是值得担心,我会说它非常适合某些 EDSL。

类似地,C++11 使“分解” EDSL 表达式的部分变得更加容易。这并不等同于a <- foodo-notation 的糖,但它等同于let a = foo. 因此,您实际上可以毫不费力地使以下操作“正确”:

auto double_pop = make_tuple(pop(), pop());
auto program = (push(3), push(4), consume(double_pop));

这可能相当于单调和人为的以下内容:

program = do
  let a = pop
  return consume `ap` a `ap` a

(由于 Boost.Proto 最初是一个 C++03 库,因此请确保在使用 C++11 之前仔细阅读文档auto,IIRC 有一个警告。)

于 2013-02-22T21:04:14.150 回答