Pretty.c – Scripting auf C
(github.com/aartaka)- Pretty C ist eine neue Scripting-Sprache, die mit C kompatibel ist und C-Programmen Komfortfunktionen wie dynamische Typisierung, generische Iteration und Ressourcenverfolgung hinzufügt
- Verwendet wird es als Header-only-Bibliothek, indem lediglich
pretty.heingebunden wird; es kann zusammen mit bestehenden C-Dateien und C-Bibliotheken genutzt werden - Zu den bereitgestellten Funktionen gehören Aliasse wie
string,anyundnil, Typinferenz mitvar/let, generische Ausgabe mitprint/println, generischer Vergleich mitequalsowie besser lesbare ternäre Makros - Um Wiederholungen und Speicherarbeit zu reduzieren, bietet es eine makrobasierte Syntax wie
foreach,forthese,fortimes,forrange,new,vector,delete,with,lambdaundtry/catch - Einige Funktionen setzen GCC, Clang, C23+ oder C11+ voraus; zudem sind mit
withgebundene Variablen vom Typvoid *, sodass vor der Nutzung möglicherweise eine Typumwandlung nötig ist
Ziele und Nutzung von Pretty C
- Pretty C ist eine mit C kompatible Scripting-Sprache, die C-Programmen dynamische Typisierung, generische Iteration, Ressourcenverfolgung und verschiedene Syntax-Erleichterungen hinzufügt
- Die Abwärtskompatibilität zu bestehendem C und C-Bibliotheken bleibt erhalten
- Inspiriert von Lua, Python, JavaScript und Lisp
- Zur Installation kann das Repository geklont oder einfach nur die Datei
pretty.hkopiert und verwendet werden- Einbindung in beliebige C-Dateien mit
#include "pretty.h" - Alternativ kann der Pretty-C-Pfad auch im Include-Pfad angegeben werden
- Einbindung in beliebige C-Dateien mit
Standardmäßig eingebundene Header und einfache Makros
- Pretty C bindet Standard-Header ein, damit häufig verwendete Typen und alternative Operatordarstellungen sofort verfügbar sind
- Außerdem werden häufig definierte einfache Makros bereitgestellt
max,min: Maximum und Minimum zweier Zahlenlen: Array-Längedefault: stellt einen Fallback-Wert bereitlimit: begrenzt einen Wert auf einen Bereichbetween: prüft, ob eine Zahl in einem Bereich liegtdivisible: prüft, ob sie ohne Rest durch eine andere Zahl teilbar ist
Typen und Aliasse
- Pretty C bietet kurze Typ-Aliasse für C-Typen
stringistchar*byteistcharbytesistchar*anyistvoid*- Als Kurzformen für Ganzzahlen gibt es
uchar,ushort,uint,ulong
- Enthalten sind auch von Lua und Lisp beeinflusste Syntax-Aliasse
eq,is:==bitnot,bitxor: Aliasse für Bit-Operationensuccess,fail,failure: Aliasse für das Mustersuccess == 0below,above,upto,downto: Vergleichsoperatoreneven,odd,positive,negative,zero,empty: Prädikate für Zahlen und Datennil:NULLuntil: negierteswhileelif:else ififnt,elifnt: Ausdrücke der Formif(!...)repeat: Lua-artiger Alias fürdodone,finish,pass: Aliasse fürbreak,continuealways,forever,loop,indefinitely: Ausdrücke für Endlosschleifennever,comment: Ausdrücke, mit denen Code nicht ausgeführt wird, aber weiterhin vom Compiler analysiert werden kann
Typinferenz, Ausgabe, Vergleich und ternäre Ausdrücke
- Typinferenz ist mit GCC, Clang oder C23+ verfügbar
- Beispielhaft werden Formen wie
var t = time(0);,let lt = localtime(&t);,local at = asctime(lt);bereitgestellt
- Beispielhaft werden Formen wie
- Generische Ausgabe ist ab C11+ verfügbar
printgibt den übergebenen Wert ausprintlnfügt nach der Ausgabe einen Zeilenumbruch an
- Generischer Gleichheitsvergleich wird ebenfalls über C11+-Funktionen bereitgestellt
- Zeichenkettenvergleich wie
equal("NA", line) - Enthalten ist auch ein Beispiel wie
equal(0.3, 0.2 + 0.1)
- Zeichenkettenvergleich wie
- Der ternäre Operator kann mit textbasierten Makros lesbarer gemacht werden
whenexpandiert zu einem leeren String zur besseren Lesbarkeitunlessexpandiert zunotund fungiert als verneinte Form vonwhenthenist?otherundotherwisesind:onlywird verwendet, wenn keinotherwise-Zweig nötig istotherwhenwird verwendet, um die nächste Bedingung anzuhängen
Iterationsmakros
- Pretty C abstrahiert häufig verwendete
for-Schleifenmuster über Makros foreach (var, type, length, ...)- Iteriert über ein Array oder einen Speicherbereich
- In jeder Iteration ist
varein Zeiger auf das jeweilige Array-Element - Da es ein Zeiger ist, kann das Element bei Bedarf direkt an Ort und Stelle verändert werden
forthese (var, type, ...)- Iteriert über die übergebenen variadischen Argumente und bindet jeden Wert an
varvom Typtype
- Iteriert über die übergebenen variadischen Argumente und bindet jeden Wert an
fortimes (var, times)- Reduziert das übliche Muster einer Wiederholung von 0 bis zu einer positiven Anzahl
forrange (var, init, target)- Iteriert über einen Zahlenbereich von
initbistarget initundtargetkönnen beliebige signed oder unsigned Integer sein- Ist
initgrößer alstarget, wird die Schrittweite negativ
- Iteriert über einen Zahlenbereich von
forrangeby (var, type, init, target, by)- Iteriert mit
vardes angegebenentypevoninitbistargetin Schritten vonby
- Iteriert mit
Allokation und Block-Hilfsfunktionen
- Allokationsmakros vereinfachen, in von C++ beeinflusster Form, typische Muster der Speicherallokation
new (type, ...): erzeugt Strukturen usw. in einer Form ähnlich zu C++newvector (length, type, ...): vereinfacht das Muster, ein Array mit angegebener Länge und Typ zu allokieren und mit Anfangsinhalten zu versehendelete (...): entsprichtfree, kann aber verwendet werden, wenn ein C++-artiger Name bevorzugt wird
- Block-Hilfsfunktionen bieten Makros für lokale Bindungen, verzögerte Ausführung und blockweise Operationen
lambda (ret, name, ...): ermöglicht unter GCC, Clang oder C++ verschachtelte Funktionen, Lambdas oder Closures in Cwith (var, close, ...): stellt die Freigabefunktionclosevorab bereit und ist nützlich für dynamisch allokierte Objekte oder Dateihandles- Nachteilig ist, dass das gebundene
varvom Typvoid *ist und vor der Nutzung eventuell in den gewünschten Typ umgewandelt werden muss
- Nachteilig ist, dass das gebundene
defer: wurde entfernt; stattdessen wird auf ein neu verfügbaresdeferverwiesentryundcatch: ermöglichen eine auffälligere Schreibweise für Fehlerbehandlung in CNOERR,NOERROR: werden als Komfortfunktionen für Fehler-switch-casebereitgestellt
Beitragen
- Beim Hinzufügen von Funktionen wird gebeten, den Linux Kernel Style Guide zu befolgen
- Vor dem Commit wird empfohlen,
make indentauszuführen
- Vor dem Commit wird empfohlen,
- Das Befolgen von A’s Commit Message Guide wird bevorzugt, ist aber nicht verpflichtend
1 Kommentare
Meinungen auf Hacker News
Die Tradition, in C domänenspezifische Sprachen zu bauen, ist alt.
Stephen Bourne wollte die Shell in ALGOL schreiben, also bearbeitete er den C-Präprozessor hartnäckig so lange, bis sie wie seine bevorzugte Sprache aussah.
https://www.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd/sh...
https://www.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd/sh...
https://www.ioccc.org/
Ich frage mich, ob jemand erklären kann, ob das ein Witz ist oder ob der Autor wirklich verwirrt ist.
Nichts davon ergibt Sinn. Es ist kein „Scripting“, es behauptet, „starke Typisierung“ einzuführen, tut aber nichts mit Typen, und die an Lua und Lisp angelehnten Operator-Aliase gibt es in keiner der beiden Sprachen. Gleichzeitig wirkt es aber auch nicht wie eine offensichtliche Parodie, was es wirklich verwirrend macht.
Es behauptet, eine Scripting-Sprache zu sein, aber man muss das Programm weiterhin kompilieren. Buhrufe dafür.
Wenn man CINT (https://root.cern.ch/root/html534/guides/users-guide/CINT.ht...) einbindet, bekommt man sofortige Ausführung und auch eine REPL.
Ich habe früher einmal einen Blogbeitrag gesehen, der ausführlich behandelte, wie
./foofunktioniert und wie ELF-Dateien ausgeführt werden. Auf dieselbe Weise könnte man wohl auch.c-Programme registrieren, sodass sie kompiliert und anschließend ausgeführt werden.[0] https://gist.github.com/jdarpinian/1952a58b823222627cc1a8b83...
[0] https://bellard.org/tcc/tcc-doc.html
„Es bietet genug syntaktischen Zucker, um C-Entwicklern einen diabetischen Herzinfarkt zu verpassen.“
Diese Formulierung ist wirklich gut.
Ich sehe ein paar Dinge, die zu CNoEvil[0] und ogw[1] hinzugefügt werden sollten. Jedes Mal, wenn dieses Projekt alle paar Monate wieder auftaucht, scheint es mehr davon zu geben.
[0] https://git.sr.ht/~shakna/cnoevil3/
[1] https://git.sr.ht/~shakna/ogw
Ein Satz, den man wirklich von Herzen lieben muss.
Das macht denselben Fehler wie Python 2. Strings und Bytes sind nicht derselbe Typ und sollten auch nicht so behandelt werden.
argvoder die Ausgabe von Unterprozessen?Darin kann beliebiger Müll stehen, also ist es kein gültiger UTF-8-String, aber Tools wie awk und grep werden überall verwendet.
Man kann Strings und Bytes als denselben allgemeinen Typ ansehen, wobei es manchmal nützlich ist, gültigen UTF-8-Bytes intern einen anderen Typ zu geben. Rust löst das mit OsString und String größtenteils gut.
https://en.cppreference.com/w/c/string/multibyte
Nichts davon ist immer wahr. Es ist nützlich, eine validierte Byte-Sequenz in einen Typ zu verpacken, der nur durch Validierung erzeugt werden kann, aber wenn man das tut, gehören
Utf8StringundEmailAddressim Grunde zur selben Kategorie. Es gibt keinen Grund, im Typsystem nur die Kodierung besonders zu behandeln.Wenn damit „für Menschen lesbarer Text“ gemeint ist, stimme ich zu, dass ein String nicht dasselbe ist wie ein beliebiges Byte-Array. Viele Sprachen erzwingen diese Definition aber nicht.
Erinnert mich an eine C++-Codebase, die ich früher einmal überprüfen musste. Das Ganze war so, als wäre es in Java geschrieben: CamelCase für alles, Getter/Setter für alle Klassenvariablen und überall Interfaces
https://minnie.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd...
Es ist schwer zu glauben, dass das nicht ALGOL ist
std::stringumhüllte, aber mit Java-artigen Methoden versehen warhttps://learn.microsoft.com/en-us/cpp/cpp/property-cpp?view=...
f(String *)übergeben wurden, sodass der C++-Code dann etwaf(new String("Hello")warWenn dich das interessiert, könnte dir auch libcello.h gefallen
https://www.libcello.org
Die Typnamen sind gut, und auch die Auswahl der Built-in-Funktionsmakros wie
minist perfekt.Lengefällt mir ebenfallsBenannte boolesche Operatoren sind vielleicht etwas übertrieben, aber einen Versuch wert; der ternäre Operator ist ohnehin schwer lesbar, da gibt es also viel Verbesserungspotenzial. Von allen Schleifendefinitionen bin ich nicht ganz überzeugt, aber einige ergeben Sinn. Das Ressourcen-Tracking ist beeindruckend, und die
for...-Form sieht etwas hässlich aus, da könnte man wohl einen anderen Namen findenInsgesamt ein ziemlich solider Versuch. Für das Design würde ich etwa 8/10 geben. Die Art, wie es mit C-Makros skizziert ist, ist wirklich elegant und sieht tatsächlich nach gutem Code aus. Ob ich es selbst verwenden würde, weiß ich nicht. Es ist eine neue Sprache, und ich mag C ohnehin schon. Trotzdem ist die Implementierung sehr klar, sodass sie Leuten helfen kann, C zu lernen und über Sprachdesign nachzudenken
len(),max/minund ein paar Operator-Makros. Die anderen netten Features habe ich bisher nicht wirklich gebraucht. Also probier ruhig schon ein paar der Operator-Makros ausWenn
ifntfürif(!...)gedacht ist, wirkt unless lesbarer alsifntfor(;;)-Schleifealwayszu nennenIn anderen Sprachen habe ich
loopgesehen. Qt nennt es aberforever, und das ist wirklich hübsch. Auch sehr Qt-typischifntlaut auszusprechenunlesshabe ich für ternäre Bedingungen reserviert. Dort ist es schließlich nützlicherAch, Moment, das ist ja John Tromp. Der Erfinder von BLC! Ich bin Fan