Forth anyone?



  • hi, ich beschäftige mich gerade mit forth, einer programmiersprache aus der zeit der 8-bitter, die ziemlich in vergessenheit geraten ist. was eigentlich recht schade ist, da das konzept einer erweiterbaren wortliste in verbindung mit einer stackmaschine (upn) irgendwie genial ist.

    als begleitliteratur lese ich Leo Brodie's "starting forth".
    als umgebung benutze ich einen in java geschriebenen forth-interpreter (vermutlich forth-79 kompatibel)

    hat jemand noch tipps für mich?
    danke schon mal ... 🙂



  • Hi Retro-Fan,

    retro-fan schrieb:

    da das konzept einer erweiterbaren wortliste

    Ist das nicht eigentlich jedes (ordentliche) Programm?
    Nur woanders heißen sie halt Komponenten, proceduren oder funktionen... Das sind auch nur (selbst oder vom herstelelr) vorgefertigte Arbeitstiere, die mit einem entsprechendne Aufruf zum Arbeiten animiert werden.

    Wenn Du schreibst:

    Programm SchnickschnackRechnen
    {
      Eingeben;
      Berechnen;
      Ausgeben;
    }
    
    und dann schreibst 
    
    Eingeben
    { 
      KursorPositionieren;
      EingabeaufforderungSchreiben;
      EngabeEntgegennehmen;
    }
    ...
    

    Dann ist das nichts anderes als die Bildung neuer Worte in Forth.

    Forth ist damals zur Echzeitsteuerung von Radioteleskopen entwickelt worden. Und auf diesem Sektor liegen auch seine größten Stärken. Du kannst damit auch gut ne Waschmaschine programmieren.

    Für die praktische Anwendung ist es etwas spröde, da die UPN-Schreibweise für normale Programmierer doch ienen ziemlichen Knoten im Kopf erfordert. Außerdem sehe ich die Arbeitsweise als Stackmaschine für größere Projekte als ein wenig sperrig an. Du musst immer zusehen, wie Du die benötigten Parameter in der richtigen Reihenfolge auf den Stack bekommst. Änderungen an einzelnen "weiter unten" steckendne Teilen sind da nicht ganz einfach. An sich ist ja (fast) jeder Prozessor mehr oder weniger eine Stackmaschine, aber es hat schon sienen Grund, warum einem der Compiler die Arbeit damit abnimmt.

    Der wiuchtigste Grund für Forth dürfte damals gewesen sein, dass UPN-Programmierung sehr einfach durch den Compiler oder Interpreter auswertbar ist. Als ich mal einen Formelinterpreter in enem früheren Projekt brauchte, hab ich den auch als UPN-Stackmaschine realisiert, aber das umschreiben der vielen hundert Einzelnen Formeln in die umgekehrt polnische Notation war echt eine Schweinearbeit.

    Als Spaßobjekt und Hobby ist sowas immer gut zu machen, auch um die eigenen Hirnwindungen geschmeidig zu halten..., aber für produktive Zwecken würde ich es nicht mehr nehmen.

    Wenn Du aber wirklich damit arbeiten willst, solltest Du mal nach einem geeigneten Tool suchen (git es) das aus normelen Anweisungen UPN-code macht.

    Gruß Mümmel



  • Naja, die Proceduren sind auch eine Art Wortschatz... stimmt. Aber der Clou bei Forth ist, das diese zur Laufzeit definiert werden.

    Aber ansonsten hat Forth nichts was mich reizen würde. muemmel hat schon den großen Nachteile aufgezählt, nämlich die Umgekehrte polnische Notation. Dagegen ist C und C++ Kindergarten!

    OK, das wäre jetzt echt ungerecht, Forth komplett abzuschreiben. Es gibt einen einzigen Fall, wo ich Forth einsetzen würde: man hat ein nacktes System, das vielleicht nicht mal sowas wie ein BIOS hat. Und man soll da jetzt irgendwas mit drauf machen, weil man höchstens einen Maschinensprachemonitor dafür hat. In dem Fall würde ich mir einen Forth-Interpreter schreiben, um das Henne-Ei-Problem zu lösen... auch bekannt als Bootstrep. Dann könnte man in kleinen Forth-Schritten sich Progrämmchen schreiben um ein BIOS und Interpreter für bessere Sprachen zu erschaffen... und um dann Forth endlich los zu werden. 😃 😉

    Ja, Forth hat seine Berechtigung. Aber ganz bestimmt nicht für den täglichen Einsatz. Sondern da, wo einem nur ganz wenige Hilfsmittel zur Verfügung stehen. Vielleicht noch auf einem kleinen System, wo man nur Assembler nutzen kann, noch kleine Scripte einbetten will ohne groß eine Script-Engine aufzufahren. Aber mehr auch nicht.

    Es gibt übrigens zwei Sprachen, die sich an Forth ohne UPN orientieren. Und die machen dann wirklich Spaß!

    Einmal das aus Amiga-Zeiten bekannte, aber schon lange auf PC portiertes REBOL: http://rebol.com/
    Habe ich damals mit rumgespielt und war doch angetan. Aber irgendwann blieb die Entwicklung stehen.
    Der REBOL-Kern ist deshalb mittlerweile auch Open Source. Aber interessant ist das Gesamtpaket, also mit GUI- und Internet-Runtime. Der Gedanke von Forth ist dort wirklich umgesetzt... ohne UPN.

    Zweiter Kandidat ist http://www.red-lang.org/ Einfach mal anschauen, weil dieses scheint aktiv in Entwicklung zu sein... sozusagen das lebende REBOL.



  • hallo leute, erstmal danke für eure beiträge.

    mummel: eine konverterung infix nach postfix und zurück ist ein standardproblem. dafür gibt es fertige algorithmen. so viel handarbeit ist dazu gar nicht nötig.

    all: upn finde ich gar nicht so schlimm. es war nur am ersten tag gewöhnungsbedürftig aber wenn man verstanden hat wie ein stack funktioniert, dann ist upn doch okay. ich persönlich mag es sogar lieber als die übliche schreibweise.

    ich beschäftige mich nur interessehalber mit forth und glaube, dass die sprache ein ungaubliches potential hat, wenn man sich gut damit auskennt. ich vermute, dass sich vieles damit eleganter lösen lässt als in c oder java.

    dass forth kaum noch jemand kennt, liegt bestimmt einerseits am upn und andererseits an den vielen schlechten implementierungen aus hobbyprogrammierer-bastelküchen.



  • muemmel schrieb:

    retro-fan schrieb:

    da das konzept einer erweiterbaren wortliste

    Ist das nicht eigentlich jedes (ordentliche) Programm?
    Nur woanders heißen sie halt Komponenten, proceduren oder funktionen...

    das kann man nicht vergleichen, weil das Vokabular bei Forth zur Laufzeit erweitert werden kann.

    muemmel schrieb:

    Wenn Du schreibst:

    Programm SchnickschnackRechnen
    {
      Eingeben;
      Berechnen;
      Ausgeben;
    }
    
    und dann schreibst 
    
    Eingeben
    { 
      KursorPositionieren;
      EingabeaufforderungSchreiben;
      EngabeEntgegennehmen;
    }
    ...
    

    Dann ist das nichts anderes als die Bildung neuer Worte in Forth.

    nein, das ist nur ein Spezialfall der Bildung neuer Wörter.

    In Forth kann man während der Erzeugung eines neuen Worts zwischen Compiler- und Interpreter-Zustand umschalten; man kann z.B. während der Compilierung eine Zwischenrechnung durchführen und das Ergebnis in die Wortdefinition einkompilieren.



  • eine wichtige Anwendung von Stackmaschinen ist die als Ziel für Zwischencode oder auch Endcodes von Compilern. Man kann den Zielcode dann auf einer virtuellen Maschinen mit Stackorientiertem Befehlssatz laufen lassen oder die Codes vor dem Laufen in Maschinencodes für echte CPUs umsetzen.

    Wenn man den beim Parsing aufgebauten abstrakten Syntaxbaum in DFS-Ordnung abgrast, entsteht der Code nämlich in genau der Reihenfolge, wie eine Stackmaschine ihn braucht.



  • Sehr empfehlenswert für alle die sich für Programmiersprachen
    interessieren:

    Teil 1: https://github.com/AlexandreAbreu/jonesforth/blob/master/jonesforth.S
    Teil 2: https://github.com/AlexandreAbreu/jonesforth/blob/master/jonesforth.f

    Ich kannte forth vorher nicht und werde vermutlich auch nie damit
    programmieren aber ich bin froh das jetzt mit im Kopf haben.



  • HERE @ SWAP schrieb:

    Ich kannte forth vorher nicht und werde vermutlich auch nie damit
    programmieren aber ich bin froh das jetzt mit im Kopf haben.

    Exotische Sprachen sind immer interessant.
    Hier ein Forth für die JVM, das ziemlich vollständig ist: https://github.com/nietoperz809/JForth

    Vordefinierte Wörter:

    > wordsd
    Words:
    Name: "!", Primitive: true, Immediate: false
    Name: "'", Primitive: true, Immediate: true
    Name: "(", Primitive: true, Immediate: true
    Name: "*", Primitive: true, Immediate: false
    Name: "+", Primitive: true, Immediate: false
    Name: "+!", Primitive: true, Immediate: false
    Name: "+loop", Primitive: true, Immediate: true
    Name: "-", Primitive: true, Immediate: false
    Name: ".", Primitive: true, Immediate: false
    Name: "/", Primitive: true, Immediate: false
    Name: "0<", Primitive: true, Immediate: false
    Name: "0=", Primitive: true, Immediate: false
    Name: "0>", Primitive: true, Immediate: false
    Name: "1+", Primitive: true, Immediate: false
    Name: "1-", Primitive: true, Immediate: false
    Name: "2+", Primitive: true, Immediate: false
    Name: "2-", Primitive: true, Immediate: false
    Name: ":", Primitive: true, Immediate: false
    Name: ";", Primitive: true, Immediate: true
    Name: "<", Primitive: true, Immediate: false
    Name: "<<", Primitive: true, Immediate: false
    Name: "=", Primitive: true, Immediate: false
    Name: ">", Primitive: true, Immediate: false
    Name: ">>", Primitive: true, Immediate: false
    Name: ">r", Primitive: true, Immediate: false
    Name: "@", Primitive: true, Immediate: false
    Name: "E", Primitive: true, Immediate: false
    Name: "PI", Primitive: true, Immediate: false
    Name: "abs", Primitive: true, Immediate: false
    Name: "acos", Primitive: true, Immediate: false
    Name: "and", Primitive: true, Immediate: false
    Name: "array", Primitive: true, Immediate: false
    Name: "asin", Primitive: true, Immediate: false
    Name: "atan", Primitive: true, Immediate: false
    Name: "atan2", Primitive: true, Immediate: false
    Name: "begin", Primitive: true, Immediate: true
    Name: "binary", Primitive: true, Immediate: false
    Name: "bye", Primitive: true, Immediate: false
    Name: "closeByteReader", Primitive: true, Immediate: false
    Name: "closeReader", Primitive: true, Immediate: false
    Name: "closeWriter", Primitive: true, Immediate: false
    Name: "constant", Primitive: true, Immediate: false
    Name: "cos", Primitive: true, Immediate: false
    Name: "cosh", Primitive: true, Immediate: false
    Name: "cr", Primitive: true, Immediate: false
    Name: "decimal", Primitive: true, Immediate: false
    Name: "depth", Primitive: true, Immediate: false
    Name: "do", Primitive: true, Immediate: true
    Name: "drop", Primitive: true, Immediate: false
    Name: "dup", Primitive: true, Immediate: false
    Name: "else", Primitive: true, Immediate: true
    Name: "execute", Primitive: true, Immediate: false
    Name: "exp", Primitive: true, Immediate: false
    Name: "false", Primitive: true, Immediate: false
    Name: "forget", Primitive: true, Immediate: true
    Name: "gaussian", Primitive: true, Immediate: false
    Name: "hex", Primitive: true, Immediate: false
    Name: "i", Primitive: true, Immediate: false
    Name: "if", Primitive: true, Immediate: true
    Name: "j", Primitive: true, Immediate: false
    Name: "leave", Primitive: true, Immediate: true
    Name: "length", Primitive: true, Immediate: false
    Name: "load", Primitive: true, Immediate: false
    Name: "log", Primitive: true, Immediate: false
    Name: "log10", Primitive: true, Immediate: false
    Name: "loop", Primitive: true, Immediate: true
    Name: "max", Primitive: true, Immediate: false
    Name: "min", Primitive: true, Immediate: false
    Name: "mod", Primitive: true, Immediate: false
    Name: "not", Primitive: true, Immediate: false
    Name: "openByteReader", Primitive: true, Immediate: false
    Name: "openReader", Primitive: true, Immediate: false
    Name: "openWriter", Primitive: true, Immediate: false
    Name: "or", Primitive: true, Immediate: false
    Name: "over", Primitive: true, Immediate: false
    Name: "pick", Primitive: true, Immediate: false
    Name: "pow", Primitive: true, Immediate: false
    Name: "r>", Primitive: true, Immediate: false
    Name: "r@", Primitive: true, Immediate: false
    Name: "random", Primitive: true, Immediate: false
    Name: "readByte", Primitive: true, Immediate: false
    Name: "readLine", Primitive: true, Immediate: false
    Name: "rot", Primitive: true, Immediate: false
    Name: "round", Primitive: true, Immediate: false
    Name: "setbase", Primitive: true, Immediate: false
    Name: "sin", Primitive: true, Immediate: false
    Name: "sinh", Primitive: true, Immediate: false
    Name: "sp", Primitive: true, Immediate: false
    Name: "spaces", Primitive: true, Immediate: false
    Name: "sqrt", Primitive: true, Immediate: false
    Name: "subString", Primitive: true, Immediate: false
    Name: "swap", Primitive: true, Immediate: false
    Name: "tan", Primitive: true, Immediate: false
    Name: "tanh", Primitive: true, Immediate: false
    Name: "then", Primitive: true, Immediate: true
    Name: "toDouble", Primitive: true, Immediate: false
    Name: "toLong", Primitive: true, Immediate: false
    Name: "toString", Primitive: true, Immediate: false
    Name: "true", Primitive: true, Immediate: false
    Name: "until", Primitive: true, Immediate: true
    Name: "variable", Primitive: true, Immediate: false
    Name: "words", Primitive: true, Immediate: false
    Name: "wordsd", Primitive: true, Immediate: false
    Name: "writeByte", Primitive: true, Immediate: false
    Name: "writeEol", Primitive: true, Immediate: false
    Name: "writeString", Primitive: true, Immediate: false
    Name: "xor", Primitive: true, Immediate: false



  • Andromeda schrieb:

    HERE @ SWAP schrieb:

    (... jonesforth tutorial ...)

    Ich kannte forth vorher nicht und werde vermutlich auch nie damit
    programmieren aber ich bin froh das jetzt mit im Kopf haben.

    Exotische Sprachen sind immer interessant.
    Hier ein Forth für die JVM, das ziemlich vollständig ist: https://github.com/nietoperz809/JForth

    Ok, zum Lernen kann man sowas machen. Aber in echt will man ja nicht
    aus seiner Java-Umgebung ausbrechen um dann in forth zu programmieren.

    Das jonesforth-Tutorial zeigt ja gerade, wie sich forth auf einfache
    Weise direkt in Maschinencode umsetzen lässt. Man hat also eine
    Verbesserung erreicht (während Java -> Forth == Verschlechterung).



  • Übersehe ich da was oder wo sind [ und ] ?



  • Das hier beschreibt gut die (IMHO einzige) Stärke von forth.

    Aus dem jonesforth-Tutorial:

    Why then would you want to learn FORTH? There are several very
    good reasons. First and foremost, FORTH is minimal. You really can
    write a complete FORTH in, say, 2000 lines of code. I don't just mean a
    FORTH program, I mean a complete FORTH operating system, environment and
    language
    .



  • zufallswert schrieb:

    Übersehe ich da was oder wo sind [ und ] ?

    Was machen die?

    Btw, ein Freund von mir hat das JForth auf GitHub hochgeladen und bastelt daran rum. Es kann zum Beispiel mit komplexen Zahlen rechnen. Sowas wie:

    1+3i 4-7i * .
    ergibt:
    25.0+5.0i OK

    Jetzt will der dem Forth noch Bruchrechnung beibringen (Datentyp: Rational)

    Es soll eine Art Forth-basierter Desktop-Rechner für Programmierer werden. Und eventuell folgt noch eine Android-Version.



  • nur eine ergänzende Blogadresse:
    http://primarycolorforth.blogspot.de



  • HERE @ SWAP schrieb:

    Das hier beschreibt gut die (IMHO einzige) Stärke von forth.

    Aus dem jonesforth-Tutorial:

    Why then would you want to learn FORTH? There are several very
    good reasons. First and foremost, FORTH is minimal. You really can
    write a complete FORTH in, say, 2000 lines of code. I don't just mean a
    FORTH program, I mean a complete FORTH operating system, environment and
    language
    .

    Verstehe ich ehrlich gesagt nicht. 🙄 Das kann man doch mit so ziemlich jeder Sprache erreichen? Das ist kein Alleinstellungsmerkmal von Forth. Außer das man mit minimalem Bootstrapping schnell Ergebnisse erziehlt. Aber mit dem Nachteil, das es schwer für Menschen verständlich ist. Das kann man z.B. auch mit BASIC erreichen, jedoch lässt sich BASIC einfacherer schreiben und verstehen.

    Meiner Meinung nach ist Forth ein etwas besserer Makroassembler.

    Forth, PostScript u.a. Stackbasierte Sprachen haben ihre Relevanz, aber nicht als Ersatz für Infix-Sprachen, die man als Mensch leichter schreiben und verstehen (debuggen) kann.

    Such mal ein Interview von den PostScript-Erfindern (John Warnock und Charles Geschke). Die sind stolz auf ihr PS und dessen Erfolg. Denn PS ist eine vollständige Programmiersprache, die wie Forth stackbasiert und UPN ist. Aber sie sagen selbst, das es nichts ist, was man als Mensch editieren und debuggen sollte. Es ist gut für grafische Editoren, die den PS-Code generieren und für PS-Drucker die den PS-Code maschinell verarbeiten. Weil das stackbasierte und UPN nicht human-readable ist.

    Das kann man auch auf Forth übertragen.



  • Hi,

    Forth hatte seine Berechtigung, als die Rechner noch klein und leistungsschwach waren. Da musste man der Technik schon ein wenig entgegenkommen. Aber die Zeiten sind heute vorbei. Heute will ich es in meiner Sprache (also infix) ausdrücken, und der Rechner hat sich um den Rest zu kümmern.
    Bei einem damaligen Programm hab ich auch mal einen Formelinterpreter eingebaut, der mit sehr wenig Aufwand zu erstellen war (ich war ja nicht angestellt um Formelinterpreter zu programmieren sondern um das eigentliche Programm zu erstellen) und eigentlich recht leistungsfähig und flexibel war. Ist auf ner Paradox-Datenbank gelaufen. Die einzelnen Formeln und Formelgruppen waren in Memofeldern abgelegt und wurden jeweils für den entsprechenden Datensatz ausgewertet.
    Hat damals recht gut funktioniert. Aber der Formelsalat war mit einem Riesenaufwand von Hand nach Postfix übersetzt worden und die eigentlichen Fachkollegen haben da reingeguckt wie ein Schwein ins Uhrwerk. Wenn Fehler in den Formeln waren, hätte das von denen nie einer bemerkt.
    Heute verwende ich immer noch in der DB abgelegte Berechnungsvorschriften, aber eben nicht mehr Paradox, und vorallem nicht mehr irgendwelche selbstgestrickte Postfix-Dialekte, sondern ganz stinknormales und problemlos verständliches SQL. Und selbst das schreibe ich nicht mehr immer von Hand sondern gebe nur in einem Excel-Blatt vor, welche Zellen gefüllt werden sollen, sowie mit welchen Werten aus welchen Tabellen gerechnet werdfen soll, und die Bedingungen für die Where-Bedingung stehen jeweils für die Zeilen und spalten als Wertepaare am Ende der Zeilen und Spalten. Ein kleiner Präprozesor analysiert das ganze und strickt daraus die SQL-Befehle, die dann anschließend in einer Datenbank zusammen mit den zu füllenden Zellbezügen abgespeichert werden.
    Wenn schnell was operativ geklärt werden muss, arbeite ich auch direkt an der SQL-Konsole, aber wenn was mehrfach vorkommt, dann schaue ich schon, wie ich es mir einfacher machen kann, und vor allem, wie ich meine Wünsche in einer mir verständlichen Form artikulieren kann.
    Auf den Gedanken, wieder zurück in die Steinzeit zu Forth würde ich heute nie mehr kommen. Aber einen Vorteil hat die Beschäftigung mit dem damaligen Formelinterpreter doch gehabt - man lernt mal über den eigenen Tellerrand hinauszublicken und die Dinge mal aus anderer Sicht zu sehen. Und man lernt die Nützlichkeit von Werkzeugen schätzen und sieht zu, das man das, was man für seine tägliche Arbeit braucht zur Verfügung hat und einsatzbereit hält.

    Gruß Mümmel



  • Andromeda schrieb:

    zufallswert schrieb:

    Übersehe ich da was oder wo sind [ und ] ?

    Was machen die?

    vom Compiler in den Interpreter schalten und zurück.



  • zufallswert schrieb:

    Andromeda schrieb:

    zufallswert schrieb:

    Übersehe ich da was oder wo sind [ und ] ?

    Was machen die?

    vom Compiler in den Interpreter schalten und zurück.

    Ja? Wie ich es bisher mitbekommen habe, schaltet man mit : den Compiler ein und mit ; wieder aus.

    : test cr 0 do dup 0 do cr j . i . loop loop drop ;
    

    ^^ Compiliert code für ein neues Wort "test".



  • mit [ und ] kannst du aber *während* einer Wort-Kompilierung umschalten