This has been done — or rather, independently discovered as a technique — many times, and appears to be an interesting and powerful technique. I researched this possibility some time ago and categorised “C in S-expressions” implementations into two types:
“C” code in S-expression form is interpreted by a Lisp interpreter in an environment with appropriate symbols. Execution of the program constructs an AST on which further transformations can be performed, or causes C code to be output. (This allows you to use macros and generate code programmatically, etc. You’re generating C by executing a Lisp program.)
“C” code in S-expression form is parsed and analyzed by a program, but the program is not executed as a Lisp program. The parser may still be implemented in Lisp to take advantage of Lisp’s affinity for S-expressions and macro processing. (Essentially, the S-expressions are input to a compiler supporting a custom — but non-Lisp — language designed for translation to C.)
In any case, examples of S-expression-to-C systems (some of these links may have dropped off the internet by now):
I have some very rough and unpublished notes about this sort of thing and other ‘preprocessing’ technologies which people might find interesting: https://www.devever.net/~hl/lr
Another use for S-expressions or DSLs built in full-on Lisp environments is typesetting. I have my own typesetting system which is basically just a set of macros and functions in a Guile Scheme environment, which generates an SXML S-expression in a custom XML schema then translated either to XHTML or TeX, or fed directly into ConTeXt using its XML support. And again, I’m far from the only one to discover that Scheme makes a nice typesetting environment (nicer than XML, certainly); you can find many such Lisp-based typesetting systems. One nice feature of these systems allow direct lexical references to terminology, preventing typos:
;; Define terminology.
(dt pci-device "PCI device" "A PCI, PCI-X or PCI Express device.")
(define (some-chapter)
(p "A "pci-device" supports blah blah blah:")
(p "..."))
(This takes advantage of the fact that the S-expression syntax doesn’t mind symbols appearing next to quoted strings without whitespace; I tend to tell my eyes to “forget” I’m looking at a string constant, and read this code as though the quote marks referencing a term are opening a string, rather than ending a string and starting a new one. Lawyers seem to like to put terminology in quotes, so this is a vaguely familiar kind of ‘English’ to read.)
Nope, I just decided to make my own to do exactly what I want. I subsequently learned of Pollen and many similar systems, which I’m sure are great. It’s a very powerful approach and SXML is probably the most pleasant way to generate and work with XML.
If people want an interesting rabbit hole to dive down, take a look at ConTeXt and its XML support. There be dragons!
In the example, how does it know that n is an int?
The type defaults to int unless explicitly specified. The return type
#f is equivalent to int. So to define a fib in sexpc that takes and
returns an unsigned int, we’d say:
(fun (unsigned int) fib (((unsigned int) n))
(if (<= n 1) 1 (+ (fib (- n 1)) (fib (- n 2)))))
Can it be used with other editors than Emacs?
It’s just a Unix filter,
and it doesn’t require any editor at all. The homepage shows an example
of how to use it with emacs by defining an elisp function to call out to
the filter binary. You’d need to write your own scaffolding to use it
from your editor of choice.
This has been done — or rather, independently discovered as a technique — many times, and appears to be an interesting and powerful technique. I researched this possibility some time ago and categorised “C in S-expressions” implementations into two types:
“C” code in S-expression form is interpreted by a Lisp interpreter in an environment with appropriate symbols. Execution of the program constructs an AST on which further transformations can be performed, or causes C code to be output. (This allows you to use macros and generate code programmatically, etc. You’re generating C by executing a Lisp program.)
“C” code in S-expression form is parsed and analyzed by a program, but the program is not executed as a Lisp program. The parser may still be implemented in Lisp to take advantage of Lisp’s affinity for S-expressions and macro processing. (Essentially, the S-expressions are input to a compiler supporting a custom — but non-Lisp — language designed for translation to C.)
In any case, examples of S-expression-to-C systems (some of these links may have dropped off the internet by now):
I have some very rough and unpublished notes about this sort of thing and other ‘preprocessing’ technologies which people might find interesting: https://www.devever.net/~hl/lr
Another use for S-expressions or DSLs built in full-on Lisp environments is typesetting. I have my own typesetting system which is basically just a set of macros and functions in a Guile Scheme environment, which generates an SXML S-expression in a custom XML schema then translated either to XHTML or TeX, or fed directly into ConTeXt using its XML support. And again, I’m far from the only one to discover that Scheme makes a nice typesetting environment (nicer than XML, certainly); you can find many such Lisp-based typesetting systems. One nice feature of these systems allow direct lexical references to terminology, preventing typos:
(This takes advantage of the fact that the S-expression syntax doesn’t mind symbols appearing next to quoted strings without whitespace; I tend to tell my eyes to “forget” I’m looking at a string constant, and read this code as though the quote marks referencing a term are opening a string, rather than ending a string and starting a new one. Lawyers seem to like to put terminology in quotes, so this is a vaguely familiar kind of ‘English’ to read.)
Thank you for the excellent summary. To your list, I’ll add: sph-sc built with Guile.
Regarding the typesetting, there is also something like Pollen, implemented in racket. Is there a reason you prefer your own implementation to it?
I really love that approach to using sexprs for generating html, it just works so well together.
Nope, I just decided to make my own to do exactly what I want. I subsequently learned of Pollen and many similar systems, which I’m sure are great. It’s a very powerful approach and SXML is probably the most pleasant way to generate and work with XML.
If people want an interesting rabbit hole to dive down, take a look at ConTeXt and its XML support. There be dragons!
Related: https://aphyr.com/posts/353-rewriting-the-technical-interview
Awesome! I’ve been looking for something like this.
In the example, how does it know that
n
is anint
?Can it be used with other editors than Emacs?
The type defaults to int unless explicitly specified. The return type #f is equivalent to int. So to define a fib in sexpc that takes and returns an unsigned int, we’d say:
It’s just a Unix filter, and it doesn’t require any editor at all. The homepage shows an example of how to use it with emacs by defining an elisp function to call out to the filter binary. You’d need to write your own scaffolding to use it from your editor of choice.