Lispc
"Lispsy" Lisp(ish) to C Converter (designed for CLISP)
Install / Use
/learn @eratosthenesia/LispcREADME
LISP/c (Lispsy)
UPDATE
I am working on version 2 again. Sorry it took so long – life happened.
Stay Tuned!
Version 2.0 is coming out very soon. It'll have support for at least SBCL if not a few other versions, and preliminary tests show that it's generating much more readable code (with "proper" indentations and everything).
Installing
To install, simply go into the directory that you downloaded everything into, run clisp, and type (load "c.lisp"). To compile a cl file into a c file, type (c-cl-file source.cl dest.c). To compile and run a cl file, type in (compile-and-run-cl-file file.cl). More documentation on this part to come. <sup><sub>TODO</sub></sup>
NOTE: The way it is currently written, it may have to be loaded more than once. I'm looking into this and refactoring the code to run the first time at the moment. <sup><sub> TODO </sub></sup>
Resources
To learn C, I recommend The C Programming Language by Brian W. Kernighan (ISBN-10 0131103628, ISBN-13 978-0131103627). TO learn LISP, I recommend Practical Common Lisp by Peter Seibel. This can be found either here or as a hard copy (ISBN-10 1590592395, ISBN-13 978-1590592397). Also, it is currently required that you use CLISP to run the code here.. This will change <sup><sub>TODO</sub></sup>.
To learn CUDA, I recommend the resources found here, and to learn MPI, I recommend the resources found here.
Introduction
LISP/c is a powerful macrolanguage for C. It basically turns this:
(header stdio)
(main
(@printf (str "Hello, world!"))
(return 0))
into (after it being cleaned up (more on this later)) this:
#include <stdio.h>
int main(int argc,char **argv)
{
printf("Hello, world!");
return 0;
}
But why?
Why
First, you might check out this video. Because LISP is expressive and C is fast and I wanted the best of both worlds is the short answer. The longer answer has something to do with macros. But instead of immediately boring you with that, I'll answer what you really want to know:
Why Should I Care?
First let's discuss if you can use it. Not to be elitist (I wish everyone would use this tool), but you must know both C and LISP fairly well to be able to use LISP/c.
Suppose, however, that you do already know both LISP and C pretty well. You might want to use LISP/c because it features access to LISP to write C code both implicitly and explicitly. You might also want to use it if you like writing CUDA code, because it has built-in support for CUDA as well.
But really, to see why you might like to use LISP/c, check out a few examples, and feel free to skip around a little.
An Example
Suppose that you're writing a function that you'd like to write for several different types of variable types that use similar notation. You can do this easily with the templates built into LISP/c:
int foo_int(int x, int y) {
return x + y * 2;
}
float foo_float(float x, float y) {
return x + y * 2;
}
// etc.
It's true that you can just use a long macro in C to get rid of the annoying task, but it's a bit awkward. You can do the same in LISP/c using the following notation (with template):
(template make-foo (typ)
(func (add/sym foo- typ) typ ((x typ) (y typ))
(return (+ x (* y 2)))))
(make-foo int) (make-foo long) (make-foo float) (make-foo etc)
Or even like this (with templates):
(templates make-foo (typ)
(func (add/sym foo- typ) typ ((x typ) (y typ))
(return (+ x (* y 2)))))
(make-foos int long float etc)
And just like that, you have a bunch of functions written. Now to get you sort of grounded, let's go through this element by element.
Beyond Templates
If you know what you're doing, you can use lispmacros. One useful example is the following:
(lispmacro class (nym vars)
(c `(progn
(typedef (struct ,nym) ,nym)
(struct ,nym ,vars))))
Then you can write code like
(class cell
(((pt car) cell)
((pt cdr) cell)
((pt etc) void)))
And have it compile to (after cleaning it up a bit):
typedef struct cell cell;
struct cell{
cell *car;
cell *cdr;
void *etc;
};
The lisp/c-macro
This is a form of the template which allows you to write macros directly, more or less. To give you a taste of how this works, we'll start with an example:
(lisp/c-macro for-m (vars nums &rest body)
(if (or (null vs) (null nums))
`(block ,body nil) ;; "NIL" to get rid of extra {}s
`(for (var ,(car vars) int 0)
(< ,(car vars) ,(car ns))
(++ ,(car vars))
,(apply for-m (cdr vs) (cdr ns) body)))))
We can now use this in the following manner:
(for-m (i j k l m) (3 3 3 4 5) (@printf (s. "%d %d %d %d %d") i j k l m))
This will compile to:
for(int i=0;((i)<(3));++(i))
{
for(int j=0;((j)<(3));++(j))
{
for(int k=0;((k)<(3));++(k))
{
for(int l=0;((l)<(4));++(l))
{
for(int m=0;((m)<(5));++(m))
{
printf("%d %d %d %d %d",i,j,k,l,m);
};
};
};
};
}
Arithmetic
In the above example, you'll notice that we use prefix arithmetic. This is a feature of LISP and not of C. The benefit of using prefix arithmetic is that it allows you to express sums of many terms somewhat more succinctly. That is to say, instead of
2 + 3 + 4 + 5 * 6 + 7 + 8 you can just write (+ 2 3 4 (* 5 6) 7 8).
Functions
Functions have the general form:
(func function-name return-type (variables...) body...)
and convert to
return_type function_name(variables...) {
body...
}
If you need a function which returns a pointer to something, you can use:
(func (pt function-name 2) return-type ...)
Which turns into
return_type **function_name(...) {...}
Do note that the 2 is required because there are two *s, but if there were only one, you could just use (pt function-name). That's the flexibility that makes LISP/c nice to work with.
There are two ways that functions can be called. Suppose we want to know the value of foo(2,3,4). We can either use:
(call foo 2 3 4)
or
Simplifying Notation
The following are offered in order to simplify common tasks.
The @ Notation
(@foo 2 3 4)
This is the same thing as (call foo 2 3 4) and evaluates to foo(2,3,4). This is used to greatly simplify function calls. Use this whenever possible, since nobody wants to wade through a bunch of call statements. call is mainly useful for template statements. Note that if you put a space between the foo and @, this becomes foo::2::3::4.
The [] Notation
([]foo 2 3 4)
This is the same thing as (nth 2 3 4) and evaluates to (foo)[2][3][4]. It uses the same rationale as above, as do the next few Notations.
The & Notation
(&foo) is the same thing as (addr foo) and evaluates to &(foo).
The ^ Notation
(^foo bar baz) is the same thing as (cast foo bar baz) and evaluates to (after cleanup) (baz)(bar)(foo).
The * Notation
(*foo) is the same thing as (ptr foo) which evaluates to *foo.
The = Notation
This is in case you want camelcase. (=this is a test) compiles to ThisIsATest (as do (=this is a test), (=this "is-a" test), and (=this-is a-test)). This is one of two cases where "..." are not literal.
The % notation
Exactly the same as above, but the first letter is not capitalized. Viz., (%this is a test) turns out to be thisIsATest.
CamelCase
If you really want camelcase and don't want to type parentheses in every time, you can use =this-is-camelcase and -this-is-camelcase almost anywhere to compile to ThisIsCamelcase and thisIsCamelcase respectively. So you can do something like (-desert-oasis =camel-train -camel-same) and expect it to compile to CamelTrain desertOasis = camel_same.
Thing Names
Variable, type, function, etc. (identifier) names are converted using some simple rules. First of all, the -s are turned into _s. Secondly, everything is lower case. If you need to make something upper case entirely, you can prefix it with a ! (so if you need the variable name CONST_FOO you can use !const-foo, !cOnST-FoO, !const_FOO or "CONST_FOO"). The last one may be used because strings are preserved. The others work because LISP is not case-sensitive, so when the variables are rendered, all case is the same. So if you were to use cOnST-FoO instead of !cOnST-FoO, you'd wind up with const_foo instead of CONST_FOO.
Continuing Forward
We need some sort of framework for showing each of the features of LISP/c. So before I go through every function and explain what it does, I'm going to explain a little of what goes on behind the scenes.
C++ Example
LISP/c can write C++ code as well, and has a few functions which are specifically designed for C++.
Here is the "Hello world!" program written in C++ through LISP/c:
(headers++ iostream)
(using std)
(<<+ cout "Hello world!" endl)
You'll notice that we used <<+ instead of <<. This is because <<+, unlike <<, is meant for streams and does not parenthesize.
Variadic Example
This is a simple function to add up a bunch of arguments that end in zero and are all integers.
(f{} add-em-up int (
(first int)
---)
(var va-list args)
(@va-start args first)
(var sum first)
(var cur first)
(while (!= cur 0)
(= cur (@va-arg args int))
(+= sum cur))
(return sum))
You'll notice that instead of func we used f{}. This i
Related Skills
diffs
341.0kUse the diffs tool to produce real, shareable diffs (viewer URL, file artifact, or both) instead of manual edit summaries.
clearshot
Structured screenshot analysis for UI implementation and critique. Analyzes every UI screenshot with a 5×5 spatial grid, full element inventory, and design system extraction — facts and taste together, every time. Escalates to full implementation blueprint when building. Trigger on any digital interface image file (png, jpg, gif, webp — websites, apps, dashboards, mockups, wireframes) or commands like 'analyse this screenshot,' 'rebuild this,' 'match this design,' 'clone this.' Skip for non-UI images (photos, memes, charts) unless the user explicitly wants to build a UI from them. Does NOT trigger on HTML source code, CSS, SVGs, or any code pasted as text.
openpencil
1.9kThe world's first open-source AI-native vector design tool and the first to feature concurrent Agent Teams. Design-as-Code. Turn prompts into UI directly on the live canvas. A modern alternative to Pencil.
ui-ux-designer
Use this agent when you need to design, implement, or improve user interface components and user experience flows. Examples include: creating new pages or components, improving existing UI layouts, implementing responsive designs, optimizing user interactions, building forms or dashboards, analyzing existing UI through browser snapshots, or when you need to ensure UI components follow design system standards and shadcn/ui best practices.\n\n<example>\nContext: User needs to create a new dashboard page for team management.\nuser: "I need to create a team management dashboard where users can view team members, invite new members, and manage roles"\nassistant: "I'll use the ui-ux-designer agent to design and implement this dashboard with proper UX considerations, using shadcn/ui components and our design system tokens."\n</example>\n\n<example>\nContext: User wants to improve the user experience of an existing form.\nuser: "The signup form feels clunky and users are dropping off. Can you improve it?"\nassistant: "Let me use the ui-ux-designer agent to analyze the current form UX and implement improvements using our design system and shadcn/ui components."\n</example>\n\n<example>\nContext: User wants to evaluate and improve existing UI.\nuser: "Can you take a look at our pricing page and see how we can make it more appealing and user-friendly?"\nassistant: "I'll use the ui-ux-designer agent to take a snapshot of the current pricing page, analyze the UX against Notion-inspired design principles, and implement improvements using our design tokens."\n</example>
