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:
(Man beachte, dass die Variable a und das Array a() unterschiedliche Dinge sind.)>> 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.
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).
Thema: Taschenrechner
Hybrid-Darstellung
-
17.06.2012, 19:36 #1
[C] Taschenrechner
Geändert von asdfman (17.06.2012 um 19:39 Uhr)
-
18.06.2012, 00:42 #2Commander
- 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
-
18.06.2012, 08:02 #3
[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.
-
18.06.2012, 11:26 #4Cadet 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.
-
18.06.2012, 11:56 #5
[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 ASCIIGeändert von 7H3 N4C3R (18.06.2012 um 12:24 Uhr)
-
18.06.2012, 13:31 #6
[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
-
18.06.2012, 14:09 #7
[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:
Da hast du schon eine Doppeldeutigkeit von Namen und Operatoren drin.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)
Geändert von 7H3 N4C3R (18.06.2012 um 14:22 Uhr)
-
18.06.2012, 15:56 #8
[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)
-
19.06.2012, 12:00 #9
[C] AW: Taschenrechner
getestet mit tarball auf Basis von bdb4ea1:
Edit:Code:$ bin/int >> print a% + 5 Segmentation fault (core dumped)
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:
Der Fehlercheck fehlte.Code:opr = getoper(exp, &oprpos); if (opr != ERROR_NONE) { *status = opr; return NULL; }Geändert von 7H3 N4C3R (19.06.2012 um 12:40 Uhr)
-
19.06.2012, 12:59 #10
[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.exeGeändert von asdfman (19.06.2012 um 20:25 Uhr)
-
19.06.2012, 22:52 #11Commander
- 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
-
20.06.2012, 14:28 #12Cadet 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?
-
20.06.2012, 20:42 #13
[C] AW: Taschenrechner
Ich würde ungern einfach Binaries herunterladen und ausführen. Da ist mir Quellcode lieber :/
Habe ich (offensichtlich) von BASIC geklaut und die kommen doch auch damit klar. Außerdem istNa 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.
es in jeder Programmiersprache doof, Leerzeichen innerhalb von Variablenbezeichnern zu haben.
Wüsste nicht, welche Sprache das erlaubt.
Dann müsste er einen Type mismatch error schmeißen. Tut er aber nicht. Sehe ich mir an.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...
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.
-
20.06.2012, 21:32 #14
[C] AW: Taschenrechner
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.
Nur weil du gefragt hast.Code:set {variable name with spaces} 12235 puts ${variable name with spaces}
-
20.06.2012, 22:37 #15Commander
- 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
-
20.06.2012, 23:03 #16
[C] AW: Taschenrechner
Sehe da überhaupt keine Zweideutigkeit. Egal wie man da Leerzeichen setzt.
a+++b ist da doch etwas völlig anderes.
-
21.06.2012, 00:05 #17Commander
- 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
-
27.06.2012, 10:17 #18
[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)
-
27.06.2012, 13:17 #19
[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.

Zitieren
