Software & Apps

Github – medelful / c_plus_prolorolong: c plus prolog

Prolog is the only good programming language. I will know, my website is Prolog wrote.

Unfortunately, C is the only useful programming language.

Scientists try to find a response to this problem for almost 50 years. Others make their C More to prolog. Others make their Prolog is more like c.

I offer a new solution: simply add prolog and c to go together. I call it, “C Plus Prolog”, or “C + P” for short.

:- include(stdio).

int func main
{ 
	puts("Hello, world!");
	return 0
}.

If you are familiar with C, you notice that it is a different strange, bad C. You are mistaken. It is valid prolog, using some Non-standard swi-prolog parts for curly braces.

This prol is read as a list of terms, and converted to valid C code. Is this:

int func main(int var argc, char:ptr:array var argv)

It is translated:

int main(int argc, char*( argv()))

Beyond some obvious changes such as var and func Operators, making syntax bright as prolog, have some unexpected quirks:

  • Symbols starting with capital letters or underscores for use in prolog, and do not translate c except for the quote:
int:ptr var string = 'NULL';
'_Bool' var v = true;
  • As a result of the above, characteristics literally begin with #:
char var c = #c;    % quotes not required for lowercase letters
char var c2 = #'C'; 
char var nl = #'\n';
  • The operator first is maintained for those in Prolog users. For example, = and comparison operators want ==,, <and > have the same advance, so you need parents where you don’t go to C:

So is this reason why the arrow operator -> replaced by @Because it’s used in a perfectly different prolog means and has a perfectly different time.

C + P:

C:

  • Complex statements of type are different. The statements of the C-style are fully informed of the prolog, I do not want them.

Can

It can also help you remember the difference between const char * and char const *:

const(char):ptr,
char:const(ptr)

Examples give a more complete photo of syntax. Finally, it is but more burning and particularly in semicolons. Not exactly a silver bullet.

Let’s introduce the *=> Operator.

Get this snippet from Example 04:

max(A, B) *=> A > B then A else B.

I say c + p is not processed without resolving C terms, but it is a small step. The compiler gathers all the terms described *=>and then replace the left hand for the right hand of the remaining code until no rules available.

Because it works in the terms of prolog, not text, we do not need any additional crooks in our max(A, B) Macro to prevent errors in the operator first. This code is inserted as a term, and looks like a function call used:

float var f = max(12.3, 0) + 20;
printf("Should be 32.3: %f\n", f);`

It has been converted to the following C:

float f=(((12.3>0) ? 12.3 : 0)+20);
printf("Should be 32.3: %f\n", f);

Also, I’m tired of adding \n At the end of all my printf statements. We define another macro, println:

PrintLn *=> PrintF :-
	PrintLn =.. (println,Format| Args),
	string_concat(Format, "\n", Format2),
	PrintF =.. (printf,Format2| Args).

We have full prologue access at compiling time :-that we are allowed to do anything. This macro is obtained any instance println(Format, Args...) with a string literally Formatand it converted to printf with a new line involved Format.

Simply enough. Let’s apply the generics of the poor man.

Poor difference in poor poor at C Plus PLANG

Example 05 describes a generic type, list(T)Using the following syntax:

list(T)
{
	struct list(T) {
		T:ptr:ptr var items
	};

	% Let's also define syntax for type-specific functions, in this caselist(T):capacitysize_t:ptr func list(T):capacity(list(T) var this)
	{
		...
	};
	...
}.

This works the same with C ++ templates. For simplicity to implement, we require the user to insert the template.

declare(list(int)).
declare(list(const(char):ptr)).

We can do this automatically by scanning the code for any use of list(T) And fix the template right over it, but I leave that as an exercise for the reader.

We also have some syntax to get a name function list(T):Method:

int func main {
	list(int) var my_ints = list(int):new(17);

	size_t var size = *(list(int):capacity(my_ints));
	for(int var i = 0; i < size; i += 1)
	{
		list(int):append(my_ints, i*i)
	};
	for(int var i = 0; i < size; i+= 1)
	{
		printf("%d squared = %d.\n", i, list(int):get(my_ints, i))
	};
	return 0
}.

Not exactly C ++, but it prevents namespaces.

Let’s read Macro.

This corresponds to our template as you expected:

Name(T) {Body} *=> Comment :-
	\+ground(T), atom(Name),
	atom_concat('//Defined template type: ', Name, Comment),

We have a template with a name Nametype parameters Tand the body Body. Macro has taken this code and enter a comment. Everything is directed to the prolog world.

	assertz(
		declare(Name(Z)) *=> NewBody

To God. Our macro asserts in a macro, declare(Name(Z)). It also has conditions:

		:- (
			ground(Z),
			T=Z,
			Body=NewBody,

Those three lines are most macro. This Template type is united T with real (ground) type ZThen return the body to the template. This is the turn declare(list(int)) to code for type.

But that’s not all, the macro that strikes himself expressing more macros:

			('*mangled_name'(Name(Z)) *=> ZName),
			assertz(Name(Z) *=> ZName),
			assertz((ZName:Method *=> ZMethod :-
				% Crudely hacking some shorthand for method names
				Method \= ptr, Method \= array,
				(	atom(Method)
				->	MName = Method,
					ZArgs = ()
				;	Method =.. (MName|ZArgs)
				),
				('*mangled_name'(ZName:MName) *=> MZ_Name),
				ZMethod =.. (MZ_Name|ZArgs)
			))
		)).

This makes names in C list(int) and list(int):function. '*mangled_name' Just another macro, but this instance is long and it’s all in the example 05. The * and the quote is nothing special, they just keep this macro from an unintentional collision with a mean user mangled_name function.

C + P provides bad information we can use for syntax method, to make something like my_list.append(...)instead of list(int):append(my_list, ...).

Of course we can, use macros to gather each variable in a body function and a charming idea, but I have an interesting idea, but I have an interesting idea, but I have an interesting idea, but I have an interesting idea, but I have an interesting idea, but I have an interesting idea, but I have an interesting idea Ideas, but I have an interesting idea, but I have an interesting idea, but I have an interesting idea, but I’m preparing.

I give many other examples of wonders of C Plus Plost:

  • Example 06 overloaded to struct Keyword to add accumulation to offer on time.
  • Example 08a gathers in different code if the target file ends with .h or .cto express a typical header and implement a file.

I know it’s compelling to write C + P, adding parts impossible. It’s like a puzzle game, which is why I can always get to the prolog.

C plus prolog easily installed. All you need is a C compiler, Swi-Prolog, and this repository. You can find it.

Then you can run cpp.pl From this repository of the following syntax:
swipl -s cpp.pl --

By convention, c additional props of the extension prop .c+p.

CHECKS test.sh and test.ps1 For the added example of use, plus a fast way to run all tests (which may not be rooted).

What is this point?

The C Plus PLOG is one half intense exploration of macros in a programming program. In this process of doing this, it clearly I want to compare time to check and meditation offered in languages ​​such as D and Zig in syntactic macros.

Sure, with enough work you can do everything and more than the macro system, but what is true increase In a separate code generator, or a DSL? A better interface, perhaps.

In common seeds, you have full-time congEbase at the time of accumulation, but the actual value is to resign Runtime code, not manipulate a list of lists such as code and comas.

Retail processing procedure

Most of my metaprogramming wants to involve meditation on the information that compiler has already known, such as code types and annotations. For a language-within-a-language, which syntactic macros are best at, I’d usedually rather go the extra mile and make an entirely separate DSL with a purpose-built syntax, rather than contort the problem to, say, s expressions or prolog terms.

However, C + P is dangerously almost useful. The biggest advantage is the fact that it makes it simple C by default, allowing for more popular tongues with no car support in different abstractions. Prologue is about 50 years, as well. If exi-prolog extensions have been removed, swapping func F {Body} OTHERS func F => BodyFor example, it will be built in a large hardware swath.

But I don’t want to use it. There is absolutely no validation or error messaging, so any wrongdoing errors lead to broken co silent failures. I thought used var As an operator becomes good, but it’s a lot of visual noise. And if you think the semicolons of c enraged, in C plus prolog, semicolon operators. With two in a row that breaks things. Having someone starting to start things. With one of Finally breaks things.

If someone wants to use c + p, there are many best replacements.

  • the Nim and Bristen Languages ​​can assemble C and / or C ++, and they offer a great user experience from the box, even if I can’t say how directly their code translates C.
  • CMACRO Offers a similar level of syntax maneuver to C + P in a better format, powered by common seed.
  • The dine There are GCC and LLVM-backed arrangements, so it should work in most places C will.

I don’t know what is the conclusion.


https://opengraph.githubassets.com/ad364136b67c925563d28fc550096723a4437b1f4375fe9579b652a2999d5dbb/needleful/c_plus_prolog

2025-03-14 01:48:00

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button