【问题标题】:Is it possible to build Lisp-like macros into an imperative language?是否可以将类似 Lisp 的宏构建成命令式语言?
【发布时间】:2013-07-29 18:25:41
【问题描述】:

是什么阻止了像 C 这样的语言拥有 Lisp 宏? C 在编译过程中的哪个阶段放弃了操作其代码树的能力?

而且,这具体是解释还是编译问题?

【问题讨论】:

  • “是什么阻止了像 C 这样的语言拥有 Lisp 宏?” - 其创造者的理智。
  • Perl6 有类似 C 的 Algol 语法,它应该有 parse time subs and operator overloading
  • Nemerle 是一种在语法上更类似于 C 语言的示例,它具有类似 Lisp 的宏。但我对此知之甚少。 HaXe 也有类似的宏系统。然而,C 存在固有的问题,尤其是与维护相关的问题,这使得复杂的宏不受欢迎。调试就是这样一个问题,语法的原始歧义和大量鲜为人知但仍然有效的编写相同内容的方法是另一个问题。这可以解释为什么早期对 C 进行改进的尝试与使用宏的想法(想想 D、ADA 等)作斗争
  • 完全有可能 - 看看 Nemerle、Converge、PFront、Template Haskell、MetaOCaml、MetaLua 和其他类似语言。

标签: c compiler-construction macros lisp language-design


【解决方案1】:

Haskell 提供了强大的类型宏:

http://www.haskell.org/ghc/docs/7.0.2/html/users_guide/template-haskell.html

就 C 而言,我认为这源于 C 的设计试图保持简单,以便程序的语义易于理解(与 C++ 不同,它有许多允许创建 DSL 的特性)

【讨论】:

    【解决方案2】:

    语法问题

    是的,您可以在命令式语言中使用类似 Lisp 的宏,因为 Lisp 支持命令式编程。 C 和 Lisp 中的宏的主要区别在于操作源代码树的难易程度:

    • 在 C 中,有声明、声明符、语句、表达式、块、一些不同的控制结构、标签等。新的句法结构可能需要更改解析器。宏将需要构建这些数据结构。

    • 在 Lisp 中,只有 s 表达式。新的句法结构不需要对解析器进行任何更改。只有一种数据结构意味着构建语法树的API非常简单易记。

    有些语言的语法更复杂(如 C),但它们具有强大的宏功能(如 Lisp)。例如,哈斯克尔。但是,在 Haskell 中编写宏的接口要复杂一些,因为您需要用于创建和应用类型构造函数、表达式、声明、表达式等的函数,而不仅仅是列表的单个构造函数。

    Haskell 中宏中的模板具有类型注释:

    [e| ... |] -- expression
    [d| ... |] -- declaration
    [t| ... |] -- type
    [p| ... |] -- pattern
    

    相比之下,这些字母 edtp 在 Lisp 宏中是不需要的。这些在 Haskell 中是必需的不是,因为 Haskell 是强类型的,而是因为注释将解析器置于正确的状态,因此它可以使用正确的上下文解析内容。同样,Lisp 语法只有一个上下文。

    解释与编译

    大多数语言都可以解释、编译或同时进行。 C 可以是其中之一,也可以是两者。 Lisp 可以是其中的一个,也可以是两者。宏要求编译器在编译时执行代码,这可以通过解释宏代码或编译宏然后执行它来完成。所以解释型与编译型真的不是问题(在几乎所有关于语言的讨论中都不是问题)。

    【讨论】:

    • 虽然我喜欢这个答案,但我认为使用 Haskel 作为命令式语言的例子有点牵强。 :)
    • @wvxvw:我将它用作语法复杂(与 Lisp 相比)但具有复杂模板的语言的示例。但是,它也是一种很棒的命令式语言。见:stackoverflow.com/questions/6622524/…
    【解决方案3】:

    对于某些“类 C”的定义,Rust 无疑是一种类 C 语言,它有一个 Scheme-like macro system

    【讨论】:

      【解决方案4】:

      您可以在 C 中使用一些更强大的预处理器,例如 gpp 可以用作更强大的 cpp 替代品,同时保持与它完全兼容。

      但是gppcpp 一样适用于文本表示,而不适用于抽象语法树。

      您可以自定义您的 C 编译器(特别是 GCC):例如,通过使用 MELT 扩展 GCC - 您可以添加自己的内置函数和编译指示,并在编译器中更改优化。

      使用 MELT,您主要处理 GCC 中的树和 Gimple 内部表示。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-08-21
        • 1970-01-01
        • 2012-01-24
        • 1970-01-01
        • 2021-10-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多