8

What is preventing a language like C from having Lisp macros? At what point in the compilation process does C forego the ability to manipulate its code tree?

And, is this specifically an interpreted vs. compiled issue?

sdasdadas
  • 23,917
  • 20
  • 63
  • 148
  • 2
    "What is preventing a language like C from having Lisp macros?" - the sanity of its creators. –  Jul 29 '13 at 19:51
  • @H2CO3 We can always substitute those. :) – sdasdadas Jul 29 '13 at 19:51
  • 1
    You mean, like this: http://programmers.stackexchange.com/questions/53441/are-c-templates-just-a-kind-of-glorified-macros – Will Hartung Jul 29 '13 at 20:18
  • 1
    Perl6 has Algol syntax like C and it's supposed to have [parse time subs and operator overloading](http://perl6advent.wordpress.com/2011/12/22/day-22-operator-overloading-revisited/) – Sylwester Jul 29 '13 at 22:00
  • 2
    Nemerle is an example of a language more similar syntactically to C, which has Lisp-like macros. But I don't know much about it. HaXe also has similar macro system. There are however, inherent problems with C, especially those related to maintenance, which make complex macros undesirable. Debugging is one such problem, original ambiguity of syntax and plethora of less known but still valid ways of write the same thing is another one. This may explain why early attempts of improve upon C fought against the very idea of having macros (think D, ADA etc.) –  Jul 30 '13 at 10:10
  • 1
    It's perfectly possible - take a look at Nemerle, Converge, PFront, Template Haskell, MetaOCaml, MetaLua and other similar languages. – SK-logic Jul 30 '13 at 13:27
  • Common Lisp is an imperative language with Lisp-style macros. (Like many imperative languages, Common Lisp has first class functions and a syntax for anonymous functions so it also allows functional programming, but idiomatic Common Lisp includes many imperative techniques such as using global variables for configuration and `push`ing values onto a list and then `nreverse`-ing it.) – Omar Antolín-Camarena Jul 31 '13 at 17:08

4 Answers4

16

Syntax issues

Yes, you can have Lisp-like macros in an imperative language, because Lisp supports imperative programming. The main difference between macros in C and Lisp is how easy it is to manipulate the source tree:

  • In C, there are declarations, declarators, statements, expressions, blocks, a handful of distinct control structures, labels, etc. New syntactic constructs might require changes to the parser. Macros will need to construct these data structures.

  • In Lisp, there are only s-expressions. New syntactic constructs require no changes to the parser. Only one data structure means the API for constructing a syntax tree is very simple and easy to remember.

There are some languages with more complicated syntax (like C) but which have powerful macro facilities (like Lisp). For example, Haskell. However, the interface for writing macros in Haskell is somewhat more complicated, since you need functions for creating and applying type constructors, expressions, declarations, expressions, etc., instead of just a single constructor for lists.

A template in a macro in Haskell has its type annotated:

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

By comparison, those letters e, d, t, and p are not needed in Lisp macros. These are necessary in Haskell not because Haskell is strongly typed, but because the annotations put the parser in the correct state so it can parse the contents with the proper context. Again, the Lisp syntax only has one context.

Interpreted versus compiled

Most languages can be interpreted, compiled, or both at the same time. C can be either or both. Lisp can be either or both. Macros require the compiler to execute code at compile-time, which can be done either by interpreting the macro code, or by compiling the macro and then executing it. So interpreted-versus-compiled is really a non-issue (it is a non-issue in almost every discussion about languages).

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • While I liked the answer, I think that using Haskel as an example of imperative language is a bit farfetched. :) –  Jul 30 '13 at 09:30
  • @wvxvw: I was using it as an example of a language with complicated syntax (compared to Lisp) but which has sophisticated templates. However, it is also a great imperative language. See: http://stackoverflow.com/questions/6622524/why-is-haskell-sometimes-referred-to-as-best-imperative-language – Dietrich Epp Jul 30 '13 at 17:06
2

Rust, which is certainly a C-like language for some definitions of "C-like", has a Scheme-like macro system.

Paul Stansifer
  • 1,239
  • 9
  • 10
1

Haskell has typed macros which are as powerful:

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

In the case of C, I think it stems from the fact that C's design tries to keep things simple, so that a program's semantics is easy to understand (unlike C++ with its many features that allows creation of DSLs)

tohava
  • 5,344
  • 1
  • 25
  • 47
1

You could use some more powerful preprocessor with C, for instance gpp can be used as a more powerful cpp replacement while staying quite compatible with it.

But gpp, like cpp works on textual representations, not on abstract syntax trees.

You could customize your C compiler (in particular, GCC): for instance by extending GCC with MELT - you can add your own builtins and pragmas and change optimizations in the compiler.

With MELT you mostly work on the tree and Gimple internal representations inside GCC.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547