Hybrid-Darstellung

  1. #1
    Lt. Commander
    Dabei seit
    Mär 2008
    Beiträge
    1.231

    [C] Taschenrechner

    Mahlzeit.

    Ich habe vor, in C einen Skriptinterpreter zu schreiben und bis jetzt bin ich so weit, dass er
    zumindest mal als Taschenrechner zu gebrauchen ist. Ich würde mich freuen, wenn ihr mal
    drüber guckt und mir Bugs meldet (die vermutlich noch zuhauf vorhanden sind).

    Aktueller Sourcecode
    Vorkompiliertes Binary(Windows)

    Die Bedienung ist relativ einfach.

    dim <ID> <N> deklariert ein Array mit dem Identifier ID und N Elementen.
    set <ID> <EXP> weist der Variablen mit dem Identifier ID den Wert des Ausdrucks EXP zu.
    print <EXP> gibt den Wert des Ausdrucks EXP aus.
    Eine leere Zeile beendet den Interpreter/Taschenrechner.

    Falls das irgendwie unklar erklärt ist, hier mal ein Beispieldurchlauf:
    >> dim a 2
    OK.
    >> set a 1
    OK.
    >> set a(a-1) a
    OK.
    >> set a(1) (a(0)+9)*(a+2)
    OK.
    >> print a(1)
    30
    OK.
    (Man beachte, dass die Variable a und das Array a() unterschiedliche Dinge sind.)

    Ich würde mich über jede Form der Anregung, was den Evaluator für mathematische Aus-
    drücke angeht, freuen. Wenn euch die Syntax der Eingaben nicht gefällt, kann ich das ver-
    stehen, aber das bleibt eh nicht so und da kümmere ich mich selbst noch drum.

    €: Ach, der Evaluator kennt im Moment die Operatoren +, -, *, /, sowie
    &, |, ^ (bitweises AND, OR, XOR) und % (Modulo).
    Geändert von asdfman (17.06.2012 um 19:39 Uhr)
    Heute schon dein SICP gelesen und deine Vorlesung besucht?


  2. #2
    Commander
    Dabei seit
    Nov 2007
    Ort
    Ulm
    Beiträge
    2.473

    [C] AW: Taschenrechner

    Die Doppeldeutigkeit von Variable und Array gefällt mir nicht ganz.
    Was an Operatoren noch fehlt: Mehrdimensionale Arrays und dann Matrizenoperationen (wenigstens + * transpose()), sin cos tan sqrt pow also alles was der Taschenrechner so bietet ^^.
    Ein Schmankerl wäre natürlich auch die Unterstützung von komplexen Zahlen sowie inv() auf Matrizen (also intervieren), oder aber die Matlab-Operatoren / und \.

    Vielleicht auch ganz nützlich: round und trunc, damit man die Arrays auch immer richtig ansprechen kann.
    Wenns ein Scriptinterpreter wird: size(), length()...

    EDIT: Seh grad, sind ja nur Ganzzahlen (wie langweilig ).
    Wie wärs mit Typdefinitionen oder nem automatischen Castsystem für verschiedenste Datentypen.
    Wie kann ich den Interpreter beenden?
    Sapphire HD 5770|Zalman CNPS 9700 LED@Intel Q6600 G0@1,1 Volt|Asus P5Q-E
    BE PART OF THE Computerbase-HWLuxx FOLDING@HOME TEAM

  3. #3
    Lt. Commander
    Ersteller dieses Themas

    Dabei seit
    Mär 2008
    Beiträge
    1.231

    [C] AW: Taschenrechner

    Es geht mir erstmal um den Evaluator für mathematische Ausdrücke. Trigonometrische Funktionen z.B.
    sind ja keine mathematischen Operationen im eigentlichen Sinn. Die werden sicher in einem anderen
    Modul des Interpreters folgen.

    Mehrdimensionale Arrays klingen sehr sinnvoll. Müsste mir mal Gedanken darüber machen, wie ich die
    implementiere, also schiebe ich das erst einmal etwas nach hinten.

    Dass der Evaluator nur mit Integern umgehen kann, lag an meiner Faulheit, weil ich das für am einfachsten
    zu implementieren hielt und dann Dezimalzahlen aus dem Blick verloren habe. Das kommt dann auf jeden
    Fall als Nächstes, weil ich es am wichtigsten von deinen Anregungen finde. Danke für die Erinnerung

    Meinst du mit automatischem Castsystem, dass 1.5+0.5 zu einer Integer-2 gecastet werden? Bzw eine
    Integer-3 durch Integer-2 zu Float-1.5? Klingt als wäre das geradezu notwendig. Kommt rein :3

    Den Interpreter beendet man mit einer leeren Zeile. Einfach an der Eingabeaufforderung Enter drücken.
    Heute schon dein SICP gelesen und deine Vorlesung besucht?


  4. #4
    Cadet 4th Year
    Dabei seit
    Jun 2010
    Beiträge
    120

    [C] AW: Taschenrechner

    Wie wäre es mit eckigen Klammern für Array-Indices?
    Sonst ist:
    set a(a-1) -1
    kaum von
    set a (a-1)-1
    zu unterscheiden.

  5. #5
    Lt. Commander
    Dabei seit
    Feb 2002
    Beiträge
    1.800

    [C] AW: Taschenrechner

    Makefile:
    kein all-Target.
    clean (und all) ist kein phony target
    Compile-Flags:
    -fno-omit-frame-pointer -> sonst macht debuggen auf x64 keinen Spaß
    -ansi -pedantic -> gehört zum guten Ton
    -Wextra -> kann man getrost auch per default anmachen

    var.c:
    // -> C++-Kommentare, kompiliert nicht mit pedantic

    errno.h -> Dateiname ist ne schlechte Idee, weil wegen C-Standard-Header <errno.h>


    Zuviel Code um das mal ernsthaft durchzuschauen (TLDR ) Ein paar Unsauberheiten mit signed/unsigned spuckt schon der Compiler aus. Dazu Vermischung von z.B. int und size_t in der main. Valgrind war soweit ruhig, ein paar kleine Leaks die ich mir jetzt nicht im Detail angeschaut hab.

    Parser schreibt man niemals selber, immer generieren lassen. Sonst stehst du direkt mit einem Bein in der Hölle.

    Der Meldung "Array redimensioned." sieht man nicht an, dass sie ein Fehler ist. Würde ich als "Erfolg, Array dimensionen geändert" verstehen.

    Unittest-Suite und dazugehöriges check-Target wäre natürlich auch fein.


    Weiter im Text (hab doch noch weiter gelesen *g*):
    * Einrückung unsauber (Mischung aus non-tabs und tabs)
    * strcpy -> von denen, die ich gesehen hab, lässt sich alles problemlos auf strncpy umbauen
    * Viel copy und paste beim Speicherhandling. Kann nach meinem ersten Eindruck viel besser zusammengefasst werden, indem man ein paar Management-Funktionen dazu baut.
    * var.c:366 (dimint) -> mknewvar -> unchecked malloc (auch wenn addtovarlist nix böses damit macht) und falscher Rückgabewert (ERROR_NONE statt ERROR_MALLC)
    * help.c:11 (strtoup) -> implizite Annahme von ASCII
    Geändert von 7H3 N4C3R (18.06.2012 um 12:24 Uhr)

  6. #6
    Lt. Commander
    Ersteller dieses Themas

    Dabei seit
    Mär 2008
    Beiträge
    1.231

    [C] AW: Taschenrechner

    >Makefile: Extrawünsche hinzugefügt
    >C++-Kommentare zu C-Kommentaren gemacht.
    >errno.h in errlist.h umbenannt

    >Valgrind ist bei mir zufrieden.
    >Parser schreibt man niemals selber -> Ich will das aber lernen ;<
    >Allen Fehlermeldungen explizit "ERROR:" vorangestellt.


    >Einrückung unsauber: Kam vom hin- und herpasten zwischen VS und vim. Sollte jetzt passen.
    >strcpy: zu strncpy() auch an Stellen, an denen strcpy() nichts falsch machen dürfte geändert.
    >Viel copy und paste beim Speicherhandling: Muss ich mir mit mehr Zeit genauer ansehen.
    >var.c:366 (dimint): Korrigiert.
    >implizite Annahme von ASCII: Tja, Pech, liebe Chinesen ;<

    Änderungen hier: https://github.com/SirDzstic/int
    Heute schon dein SICP gelesen und deine Vorlesung besucht?


  7. #7
    Lt. Commander
    Dabei seit
    Feb 2002
    Beiträge
    1.800

    [C] AW: Taschenrechner

    >Parser schreibt man niemals selber -> Ich will das aber lernen ;<
    Hehe Ist ja auch gut, das mal gemacht zu haben. Die Lektion sollte aber sein: nicht selber schreiben. Man baut viel zu viele Bugs ein.

    Offensichtlicher weiterer Bug:
    Crash: div-by-zero mit Modulo möglich.

    Integer-Namen dürfen mit % enden - funktioniert nicht:
    Code:
    >> dim a% 1
     OK.
    >> set a%(0) 5
     Syntax error.
    >> set a% 5
     OK.
    >> print a%   
     0
     Syntax error.
    >> print a%(0)
    Floating point exception (core dumped)
    Da hast du schon eine Doppeldeutigkeit von Namen und Operatoren drin.
    Geändert von 7H3 N4C3R (18.06.2012 um 14:22 Uhr)

  8. #8
    Lt. Commander
    Ersteller dieses Themas

    Dabei seit
    Mär 2008
    Beiträge
    1.231

    [C] AW: Taschenrechner

    Haha, das habe ich tatsächlich nie ausprobiert. Ich sollte das ganze eh mal in Tokens zerlegen und dabei
    zwischen dem Modulooperator und den Endungen für Variablenbezeichner unterscheiden, dann erledigen
    sich solche Probleme von allein.

    €: Trotzdem peinlich.

    Ergänzung vom 18.06.2012 20:07 Uhr:
    Okay, % als Suffix für Integer geht jetzt und ich mache mich als nächstes an Support für Dezimalzahlen
    und deren implizite Typumwandlung. Testen weiter erwünscht. Ich kann auch gern ein aktuelles Windows
    Binary bauen, falls es jemanden interessiert.

    €: Noch zu dem Herrn, der [] für Indizes vorgeschlagen hat: Kann ich machen, aber das Problem, das du
    angesprochen hast, soll sich früher oder später eh erledigen, weil ich doch gerne = als Zuweisungsoper-
    ator einbauen würde am ende, so dass "SET" eh wegfällt.
    Geändert von asdfman (18.06.2012 um 20:10 Uhr)
    Heute schon dein SICP gelesen und deine Vorlesung besucht?


  9. #9
    Lt. Commander
    Dabei seit
    Feb 2002
    Beiträge
    1.800

    [C] AW: Taschenrechner

    getestet mit tarball auf Basis von bdb4ea1:

    Code:
    $ bin/int 
    >> print a% + 5
    Segmentation fault (core dumped)
    Edit:
    Zweiten Fehler entfernt, kam wohl durch meine Basteleien

    Da wird offensichtlich -1 als int an strncpy übergeben. -> Konversion nach size_t: 18446744073709551615

    Solltest mal die int vs. size_t Geschichte sauber machen und immer und überall auf overflows und underflows checken.


    N bisschen gedebuggt:

    Hier fehlt ein Check:
    src/eval.c in buildtree:
    Code:
            opr = getoper(exp, &oprpos);
            if (opr != ERROR_NONE) {
              *status = opr;
              return NULL;
            }
    Der Fehlercheck fehlte.
    Geändert von 7H3 N4C3R (19.06.2012 um 12:40 Uhr)

  10. #10
    Lt. Commander
    Ersteller dieses Themas

    Dabei seit
    Mär 2008
    Beiträge
    1.231

    [C] AW: Taschenrechner

    Ok, habe den Check etwas modifiziert eingebaut. geoper() schmeißt nur -1 als Fehler, ansonsten gibt es den
    Eintrag in der Operatortabelle zurück.

    Ergänzung vom 19.06.2012 20:20 Uhr:
    So. Jetzt habe ich Support für Dezimalzahlen eingebaut.
    Endet eine Variable auf %, wird sie als Integer betrachtet, auf $ als String und ohne Endung als Dezimalzahl.

    Vermutlich haben sich wieder 934943 bugs eingeschlichen.
    Und ganz vielleicht guckt es sich sogar nochmal jemand an

    €: Habe nochmal ein Windowsbinary gebaut:
    https://dl.dropbox.com/u/13226560/medien/int-0.2.0.exe
    Geändert von asdfman (19.06.2012 um 20:25 Uhr)
    Heute schon dein SICP gelesen und deine Vorlesung besucht?


  11. #11
    Commander
    Dabei seit
    Nov 2007
    Ort
    Ulm
    Beiträge
    2.473

    [C] AW: Taschenrechner

    Die Windowsbinaries sind das wichtigste, weil kaum jemand macht sich die Mühe, das mal schnell zu kompilieren...
    Na ja, eine Unterscheidung von Variablen am Namen nach Typ halt ich für ... unelegant.

    BTW: Ich finde es schlecht, wenn Operatoren als Name(-ssuffix) verwendet werden dürfen, weil dann kommts auf Leerzeichen an, find ich unschön.

    Was machst du eig. wenn jemand einen String (der ruhig auch Groß-kleinschreibung unterstützten dürfte) mit Zahlen verrechnet, bei mir hat der einfach nur die Zahl genommen...
    Sapphire HD 5770|Zalman CNPS 9700 LED@Intel Q6600 G0@1,1 Volt|Asus P5Q-E
    BE PART OF THE Computerbase-HWLuxx FOLDING@HOME TEAM

  12. #12
    Cadet 4th Year
    Dabei seit
    Jun 2010
    Beiträge
    120

    [C] AW: Taschenrechner

    Hier ist nochmal der "Herr (woraus schließt du das?), der [] für Indizes vorgeschlagen hat".
    Spätestens, wenn du Funktionen zulassen willst, musst du dir Gedanken darüber machen entweder Arrays und Funktionen mit gleichem Namen nicht zuzulassen oder [] zu verwenden. Wenn die Funktion sin() existiert, dann
    Code:
    sin = 0      // sin als Variable geht
    sin(0) = 1   // sin als Array geht, wenn Funktionsaufrufe auf linker Seite der Zuweisung nicht erlaubt sind
    sin = sin(0) // die rechte Seite wäre mehrdeutig, Arrayzugriff oder Funktionsaufruf?

  13. #13
    Lt. Commander
    Ersteller dieses Themas

    Dabei seit
    Mär 2008
    Beiträge
    1.231

    [C] AW: Taschenrechner

    Zitat Zitat von Hancock Beitrag anzeigen
    Die Windowsbinaries sind das wichtigste, weil kaum jemand macht sich die Mühe, das mal schnell zu kompilieren...
    Ich würde ungern einfach Binaries herunterladen und ausführen. Da ist mir Quellcode lieber :/

    Na ja, eine Unterscheidung von Variablen am Namen nach Typ halt ich für ... unelegant.

    BTW: Ich finde es schlecht, wenn Operatoren als Name(-ssuffix) verwendet werden dürfen, weil dann kommts auf Leerzeichen an, find ich unschön.
    Habe ich (offensichtlich) von BASIC geklaut und die kommen doch auch damit klar. Außerdem ist
    es in jeder Programmiersprache doof, Leerzeichen innerhalb von Variablenbezeichnern zu haben.
    Wüsste nicht, welche Sprache das erlaubt.

    Was machst du eig. wenn jemand einen String (der ruhig auch Groß-kleinschreibung unterstützten dürfte) mit Zahlen verrechnet, bei mir hat der einfach nur die Zahl genommen...
    Dann müsste er einen Type mismatch error schmeißen. Tut er aber nicht. Sehe ich mir an.

    Zitat Zitat von r0b0t Beitrag anzeigen
    Hier ist nochmal der "Herr (woraus schließt du das?), der [] für Indizes vorgeschlagen hat".
    Spätestens, wenn du Funktionen zulassen willst, musst du dir Gedanken darüber machen entweder Arrays und Funktionen mit gleichem Namen nicht zuzulassen oder [] zu verwenden.
    Ich benutze halt das generische Maskulinum. Mit dem Rest hast du Recht. [] ist natürlich
    einfacher zu implementieren, also mache ich das mal demnächst.
    Heute schon dein SICP gelesen und deine Vorlesung besucht?


  14. #14
    Lieutenant
    Dabei seit
    Jun 2010
    Ort
    Erlangen
    Beiträge
    567

    [C] AW: Taschenrechner

    Zitat Zitat von asdfman Beitrag anzeigen
    Habe ich (offensichtlich) von BASIC geklaut und die kommen doch auch damit klar. Außerdem ist
    es in jeder Programmiersprache doof, Leerzeichen innerhalb von Variablenbezeichnern zu haben.
    Wüsste nicht, welche Sprache das erlaubt.
    Tut jetzt nichts zur Sache, aber Tcl erlaubt das zum Beispiel. Man muß den Bezeichner dann natürlich in Quotes / Braces setzen, damit der Interpreter das Leerzeichen nicht als Delimiter interpretiert.

    Code:
    set {variable name with spaces} 12235
    puts ${variable name with spaces}
    Nur weil du gefragt hast.

  15. #15
    Commander
    Dabei seit
    Nov 2007
    Ort
    Ulm
    Beiträge
    2.473

    [C] AW: Taschenrechner

    @antred PHP auch...

    Ich meinte eher sowas
    set a b%c
    vs
    set a b%%c
    Ähnlich der Probelmatik mit i++ +a vs. i+ ++a in C-ähnlichen Sprachen.
    Sapphire HD 5770|Zalman CNPS 9700 LED@Intel Q6600 G0@1,1 Volt|Asus P5Q-E
    BE PART OF THE Computerbase-HWLuxx FOLDING@HOME TEAM

  16. #16
    Lt. Commander
    Ersteller dieses Themas

    Dabei seit
    Mär 2008
    Beiträge
    1.231

    [C] AW: Taschenrechner

    Sehe da überhaupt keine Zweideutigkeit. Egal wie man da Leerzeichen setzt.
    a+++b ist da doch etwas völlig anderes.
    Heute schon dein SICP gelesen und deine Vorlesung besucht?


  17. #17
    Commander
    Dabei seit
    Nov 2007
    Ort
    Ulm
    Beiträge
    2.473

    [C] AW: Taschenrechner

    Stimmt beim genauen Überlegen haste Recht, aber schön find ich's trotzdem net
    Sapphire HD 5770|Zalman CNPS 9700 LED@Intel Q6600 G0@1,1 Volt|Asus P5Q-E
    BE PART OF THE Computerbase-HWLuxx FOLDING@HOME TEAM

  18. #18
    Lt. Commander
    Dabei seit
    Feb 2002
    Beiträge
    1.800

    [C] AW: Taschenrechner

    Die Mehrdeutigkeit ist absolut vorhanden.

    1.) a%%b
    2.) a%b

    Was ist gemeint?
    1.) a% modulo b? Oder vielleicht ist ein Syntax-Fehler gemeint?
    2.) a% gefolgt von Variable? (Syntax-Fehler) Oder a modulo b?

    Wenn du jeweils die korrekten Fälle als die gültigen annimmst, wie sieht dann die Parsing-Regel aus? Versuchen wir die mal zu formulieren:

    Wenn Variable gefolgt von %, dann modulo. -> Funktioniert nicht wegen Fall 1
    Wenn Variable gefolgt von %, dann Integer. -> Funktioniert nicht wegen Fall 2
    Wenn Variable gefolgt von %, dann: variable% bekannt? Dann variable%, sonst modulo -> Funktioniert nicht, weil variable% und variable definiert sein können
    Wenn Variable gefolgt von %, dann: rechts von % steht Variable? Dann modulo, sonst: Rechts von % steht %: dann: rechts von % steht variable: dann variable% modulo variable. Sonst: Fehler oder sowas: Sonst Fehler

    Ich vermute, du willst den letzten Fall. Anhand der Komplexität der Regel dürfte schon klar sein, dass das eher bitter ist? Außerdem ist die Regel rekursiv: a%%b%%c%%d%%e. Ich habe keine wirkliche Ahnung davon, aber das könnte schon eine kontext-sensitive Grammatik sein und braucht einen LALR-Parser? Wer das studiert hat und meint, das ist Bullshit, schlägt mich bitte mit nem Knüppel auf den Kopf

    Dann gäbe es auch noch das hier:
    a%-b

    Was ist gemeint? a modulo unäres minus b? a% minus b? Ohne Operator-Prioritäten ist das nicht lösbar. (Nebenbei, modulo mit einer negativen Zahl ist undefined behaviour)

    Mein Vorschlag wäre, den Parser komplett neu zu machen, z.B. auf Basis einer Stack Machine / Push Down Automat:
    http://en.wikipedia.org/wiki/Pushdown_automaton

    Außerdem kommt noch das Typ-Problem dazu. Du hast jetzt schon 6 Typen (int, string, float, intarr, strarr, decarr). Jetzt würde ich mir vorstellen, dass man Arrays der gleichen Dimension miteinander verrechnen können soll (-> Vektorrechnung). Dürfte äußerst kompliziert werden im bestehenden Code. Wenn jetzt noch komplexe Zahlen dazu kommen sollen, wird es echt mies vom Programmieraufwand.

    Nebenbei: warum float und nicht double? Double ist der Typ, der ideal zur drunter liegenden Plattform passt. Floats sind meist nur unnötig unpräzise und vor allem lahm.
    Geändert von 7H3 N4C3R (27.06.2012 um 10:23 Uhr)

  19. #19
    Lt. Commander
    Ersteller dieses Themas

    Dabei seit
    Mär 2008
    Beiträge
    1.231

    [C] AW: Taschenrechner

    Die Operatoren werden von rechts nach links gesucht. Das erste, auf dass er trifft, was wie ein Operator
    aussieht, wird wie einer behandelt:
    a%%b%%c%%d%%e -> a% mod b% mod c% mod d% mod e.
    a%-b -> a% - b

    Wobei letzterer Fall wenn man sich ganz stark zwingen will eine Zweideutigkeit sein könnte. Unäres - wird
    übrigens noch nicht richtig erkannt und behandelt. Wenn du mich jetzt mit einem klaren Beispiel überzeugen
    kannst, dass es gar nicht möglich ist, zu entscheiden, wann ein - unär oder binär ist (oder es sonst einen
    Ausdruck gibt, den der aktuelle Evaluator nicht entscheiden kann), könnte ich erwägen, den Evaluator neu
    zu schreiben. Sonst versuche ich erst einmal den unären - Operator korrekt zu erkennen.

    Außerdem gibt es Operatorprioritäten. Siehe operlist in oper.c. Der Dritte Wert einer Spalte gibt die Priorität
    an. Kleinere Zahlen bedeuten niedrigere Priorität.

    -- Rhabarberrhabarber. Keine Lust meinen schön geschriebenen Text von oben zu löschen, aber folgendes:

    Die Suche nach Operatoren von rechts nach links gibt einen Bug, wenn der letzte Operand vom Typ Integer
    ist. Bei print a%-b% hält er das letzte % für den Modulooperator und schmeißt einen Syntaxfehler.
    Ich gehe davon aus, dass dieses Problem mit dem Aktuellen Aufbau des Evaluators nicht zu beheben ist und
    ich vermutlich einen Tokenizer schreiben muss und dann einen neuen Evaluator. Nicht sicher, ob ich mir diese
    Arbeit machen will.
    Heute schon dein SICP gelesen und deine Vorlesung besucht?


Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •