Sxc – An s-expression based language source transpiler for C
github.com
github.com
I remember finding it was hard to remember how many parens to use where. For example is it (if (condition) (statement)) or is it (if (condition) (list of statements))? If it's the former you have to explicitly call out multi-statement if with something like progn, like (if (== foo 3) (progn (= foo 4) (return))), which doesn't feel very C-like, while if you pick the latter option it's easy to get the syntax wrong, when you have single-statement blocks because you need to double-paren them, like (if (== foo 3) ((return)). When you're writing scheme this isn't such a problem because it tends to be expression-oriented, but when you're writing C with a different syntax I found it pretty confusing.
(if* (== foo 3) then (foo 4) (return))
[1] https://github.com/shirok/Gauche/blob/master/lib/gauche/cgen...
[2] https://github.com/shirok/Gauche/blob/master/ext/bcrypt/bcry...
It was really just a prototype at first. I was going to have a more pascal-like syntax in the end, but the prototype was fast enough, and manually parsing was more trouble than it was worth.
So, we don't write all of our code in sexprs, but have a preprocessor (PPP - the pascal pre-processor) that reads a sexpr version of pascal and generates code accordingly.
- pixie (sexp + python + llvm)
- pharen (sexp + php)I don't know how people keep missing this (like, for instance, Lispyscript): newsflash, people: syntax-rules is considered inadequate for many types of macros by the community that invented it. If you want the full power of sexprs, you need to actually have the ability to traverse them.
In addition, syntax-rules is based on a DSL. If you want to build a macro that cannot be expressed in that DSL, or is hard to exress in that DSL (fairly common), tough.
With imperative hygienic macros (provided they give you control over hygene), or imperative unhygienic macros, this isn't a problem.
HOWEVER... various bugs can be easily introduced if your macros are not hygienic. For many use cases, syntax-rules will suffice, but when you use syntax-case you must explicitly break hygiene.
It is a parallel situation to languages like Rust where unsafe operations are sometimes required, and therefore provided by the language but you must explicitly flag them "unsafe".
>This is why R7RS has syntax-case.
It doesn't. In fact, sc-macro-transformer is a candidate for inclusion in r7rs-large.
>HOWEVER... various bugs can be easily introduced if your macros are not hygienic.
That's true, but you're confusing hygienic/unhygienic with imperative/declarative. sc-macro-transformer, syntax-case and friends are all hygienic imperative macro systems. So none of that matters.
What I particularly like about this is the C s-exp syntax. The s-exp C actually feels like C. It does not introduce additional tokens to identify functions or types.
This approach could be generalized to write transpilers for other languages with C-like syntax (Java, JavaScript, C++, etc).
The "industrial-strength" alternative in the open-source world is just to parse C into an AST; several important projects like the Frama-C analyzer (and, IIRC, the Cocinelle project best-known for "spatch") use CIL (https://people.eecs.berkeley.edu/~necula/cil/), and of course many recently-started projects use the LLVM infrastructure.
sexpr's do make the AST more obvious than relying on an external compiler, but you need to write a lot of macro's before "more-convenient macro's" beat "more-convenient code".
I object! The choice between this and straight C isn't completely up to personal preference; using s-expressions gives you objectively more power because it lends itself to lisp macros, which are really the strongest reason to use any lisp at all.
https://swtch.com/gosling89ace.pdf
Well, minus the "using Lisp" part.
So, I could program super-fast in a high-level BASIC with C output. LISP was worth using to reduce effort as I have no idea how I'd do all of that in just BASIC or C with what little experience I had.
ALso, this allows for far greater compile time data generation for static initialization. Even files can be loaded in to do away with runtime IO, building programs that are closer to self contained 'images' rather than a collection of files.
How about an (unfinished) common lisp to go transpiler?
Terra looks nicer to me, mostly because of syntax, but I can see those two projects having about the same power