Is it possible to build Lisp-like macros in an imperative language?

What prevents a language like C from having Lisp macros? At what point in the compilation process does C refuse to manipulate its code tree?

And is this specifically interpreted or compiled problem?

+8
c compiler-construction macros language-design lisp
source share
4 answers

Syntax Issues

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

  • In C, there are declarations, declarations, statements, expressions, blocks, several different control structures, labels, etc. New syntax constructs may require changes to the parser. Macros will need to build these data structures.

  • In Lisp, only s-expressions exist. New syntax constructs do not require changes to the parser. Only one data structure means that the API for constructing the syntax tree is very simple and easy to remember.

There are several languages ​​with more complex syntax (for example, C), but with powerful macro objects (for example, Lisp). For example, Haskell. However, the interface for writing macros in Haskell is somewhat more complicated, because you need functions to create and use type constructors, expressions, declarations, expressions, etc., and not just for one constructor for lists.

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

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

For comparison, these letters e , d , t and p not needed in Lisp macros. They are not needed in Haskell because Haskell is strongly typed, but because annotations put the parser in the correct state so that it can parse the contents with the appropriate context. Again, Lisp syntax has only one context.

Interpreted and compiled

Most languages ​​can be interpreted, compiled, or both at the same time. C may be one or both. Lisp can be one or both. Macros require the compiler to execute code at compile time, which can be done either by interpreting the macro or compiling the macro and then executing it. Thus, interpreted-versus-compiled is really not a problem (this is not a problem in almost every discussion of languages).

+16
source share

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

+2
source share

Haskell typed macros that are just as powerful:

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

In the case of C, I think this is due to the fact that C-design is trying to simplify the task, so the semantics of the program are easy to understand (unlike C ++ with its many functions that allow you to create DSL)

+1
source share

You can use a more powerful preprocessor with C, for example, gpp can be used as a more powerful replacement for cpp while staying fully compatible with it.

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

You can customize your C compiler (in particular, GCC ): for example, by extending GCC with MELT - you can add your own built-in functions and pragmas and change the optimization in the compiler.

With MELT, you mainly work on the internal views of the tree and Gimple inside GCC.

+1
source share

All Articles