Eigene Programmiersprache
-
Tippgeber schrieb:
Dabei könnte der Interpreter ja wenigstens per Kommandozeilenparameter beim Parsen der Methoden-Definition warnen wenn die nicht mit self anfängt. Statt dessen geht es erst beim Aufruf schief und wer sonst normale Sprachen gewohnt ist vergisst das schonmal
Der Bezeichner
self
ist eine reine Konvention, das geht also nicht so einfach.BTW F# hat etwas ähnliches. Es muss auch explizit ein
self
-Parameter (der auch nicht so heißen muss) angegeben werden, der aber syntaktisch an seiner natürlichen Stelle steht, so dass man ihn (eigentlich?) nicht vergessen kann. Etwa so:member self.eineMethode y = self.z * y
(Disclaimer: Bin noch beim Lernen und syntaktisch nicht so sattelfest.)
-
Bashar schrieb:
Tippgeber schrieb:
Dabei könnte der Interpreter ja wenigstens per Kommandozeilenparameter beim Parsen der Methoden-Definition warnen wenn die nicht mit self anfängt. Statt dessen geht es erst beim Aufruf schief und wer sonst normale Sprachen gewohnt ist vergisst das schonmal
Der Bezeichner
self
ist eine reine Konvention, das geht also nicht so einfach.Dass ist mir bewusst, aber es ändert nichts an der Möglichkeit Warnungen dafür zu unterstützen. Ob man den Namen nun direkt mit self vergleicht ist mit einem Namen der als Kommandoargument angegeben wurde spielt dafür ja keine rolle. Ansonsten stellt sich noch die frage wie viele Leute hier etwas anderes verwenden
-
Tippgeber schrieb:
Dass ist mir bewusst, aber es ändert nichts an der Möglichkeit Warnungen dafür zu unterstützen. Ob man den Namen nun direkt mit self vergleicht ist mit einem Namen der als Kommandoargument angegeben wurde spielt dafür ja keine rolle. Ansonsten stellt sich noch die frage wie viele Leute hier etwas anderes verwenden
Was ist ein Kommandoargument?
Aber wie willst du wissen ob folgender code OK ist oder das self vergessen wurde:def f(a,b,c): return a.foo + b.foo + c.foo
ist a jetzt korrekt self oder nicht?
-
Shade Of Mine schrieb:
Was ist ein Kommandoargument?
Er meint beim Aufruf des Interpreters.
python --self=this
würde dann erlauben, dass der self-Parameterthis
heißt. Eine Methode ohnethis
würde dann bei ihrer Definition eine Warnung hervorrufen.
-
Bashar schrieb:
Shade Of Mine schrieb:
Was ist ein Kommandoargument?
Er meint beim Aufruf des Interpreters.
python --self=this
würde dann erlauben, dass der self-Parameterthis
heißt. Eine Methode ohnethis
würde dann bei ihrer Definition eine Warnung hervorrufen.Und wie würde man das mit externen Libraries machen?
Ich müsste dann ja quasi pro .py Datei definieren können wie self heisst.Ne, einfach immer self verwenden und statische code analyse verwenden um solche Fehler zu finden. Aber um ehrlich zu sein, ich hatte noch nie einen Bug in einer Python Anwendung der auf ein fehlendes self zurückzuführen war...
-
es wirkt aber trotzdem hochgradig künstlich, wie umgeschult auf objektorientiert.
-
Für meine experimentellen Programmiersprachen habe ich folgende Komponenten benötigt:
- Lexer
- Parser
- Erstellung von deBruijn-Indizes oder Symbol-Tabellen
- Typ-Inferenz oder Typ-Checker (falls erwünscht)
- Interpreter oder Code-Generator
Für Lexer und Parser kann man sich einfache Parser-Kombinatoren schreiben, dann braucht man keinen Parser-Generator.
DeBruijn-Indizes sind hilfreich, um in den Stack oder in Umgebungen zur Laufzeit zu indizieren.
Für Typ-Inferenz braucht man Unifikation; Typ-Checker sind in der Regel einfacher zu schreiben. In Sprachen wie Python gehört der Checker zur Laufzeit-Umgebung.
Wenn man eine Sprache kennt, die der eigenen ähnlich ist, bietet sich zunächst ein Code-Generator für diese Sprache an, das macht am Anfang am wenigste Arbeit.
C/C++ geht natürlich als Zielsprache, sofern kein garbage collector benötigt wird.
Ein Interpreter macht zwar ein wenig mehr Arbeit, aber auch mehr Spaß bei Benutzung.Auf jeden Fall fängt der Stress erst nach dem Parsen an, denn zu Parsern findet sich im Internet viel.
Wenn man nicht alles verstehen will, sondern nur die Sprache bauen will, bieten sich Bibliotheken an.
Man kommt auch ohne aus, aber mit gehts schneller:- Parsec, JParsec, FParsec, scala.util.parsing.combinator, Boost::Spirit, je nach Sprache für Lexer/Parser
- Tabellen finden sich in den meisten Sprachen, für die Erstellung von deBruijn-Indizes benutzt man funktional Listen, imperativ kann man einen Stack benutzen.
- Als Typ-Inferenz könnte man Prolog benutzen oder "constraint-programming"-Bibliotheken. (letztere hab ich noch nie benutzt)
- Als Code-Generator kann man die LLVM in C++ oder OCaml benutzen. .NET bietet "Reflection", um bytecode zu erstellen.
Funktionale Sprachen (Haskell/ML/F#/Scala) sind zu empfehlen, um den Compiler/Interpreter zu schreiben, aber nicht zwingend notwendig, C# oder Python gehen auch. Funktionaler Code ist in der Regel kürzer.
Als Inspiration für Typ-Systeme oder neue Programmiersprachen kann Types&Programming Languages dienen,
Parser-Kombinatoren und deBruijn-Indizes sind in MLftw erklärt, ebenso wie der Lambda-Kalkül.
In das Drachenbuch habe ich mal reingelesen um LALR-Parser zu verstehen, aber das war nicht so schön erklärt und eher weniger verständlich. Ich kenne aber nur die deutsche Version, vielleicht ist die englische besser.Ich hoffe, dass die Anregungen helfen! Je mehr Leute verstehen wie man Compiler schreibt, desto besser!
-
Danke alf42red für den guten Beitrag.
Aber eine neue Frage. Meine Sprache ist mittlerweile für triviale Sachen zu gebrauchen, bis jetzt interpretiere ich sie.
Jetzt habe ich mich gefragt, ob es zufälligerweise eine primitive Metasprache + passenden Compiler gibt, um Binaries zu erzeugen. Zum Beispiel dass ich eine XML-Representation meines ASTs erzeuge und das kompilieren kann. (Einen eigenen Code-Generator schreiben oder mit LLVM würde ich ungern machen, würde lieber mehr high-level bleiben und etwas auf dem Niveau von XML ausgeben).Mich stört es nämlich gerade etwas, die Eigenheiten von C++ erdulden zu müssen, die teilweise auch limitieren.
-
Du kannst deine Sprache auch nach C(++) konvertieren und dann kompilieren.
-
Das Drachenbuch ist total wirr und unverstaendlich geschrieben. Keine Ahnung, wieso das Ding ein Standardwerk sein soll. Vielleicht weil man sich selber unglaublich schlau fuehlen kann, wenn man sowas empfiehlt (so a la "ich hab das Buch verstanden und alles damit verstanden").
-
Ethon schrieb:
Jetzt habe ich mich gefragt, ob es zufälligerweise eine primitive Metasprache + passenden Compiler gibt, um Binaries zu erzeugen.
Vielleicht C--.
-
maximAL schrieb:
Du kannst deine Sprache auch nach C(++) konvertieren und dann kompilieren.
Mache ich ja zur Zeit. Aber zb Metainformationen (und davon generiere ich gewaltige Mengen, ist ja Teil des Konzepts) müssen zur Laufzeit in eine HashMap gestopft werden, das könnte theoretisch bei Nutzcode die Startzeiten unangenehm drücken. Ich hätte die Hashtable lieber bei der Kompilierung fertig da. Klar könnte man das mit einem MTP-Feuerwerk irgendwie zusammenfrickeln, hab ich aber irgendwie wenig Lust drauf.
-
Ich habe vor einigen Jahren auch begonnen eine Programmiersprache zu entwickeln, die - obwohl ich noch keine Version rausgegeben habe - schon eine gewisse Historie besitzt.
Vom Drachenbuch rate ich ebenfalls ab. Zum Thema Parserbau ist es uninteressant und bei der semantischen Analyse - also da, wo es spannend wird - hält es sich recht bedeckt.
Es ist ein Must-Have, aber kein Must-Read.@Ethon: Mein Focus liegt auf praktischem Nutzen. Ich möchte eine Sprache, die sehr restriktiv arbeitet, um den Programmierer semantisch prüfbare Fehler möglichst nicht zu erlauben. Wenn er ein "Hello World" programmieren soll und schreibt ein "Salut Monde" kann ich natürlich auch nix mehr machen.
Welche Metadaten möchtest Du sammeln und vor allem warum?
-
Welche Metadaten möchtest Du sammeln und vor allem warum?
Ich halte es für eine coole Idee, über ein Netzwerk nativen Code senden und ausführen zu können. Das ganze aber komplett ohne Festplattenaktivität und sicher.
Deswegen schippt jedes Modul Metainfo über alle Funktionen oä mit, ob sie threadsafe ist, welche Parameter sie erwartet etc.Damit zb soetwas funktioniert:
remote_module io("http://example.com/io.mod") io::file "test.txt" => test io::write test "Hello from io"
Hier muss zur Runtime gecheckt werden ob es eine Klasse file in io gibt, ob es eine Funktion gibt um ein Objekt von einem String zu kontruieren, das selbe für write. Sobald das geschehen ist wird mit Funktionszeigern gearbeitet, dh. der Overhead schwindet.
-
Ethon schrieb:
Welche Metadaten möchtest Du sammeln und vor allem warum?
Ich halte es für eine coole Idee, über ein Netzwerk nativen Code senden und ausführen zu können. Das ganze aber komplett ohne Festplattenaktivität und sicher.
"Sicher" ist da so ein Punkt, wenn Daten aus dem Internet kommen.
Nativer Code geht auch nicht, denn wer sagt denn, dass ich mit einem Intel-kompatiblen Rechner das Programm ausführen möchte?Hier müssen also noch einige Schichten dazwischen geplant werden.
Und es stellt sich automatisch die Frage, ob die Aufgabe clientseitig oder serverseitig ausgeführt werden soll. Eine Sprache, die Netzwerkunterstützung voraussetzt, sollte hier ebenfalls einen Plan haben.
Die Idee ist "cool". Aber Maßstab sollte sein, ob's praktisch ist.
Lass Dir von mir nichts ausreden, den Spruch in der Signatur habe ich, weil man mir auch immer sagt, dass das, was ich mache, nicht gemacht werden kann.Ethon schrieb:
Deswegen schippt jedes Modul Metainfo über alle Funktionen oä mit, ob sie threadsafe ist, welche Parameter sie erwartet etc.
Damit zb soetwas funktioniert:
Okay, hier kommen wir wieder überein, das ist nicht ganz das, was ich unter Meta-Inforamtion erwartet habe.
Du suchst hier weniger eine neue Programmiersprache als ein alternatives Objekt-Format. Das von Dir beschriebene könnte nahezu direkt über C++ abgedeckt werden. Wozu also eine neue Sprache, wenn Du Dein Problem mit einer vorhandenen erweitern kannst? Zumal Du den Lernaufwand für die Nutzer gering hältst.
-
Wie gesagt, das Ganze ist in erster Linie zum Spaß bzw zum Lernen da, deswegen versuch ich es so aufzubauen, wie es möglichst wenig andere Sprachen machen. Zu 99.99% wird die Sprache nie produktiv genutzt werden.
Nativer Code geht auch nicht, denn wer sagt denn, dass ich mit einem Intel-kompatiblen Rechner das Programm ausführen möchte?
Das Modul soll zumindestens mitschippen, auf welcher Plattform mit welchem OS das Ganze lauffähig sein soll, da kann der Loader zur Laufzeit noch meckern, wenn er da etwas falsches vorgesetzt bekommen hat. Wie man es am Besten machen kann dass genau das richtige Modul geladen wird ... keine Ahnung.
Warscheinlich am besten mit Namenskonventionen.
Und es stellt sich automatisch die Frage, ob die Aufgabe clientseitig oder serverseitig ausgeführt werden soll. Eine Sprache, die Netzwerkunterstützung voraussetzt, sollte hier ebenfalls einen Plan haben.
Stimmt.
Du suchst hier weniger eine neue Programmiersprache als ein alternatives Objekt-Format. Das von Dir beschriebene könnte nahezu direkt über C++ abgedeckt werden. Wozu also eine neue Sprache, wenn Du Dein Problem mit einer vorhandenen erweitern kannst? Zumal Du den Lernaufwand für die Nutzer gering hältst.
Naja, zum Beispiel den Aufruf von nicht threadsicheren Funktionen zu blockieren, wenn die aufrufende Funktion als threadsicher markiert wurde etc, scheint mir per C++ nicht möglich zu sein.
-
Ethon schrieb:
Wie gesagt, das Ganze ist in erster Linie zum Spaß bzw zum Lernen da, deswegen versuch ich es so aufzubauen, wie es möglichst wenig andere Sprachen machen. Zu 99.99% wird die Sprache nie produktiv genutzt werden.
Da habe ich ein anderes Ziel. Ich meine das durchaus ernst und hoffe dieses Jahr erste Quelltexte für meine Sprache in meiner Sprache formulieren zu können.
Ethon schrieb:
Nativer Code geht auch nicht, denn wer sagt denn, dass ich mit einem Intel-kompatiblen Rechner das Programm ausführen möchte?
Das Modul soll zumindestens mitschippen, auf welcher Plattform mit welchem OS das Ganze lauffähig sein soll, da kann der Loader zur Laufzeit noch meckern, wenn er da etwas falsches vorgesetzt bekommen hat. Wie man es am Besten machen kann dass genau das richtige Modul geladen wird ... keine Ahnung.
Warscheinlich am besten mit Namenskonventionen.
Namenskonventionen sind leicht zu handhaben und dafür schwer abzusichern.
Warum sollen die Codes eigentlich aus dem Netz statt von der Festplatte kommen? Was ist der Hintergedanke?
Ethon schrieb:
Du suchst hier weniger eine neue Programmiersprache als ein alternatives Objekt-Format. Das von Dir beschriebene könnte nahezu direkt über C++ abgedeckt werden. Wozu also eine neue Sprache, wenn Du Dein Problem mit einer vorhandenen erweitern kannst? Zumal Du den Lernaufwand für die Nutzer gering hältst.
Naja, zum Beispiel den Aufruf von nicht threadsicheren Funktionen zu blockieren, wenn die aufrufende Funktion als threadsicher markiert wurde etc, scheint mir per C++ nicht möglich zu sein.
Sind Threads das einzige Problem, was Du lösen möchtest?
Grundsätzlich könntest Du alles was nicht Threadsafe ist als private Member einer Klasse machen. Damit wäre das Problem sprachtechnisch schon eingegrenzt. Du kommst aus dem unsicheren Code an den sicheren, aber nicht umgekehrt.
Es gibt schönere Lösungen. Auch eine kleine Erweiterungen am C++-Compiler bietet sich an. Aber das Problem ist gut überschaubar und alleine kein Grund für eine neue Sprache.
Vieles kannst Du semantisch bereits herausfinden, dann geht es also eher um eine Erweiterung der Fehlererkennung.Du schriebst "zum Beispiel". Also gibt es noch mehr?
Wenn das Ziel nur ist, nur mal aus Spaß eine Sprache zu schreiben, dann ist das ein ziemlich aufwendiger Spaß, den imho auch Firmen wie Microsoft bei der Entwicklung von C# unterschätzt haben. Zumindest liest sich die Begründung, weshalb man Const-Correctness weggelassen hat, viel interessanter, wenn man sich Gedanken darüber macht, wie man selbst Const-Correctness implementieren will. Was man sich an Design-Debts mit der zu frühen Veröffentlichung von c# ins Boot gezogen hat, sei mal dahingestellt.
Boxing wurde mir noch als tolle Technik präsentiert, die C# irgendwie genial macht. Marketing für Fortgeschrittene. Das war wohl void *.Wenn Du lernen willst, dann versuch Vorhandenes nachzuvollziehen und die Regel dahinter zu finden. Wenn Du soviele Ideen hast, dass es für eine neue Sprache reicht, dann ergibt sich das. Ideen bekommst Du, wenn Du Funktionsaufrufe und die grundlegenden Operatoren und Konstrukte implementiert (if!) hast. Ab da beginnt das ganze greifbar zu werden.
-
Macht das mit einer eigenen Programmiersprache und wartet auf die Resonanz möglicher Anwender. Wenn man damit Geld verdienen will, ist das ganz sicher schwer zu machen und wohl auch nicht notwendig!