C code generator

Hello all,
I was wondering if anyone has tried to do C code generation using prolog before ?

I’m currently working on an array library where I generate the low level C code for doing the actual computation.
I first generate an AST (so a prolog term) that resemble something like that (the code example is nonsense, just there to illustrate the AST format):

function(void, functionName, [int:arg1, 'int*':arg2, int:arg3[100], (
  for(int:i = 0, i < 100, i++, (
    *arg2 = arg1,
  ))
))

Then, I transform the AST to C tokens using dcg, which after formatting gives C code like this:

void functionName(int arg1, int* arg2, int arg[100]) {
  for(int i = 0; i < 100; i++) {
    *arg2 = arg1;
  }
}

If anyone has done thing like this before, any advice would be welcome.

Here is another idea, by combining automatic compilation (with swipl-ld) of the generated code when loading a prolog module, we could write foreign c module entirely in prolog !

1 Like

GNU-Prolog maybe?

You can do that. Note that you can get a lot closer to C syntax if you use some of SWI-Prolog’s extensions such as declaring {} as a postfix operator. Then this becomes valid syntax:

for(...)
{ ...
}

As SWI-Prolog supports zero-arity compounds, there is no reason not to write C function headers and calls as f(…).

But, if you just want to hand-code C in Prolog source, using “quasi quotations” may be easier on the user.

These things become more interesting if you design a DSL (Domain Specific Language) for which parts can be executed efficiently by generating C for it, i.e., if you can generate the C code from something more high level.

3 Likes

@jan Thank you as always for the thoughtful response :slight_smile:

Ho, I did not think of doing this, it’s very nice. I managed to make ++ and -- postfix operator, so I think I’ll be able to do this with {}.
By the way, ++ and --, they can also be infix operators but the resulting compound is always ++(X). Is there a way to differentiate if the operator was used as an infix or postfix operator ?

Yes, I’ll try to add this too, thanks.

When reading up on lisp, I always stop when hitting subjects like macros and quotes. I could never really understand this.
I have started to read this page on quasiquotations in R: 19 Quasiquotation | Advanced R
But could you explain in a bit more detail how quasi quotations would work for generating C code with just a very small example ?

Yes, so for me the DSL is the strided array library which is used to generate a computation graph that I then lower in C. I believe this is kind of an ideal use case for C code generation.

After reading up a little bit on GNU prolog, it seems that they lower Prolog code to C code.

In my case, it is a little bit more meta, where I want to write C code from Prolog to generate C code.

You mean prefix rather than infix. An infix operator has two arguments, so that is easy. But, ++a and a++ indeed result in the same term. There is no way to distinguish them except for using the term layout information to figure out the positions of the operator and its argument. You can also get access to the positions using term_expansion/4. It easily gets pretty messy though :frowning:

You basically write {|c(Args)||<C code interpolating Args>|}. You find examples in e.g. javascript/4 The quasi quoter implements JavaScript tokenization and allows interpolating Prolog values anywhere into the JavaScript code, respecting e.g, quoted strings. That is a friendly and safe alternative to constructing JavaScript from script fragments and Prolog values. It is good for writing other languages inline, but it is not good if you want to generate other languages based on something more abstract.

1 Like

Yes, indeed.

So, the only way would be to rewrite the term at compile time through term_expansion and differentiate at that point whether it is prefix or postfix. I may try this later.

I just found and read the quasiquotations library.

I think I’ll stick with the prolog AST approach, since my use case is more similar to your second option.

Yes, I misunderstood your question.

I have recently stumbled on a pitfall, which I think is related to the dicts functionnal notation.
I wanted to support the . operator for struct member access like mystruct.mymember with the following code in the dcg grammar:

exp(A.B) -->
    exp(A), ['.'], exp(B).

I’m getting an instantiation error when executing the code and I think it is because swi prolog is applying the functionnal notation for dicts on this code.
Is there a way to reuse the . operator for other things than dicts ?

NB: I know that there was some heated debate over the . operator on dicts in swi-prolog. I don’t want this post to rehash all that. If the answer is no, I’ll just use another functor to represent the . operator.

Yes. Use term or goal expansion to turn the ./2 term into something else. Functional expansion is the very last step, so as long as you get rid of it before, you are fine.

Okay, thanks for the tip.
Does this mean I can’t mix dicts functional notation in the same module where I do the term or goal expansion for the C struct member access ?

Well, if are careful when to rewrite and when not, you can. So, it depends on whether you can identify the terms that relate to C from the stuff that is normal Prolog code.