在C++中具有名称绑定的EDSL
EDSL with name binding in C++
是否可以用C++编写一个将值绑定到变量名的edsl?例如,我可以在Haskell中编写一个edsl,它允许我编写以下内容(另请参阅此问题):
prog3 :: StackProg Expr
prog3 = do
push (IntL 3)
push (IntL 4)
a <- pop
b <- pop
return (Plus a b)
这产生了一个AST,其中a
和b
是变量。类似的东西在C++中可能存在吗?我想要(按重要性排序)
- 得到的edsl的可接受语法
- 合理的AST
- 对象(dsl)语言中的类型安全
- 可以理解的机制
如果你想生成有效C++表达式的语法(可能是所有C++表达式的子集,就像do表示法将自己限制为monad操作一样),静态验证它们并使用它们,那么你最好的选择是Boost.Proto。为了简洁地描述它,它本身就是一个编写和描述EDSL的EDSL。
我不会再详细介绍如何使用它了。虽然它可能很难学会使用,尤其是如果你不习惯C++元编程,文档很好,如果你曾经写过语法,我相信你会找到自己的分数。在我的另一个答案中,我向某人介绍了如何编写EDSL,该语法只接受简单的算术表达式,并消耗它们来计算它们的导数,所以你可能想检查一下。
至于你的确切问题,恐怕答案要么是简短的"不,你不能那样做",要么是冗长的"你可以在一定程度上像Boost.Fenix所展示的那样做,但考虑到EDSL用户的神秘错误和/或额外的编译时间,你可能不值得花时间来实现它"。我对此的推理是,您想要做的事情符合两个层面:do表示法是Haskell特定的功能,同时使用语法树并在EDSL本身的层面上为其提供语义。
碰巧的是,典型的Proto风格EDSL是有效的C++表达式,并且该语言不提供该级别的作用域,变量在单独的语句中声明。例如,_a + _b
是一个有效的C++片段,因为_a
和_b
是Phoenix提供的C++变量,但不是EDSL中的有效程序,因为_a
和_b
未绑定。是的,错误会被发现,但你必须自己实现。相比之下,do表示法是Haskell的一部分,因此任何EDSL都可以免费继承它。也就是说,return (a + b)
本身从来都不是有效的——需要有一些a
和一些b
。
不过有一些事情需要记住。C++11提供lambda表达式,因此您实际上可以在这里获得一些范围——但这些表达式在EDSL中是不透明的,语法树将只显示一个变量。一些内省可能会发现,该变量对某些类型是可调用的,但仅此而已。即使你要求lambdas在EDSL中返回一个值,也无法告诉他们还能做什么。这并不总是值得担心的,我认为这非常适合某些EDSL。
类似地,C++11使EDSL表达式的部分"因子化"变得更加容易。这与do表示法的a <- foo
糖不太等价,但它与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有一个警告。)
不,不能用C++直接建模。然而,在C++中,您可以嵌入其他引擎,例如Lua,它通常用作扩展引擎,适用于DSL。
请参阅StackOVerflow中的答案。
在C++中嵌入Lua的步骤:
- 这是Lua的网页
- 请在此处下载源代码
- 将Lua集成到您的C++应用程序中
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 在基于范围的for循环中使用结构化绑定声明
- 使用 LuaBridge 将 LuaJIT 绑定到C++会导致"PANIC: unprotected error"
- 尝试通过OCI例程从Oracle获取blob数据,但出现错误:ORA-01008:并非所有变量都绑定
- 在使用GPU支持编译Tensorflow时,会遇到CUDA_TOOLKIT_PATH未绑定变量
- 视觉studo 2019中的漫画和静态/动态绑定
- 将自由函数绑定为类成员函数
- 将常量指针引用绑定到非常量指针
- 在派生类中绑定非静态模板化成员函数
- 绑定派生类方法C++从实例范围之外的分隔 std::function 变量调用
- 在 openGL 中多次绑定缓冲区
- 定义有趣的宏和正则表达式在Z3 C++绑定
- 使用结构化绑定'Reflection'
- 为什么 std::绑定错误参数可以成功?
- 如何绑定 C++ gRPC 客户端的网络接口
- 在 openmp 中,omp_get_thread_num是否绑定到物理线程?
- C++绑定(已弃用)
- 运行时错误:引用绑定到类型为"int"的空指针
- 有没有办法将重载的类函数绑定到函数对象?
- 在C++中具有名称绑定的EDSL