software:diy:andere:bob
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende Überarbeitung | ||
software:diy:andere:bob [26/12/2013 11:12] – Oder auch das nicht… Hmm… pbk | software:diy:andere:bob [26/12/2013 11:12] – SUP ist komplett raus genommen. Ohne funktioniert es. Kann ein Fehler im Parser sein. pbk | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
- | {{ : | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | ====== BOB+ ====== | ||
- | BOB+ ist eine von Ralf-Erik Ebert weiterentwickelte Version der Programmiersprache BOB die sich für den Portfolio hervorragend eignet.\\ | ||
- | Es ist eine Hybridsprache, | ||
- | Es ist weder ein Compiler, noch ein reiner Interpreter. Die Quelldateien werden in einen Byte-Code | ||
- | übersetzt, der anschließend interpretiert wird.\\ | ||
- | Eines der wichtigsten Kriterien bei der Entwicklung von BOB+ war sparsamster Umgang mit Ressourcen. BOB+ kommt mit knapp 50 KB Platz auf einer Speicherkarte und weniger als 128 KB Arbeitsspeicher aus. Somit ist es möglich, auf einem Atari-Portfolio in Normalausstattung BOB+-Programme nicht nur auszuführen, | ||
- | BOB+ hält noch zwei Finessen parat; es ist möglich BOB+ Quellcode unter DOS in Batch-Dateien auszuführen (siehe GRAPH.BAT) und BOB+ unterstützt die Einbindung von DOS-DLLs (siehe AESTEST.BP).\\ | ||
- | Ab der Version 1.1d gibt es außerdem die Möglichkeit, | ||
- | Version 1.1e ist ein " | ||
- | **Achtung: | ||
- | \\ | ||
- | Bezugsquelle: | ||
- | \\ | ||
- | \\ | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | ===== Lieferumfang ===== | ||
- | |||
- | Im Downloadbereich von [[http:// | ||
- | Diese Version ist [[http:// | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | ==== Programme ==== | ||
- | ^Name ^Beschreibung ^Größe ^Datum^ | ||
- | |BP.EXE |Source-Code Interpreter/ | ||
- | |BPR.EXE | ||
- | |BPI.EXE | ||
- | |BPRI.EXE | ||
- | |BPC.EXE | ||
- | |||
- | BP.EXE und BPR.EXE sind die " | ||
- | BPC.EXE ist ein reiner Bytecode-Compiler, | ||
- | \\ | ||
- | |||
- | ==== Beispiele ==== | ||
- | ^Name ^Beschreibung ^Größe ^Datum^ | ||
- | |STRSPLIT.BP | ||
- | |GRAPH.BP | ||
- | |MIN.BP | ||
- | |SQRT.BP | ||
- | |HELLO1.BP | ||
- | |RANDOM.BP | ||
- | |OP.BP | ||
- | |MINILIB.BP | ||
- | |MINI.BP | ||
- | |TYPE.BP | ||
- | |GRAPH.BAT | ||
- | |VARARGS.BP | ||
- | |SORTLIST.BP | ||
- | |||
- | |||
- | Anders als bei BOB ist die Standard-Dateierweiterung für Quellcodes *.BP (nicht *.BOB), für Byte-Code-Module *.BPM. Der Grund dafür ist die Tatsache, dass BOB+-Programme Code enthalten können, den BOB nicht versteht (BOB Programme hingegen werden von BOB+ verstanden).\\ | ||
- | |||
- | |||
- | |||
- | |||
- | ==== DOS-DLL für AES-Funktionen ==== | ||
- | Speziell für den Portfolio hat Erik Ebert eine DOS-DLL geschrieben, | ||
- | |||
- | ^Name ^Beschreibung ^Größe ^Datum^ | ||
- | |AES.EXE | ||
- | |AES.8 | ||
- | |AES.BP | ||
- | |AES.CHM |Referenzdokumentation (MS-HTML-Help) | 83939 Bytes| 28.01.08| | ||
- | |AES.BPM | ||
- | |AESTEST.BP | ||
- | |MENU.TXT | ||
- | |AESDEMO.BP | AES-DLL-Demo (Quelltext)| 9499 Bytes| 27.01.08| | ||
- | |AESDEMP.BPM | AES-DLL-Demo (vorkompiliert)| 10736 Bytes| 27.01.08| | ||
- | |cpp/ | ||
- | |cpp/ | ||
- | |cpp/ | ||
- | |cpp/ | ||
- | |cpp/ | ||
- | |cpp/ | ||
- | |cpp/ | ||
- | |cpp/ | ||
- | |cpp/ | ||
- | |||
- | Geben sie '' | ||
- | Das Unterverzeichnis '' | ||
- | |||
- | |||
- | |||
- | |||
- | ===== BOB+ auf dem Portfolio ===== | ||
- | |||
- | Das Konzept von BOB+ vereint die Vorteile eines Semi-Compilers mit denen einer Script-Sprache. Der modulare Charakter erlaubt es, den Einsatz perfekt an Portfolios Möglichkeiten und Grenzen anzupassen. Die Verwendung von Quellcode- und Byte-Code Dateien erleichtert das Programmieren und bietet große Entscheidungsfreiheit in der Handhabung der Ressourcen.\\ | ||
- | |||
- | Byte-Code Module sind platzsparender als ihre unkompilierten Quellen. Die Ersparnis ist unterschiedlich und hängt vom Inhalt des Quellcodes ab. Das Beispiel-Programm SORTLIST.BP hat unkompiliert eine Größe von 4130 Bytes, das kompilierte Byte-Code-Modul nur 1319 Bytes, eine Ersparnis von mehr als 68%. Allerdings lassen sich Byte-Code-Module nicht mehr dekompilieren oder editieren. Sie können aber bei der Kompilierung anderer Programme eingebunden, | ||
- | |||
- | Als wäre dies nicht genug, können - ähnlich wie unter Windows - auch Dynamic-Link-Libraries (DOS-DLLs) eingebunden werden.\\ | ||
- | |||
- | Die Möglichkeit BOB+ Scripts in Batch-Dateien zu speichern (siehe GRAPH.BAT) ist wie eine offene Tür zu DOS. | ||
- | All dies macht BOB+ wie für den Portfolio geschaffen.\\ | ||
- | |||
- | |||
- | ==== System-Voraussetzungen ==== | ||
- | |||
- | BP.EXE selbst benötigt insgesamt 78304 Bytes Arbeitsspeicher, | ||
- | Damit sind die Bedingungen für eine minimale Standard-Ausrüstung erfüllt.\\ | ||
- | Bei einem größeren Laufwerk C: oder mit etwaigen installierten Treibern (der FileManager FM.COM will auch seine 10480 Bytes) könnte es aber eng werden, es sei denn, man hat eine Speicherweiterung, | ||
- | |||
- | |||
- | ==== Speichermedien ==== | ||
- | |||
- | Eine minimale Programmierumgebung (nur mit BP.EXE) benötigt etwa 50 KBytes, es ist also mindestens eine 64KB-Speicherkarte notwendig, 128KB zweckmäßig. Mit ein paar DOS-Utilities und zusätzlichen Byte-Code-Dateien ist diese dann auch schon bald voll. Hat man kein größeres Speichermedium, | ||
- | |||
- | Für fertige Programmpakete (anwenderspeziefische Software), bestehend aus nur BPR.EXE (ca. 40 KB) und Byte-Code-Dateien, | ||
- | |||
- | |||
- | ==== Performance ==== | ||
- | Das Laden von BP.EXE oder BPR.EXE dauert auf einem Standard-Portfolio mit 4,9MHz weniger als 3 Sekunden.\\ | ||
- | |||
- | |||
- | |||
- | |||
- | ==== Zukunft ==== | ||
- | KiezSoft arbeitet an der Erweiterung der Sprache, verbunden mit einer neuen Architektur und einer eine vollständigen Reimplementierung. Die Ausrichtung auf extrem geringen Ressourcenbedarf steht hierbei weniger in Vordergrund, | ||
- | Die neue Version wird voraussichtlich BOB+ 2 heißen.\\ | ||
- | Für die Versionen 1.x wird es Updates und ggf. Erweiterungen geben, solange dafür ein Anwenderinteresse besteht. Dabei bleibt der Fokus auf Minimalsysteme erhalten. | ||
- | |||
- | |||
- | |||
- | ===== BOB+ Handbuch | ||
- | © 2011 Ralf-Erik Ebert, Berlin\\ | ||
- | |||
- | Die in diesem Text verwendeten Bezeichnungen von Hard- und Software-Produkten sowie Firmennamen sind in der | ||
- | Regel – auch ohne besondere Kennzeichnung – eingetragene Warenzeichen und sollten als solche behandelt werden. | ||
- | |||
- | Der hier veröffentlichte Text wurde mit großer Sorgfalt erarbeitet. Dennoch können Fehler und Irrtümer nicht | ||
- | ausgeschlossen werden. Für entsprechende Hinweise und Verbesserungsvorschläge ist der Autor jederzeit dankbar.\\ | ||
- | Die im Text verwendeten Beispiele dienen ausschließlich der Illustration und dem leichteren Verständnis des Textes. | ||
- | |||
- | **Der Autor übernimmt keinerlei Haftung für durch die Verwendung der Software BOB+, dieser | ||
- | Dokumentation und der darin enthaltenen Code-Beispiele entstehende Schäden.**\\ | ||
- | Änderungen, | ||
- | Dokumentation dienen , behält sich der Autor vor.\\ | ||
- | |||
- | BOB+ ist FREEWARE und wird als Open Source zur Verfügung gestellt.\\ | ||
- | Die Software darf frei kopiert und weitergegeben sowie – direkt oder in modifizierter Form – in beliebigen kommerziellen oder nicht-kommerziellen Umgebungen eingesetzt werden, sofern die Urheberschaft an geeigneter Stelle erwähnt wird. | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | ===== 1 Vorwort ===== | ||
- | Die Version 1.1 von BOB+ war eigentlich nicht geplant. Sie ist sozusagen als Zwischenschritt auf dem Weg zur Version 2, die im ersten Halbjahr 2008 erscheinen und neben einer komplett überarbeiteten Architektur und Implementierung zahlreiche Erweiterungen der Sprache selbst mitbringen wird, entstanden.\\ | ||
- | BOB+ 1.1 basiert wesentlich auf dem Code der Version 1.0 und behält den Fokus auf Systeme mit extrem knappen Ressourcen bei. Sie ist außerdem Quell- und Bytecode-kompatibel zur Vorgängerversion. Intern wurden einige Änderungen bzw. Erweiterungen vorgenommen, | ||
- | der Betreiber des PofoWiki zum erhöhten Speicherbedarf einer Vorab-Variante der Version 2 sowie die inzwischen vorhandene Möglichkeit, | ||
- | |||
- | Aus Sicht des Benutzers bringt die Version 1.1 folgende Neuerungen mit:\\ | ||
- | * Die Möglichkeit, | ||
- | * Durch eine veränderte interne Darstellung von Zeichenketten und Adressen können BOB+- Strings als Puffer für die Übergabe von Daten von/nach externen Funktionen verwendet werden. Außerdem verbessert sich das Laufzeitverhalten der Zeichenketten-Funktionen. | ||
- | * Für die Verwendung auf Systemen mit knappem Speicherplatz existiert eine Variante von BOB+ ohne Unterstützung von Gleitpunkt-Arithmetik. Außerdem gibt es einen separaten BOB+-Compiler. | ||
- | * Die Runtime-Version von BOB+ 1.1 besitzt keine compile-Funktion mehr. Dadurch kann sie auf den Code des Compilers verzichten und beansprucht damit weniger Platz als die der Version 1.0. | ||
- | * Im Zusammenhang mit den dynamischen Bibliotheken und den Änderungen an der Darstellung von Zeichenketten gibt es einige neue bzw. erweiterte vordefinierte Funktionen (siehe Abschnitt 12). | ||
- | Das hier vorliegende Handbuch wurde aktualisiert und um ein zusätzliches Kapitel ergänzt, das sich mit der Implementierung und Verwendung von dynamischen Bibliotheken für BOB+ beschäftigt. | ||
- | Auf Unterschiede zwischen den beiden BOB+-Versionen und zur BOB-Ur-Version von David M. | ||
- | Betz [2] wird im Text ausdrücklich hingewiesen.\\ | ||
- | |||
- | Version 1.1a ist eine kleine Erweiterung der Version 1.1. Hier sind drei Anweisungen hinzugekommen, | ||
- | |||
- | Die Version 1.1b übernimmt den Umgang mit Escape-Codes von BOB+2, d.h., sie gestattet die Verwendung von Zeichencodes in Escape-Sequenzen – siehe hierzu [[software: | ||
- | |||
- | Version 1.1c fügt Funktionen zum direkten Lesen bzw. Schreiben des Arbeitsspeichers bzw. zum Kopieren von Speicherbereichen hinzu (vgl. [[software: | ||
- | Durch einige Code-Optimierungen wurden außerdem die Größen der ausführbaren Dateien und der benötigte Speicherplatz weiter reduziert. | ||
- | |||
- | Mit Version 1.1d besteht die Möglichkeit, | ||
- | |||
- | Version 1.1e behebt ein Problem beim Aufruf geerbter virtueller Methoden in tiefen | ||
- | Klassenhierarchien (siehe Abschnitt [[software: | ||
- | |||
- | ===== 2. Vorwort zur Version 1.0 ===== | ||
- | Als ich im Jahr 2004 (nicht ohne einen leisen Anflug von Nostalgie) einen ATARI Portfolio | ||
- | erstanden hatte, begab ich mich auf die Suche nach einer Möglichkeit, | ||
- | programmieren. Genauer: Das Programmieren für den Portfolio sollte auf dem Portfolio selbst | ||
- | möglich sein – schließlich ging das mit meinem Eigenbau-Homecomputer aus den achtziger Jahren, | ||
- | der noch viel ärmlicher ausgestattet war, ja auch!\\ | ||
- | Nun sind aber mit den Jahren Ansprüche und Erwartungen gewachsen, so dass das Ergebnis der | ||
- | Suche nach geeigneten Programmiersprachen/ | ||
- | etwas ernüchternd ausfiel. Prinzipiell möglich war die Programmiererei mit GoFolio, mit dessen | ||
- | Syntax ich mich aber nicht recht anfreunden konnte sowie dem doch recht steinzeitlichen POBASIC.\\ | ||
- | Und dann war da noch BOB. BOB fand sich mitsamt C-Quellcode und ein paar Beispielen in einem | ||
- | ZIP-Archiv [1], versprach Objektorientierung und sah auf den ersten Blick so ähnlich wie C++ aus. | ||
- | Leider war keinerlei Dokumentation dazu aufzutreiben. Eine längere Internet-Suche förderte | ||
- | immerhin BOBs Ursprung, einen 1991 entstandenen Artikel von David Michael Betz im Dr.Dobbs | ||
- | Journal [2] zutage. Allerdings ist dieser Artikel nicht hinreichend, | ||
- | verwenden zu können. Neben einer groben Erläuterung der hinter BOB stehenden Ideen, beschränkt | ||
- | sich der Autor auf die Aussage, dass es sich um keinen Ersatz für C oder C++ handele und es | ||
- | einfach sei, BOB um eigene Funktionen zu erweitern. Dass letzteres für eine sinnvolle Benutzung | ||
- | auch notwendig ist, zeigte dann ein erster Blick auf die Originalquellen und die darin | ||
- | bereitgestellten vordefinierten Funktionen.\\ | ||
- | Eine ausführlichere Recherche im Internet ergab, dass BOB von D. M. Betz selbst weiterentwickelt | ||
- | worden ist [3]. Die aktuelle Version lehnt sich ihrem Konzept nach (insbesondere was die | ||
- | Deklaration und Verwendung von Klassen betrifft) jedoch stärker an JavaScript als an C++ an und | ||
- | ist in ihrem Codeumfang bedeutend angewachsen, | ||
- | Rechnern – wie dem erwähnten Portfolio – nicht mehr möglich ist. Sie schied damit als einfache | ||
- | Alternative aus ((Wenn im weiteren Text von BOB die Rede ist, so ist damit immer die ursprüngliche Fassung nach [2] gemeint)).\\ | ||
- | Also machte ich mich ans Werk, mit der Absicht, BOB etwas tiefer zu verstehen, die Sprache so zu | ||
- | dokumentieren, | ||
- | Funktionen zu erweitern. Dabei zeigte sich, dass es an einigen Stellen notwendig bzw. zweckmäßig | ||
- | war, die Sprache selbst zu erweitern und ihre Implementierung zu überarbeiten. Zur besseren | ||
- | Unterscheidung vom Original habe ich die neue Version BOB+ getauft.\\ | ||
- | Wichtig war in diesem Zusammenhang, | ||
- | Minimalsystemen, | ||
- | Gesamtgröße von BOB+ weiterhin so klein zu halten, dass er auf solchen Systemen lauffähig bleibt | ||
- | und noch genügend Arbeitsspeicher für die eigentlichen Programme übrig lässt.\\ | ||
- | Der vorliegende Text ist keine Einführung in die Programmierung. Vielmehr wird versucht, die | ||
- | Sprache BOB+ in knapper Form darzustellen. Dabei müssen grundlegende Programmierkenntnisse | ||
- | in einer anderen – vorzugsweise C-ähnlichen – Sprache sowie Grundkenntnisse der | ||
- | objektorientierten Programmierung vorausgesetzt werden. Gleichzeitig werden die | ||
- | Gemeinsamkeiten und Unterschiede zu BOB dargestellt, | ||
- | Wegweiser für die Benutzung des Vorfahren von Nutzen ist.\\ | ||
- | |||
- | ===== 3.Grundlagen ===== | ||
- | |||
- | |||
- | |||
- | ==== 3.1 Was ist BOB, was ist BOB+? ==== | ||
- | BOB ist eine Hybridsprache, | ||
- | objektorientierten Erweiterungen. Syntaktisch lehnt sich BOB an C/C++ sowie Script-Sprachen wie | ||
- | JavaScript (D. Betz sieht eher eine Nähe zu Lisp) an. BOB ist eine sehr kleine Sprache mit nur 11 " | ||
- | Schlüsselwörtern (vgl. [[software: | ||
- | BOB ist weder ein Compiler noch ein „echter“ Interpreter. Der Quellcode eines Programms wird zunächst in einen Bytecode übersetzt, der anschließend interpretiert wird.\\ | ||
- | BOB+ übernimmt das Konzept BOB, erweitert jedoch sowohl die Sprache als auch deren Implementierung um einige grundlegende Elemente, die für Anwendungen, | ||
- | * Unterstützung von Gleitpunkt-Arithmetik (Datentyp float) | ||
- | * 32-Bit-Integer | ||
- | * ganzzahlige numerische Literale auch in oktaler oder hexadezimaler Schreibweise | ||
- | * variable Parameterlisten für Funktionen | ||
- | * „echte“ polymorphe Klassen ((BOB erlaubt zwar virtuelle Funktionen, kennt aber keine Möglichkeit, | ||
- | * Überladen von Operatoren für Objekte | ||
- | * Typinformationen zur Laufzeit (RTTI) | ||
- | * Zugriff auf systemnahe Funktionen | ||
- | * integrierte Serialisierung beliebiger Daten | ||
- | * Verwendung vorkompilierter Bytecode-Bibliotheken | ||
- | * direkte Einbindung von BOB+-Quellen in Kommando-Scripts (Batch-Dateien) | ||
- | * Ergebnisrückgabe an den Aufrufer im DOS-Errorlevel | ||
- | * verbesserte Speicherverwaltung mit expliziter Freigabe nicht mehr benötigter Daten | ||
- | Dabei bleibt BOB+ abwärtskompatibel zu BOB. D.h. für BOB geschriebene Programme können | ||
- | ohne Änderung mit BOB+ übersetzt und ausgeführt werden.\\ | ||
- | |||
- | \\ | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | ==== 3.2 Benutzung von BOB+ ==== | ||
- | BOB+ besteht aus einer einzigen ausführbaren Datei (BP.EXE) und wird von der Kommandozeile gestartet. Um Aufrufe von beliebiger Stelle zu vereinfachen, | ||
- | bp [-i][-d][-t][-c][-e][-I] [sourcefile [..]] [-r objfile [..]] [-o outfile] [# userarg [..]] | ||
- | |||
- | Dabei haben die einzelnen Optionen folgende Bedeutung: | ||
- | * -i (info) Anzeige von Copyright und Funktionsnamen ((BOB verhält sich immer so, als sei –i gesetzt, die Optionen –d und –t sind in BOB ebenfalls verfügbar)) | ||
- | * -d (debug) Ausgabe des erzeugten Byte-Codes beim Übersetzen | ||
- | * -t (trace) Ablaufverfolgung des Byte-Codes bei der Ausführung | ||
- | * -c (compile) Die angegebenen Quellen werden nicht ausgeführt sondern nur in Byte-Code übersetzt. | ||
- | * -r (read / run) Lesen und Ausführen von vorkompilierten Byte-Code-Modulen | ||
- | * -o (output) Name der auszugebenden Byte-Code-Datei. Die Option wird nur ausgewertet, | ||
- | * -e (make exe) Binden des übersetzten Byte-Codes mit der Laufzeitumgebung BPR.EXE zu einem eigenständig ausführbaren Programm (ab Version 1.1d). Die Option wird nur ausgewertet, | ||
- | * -I (use bpri) Binden des übersetzten Byte-Codes mit der Laufzeitumgebung BPRI.EXE statt mit BPR.EXE (ab Version 1.1d). Die Option wird nur ausgewertet, | ||
- | |||
- | Quelldateien und einzulesende Module können ohne Dateiendungen angegeben werden. In solchen Fällen werden implizit die Erweiterungen „.bp“ bzw. „.bpm“ angenommen ((In BOB darf keine Erweiterung angegeben werden und die Datei muss immer die Erweiterung „.bob“ haben)).\\ | ||
- | Bei Angabe mehrerer Quelldateien werden diese in der angegebenen Reihenfolge in Bytecode übersetzt, bevor die eigentliche Programmausführung beginnt. Die zu ladenden vorkompilierten Module werden //vor// dem Kompilieren der Quellen (und ebenfalls in der angegebenen Reihenfolge) gelesen. | ||
- | |||
- | BOB+ erlaubt zusätzlich die Angabe einer Liste von Benutzer-Argumenten, | ||
- | |||
- | Für den Aufruf von Funktionen und die Zwischenspeicherung von Argumenten bzw. temporären Werten verwendet BOB/BOB+ einen Stack mit einer Kapazität von 500 Einträgen. BOB+ erlaubt die Modifikation dieses Wertes mit Hilfe der Umgebungsvariablen BPSTACK. So kann z.B. mit dem Eintrag '' | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | ==== 3.3 Laufzeitumgebung und Compiler ==== | ||
- | Für die Ausführung von vorkompilierten Bytecode-Modulen steht die BOB+-Laufzeitungebung BPR.EXE zur Verfügung. Gegenüber der Vollversion von BOB+ besteht die Einschränkung, | ||
- | Dem entsprechend werden die Optionsschalter –c, -r, -o, -d und –t nicht unterstützt. | ||
- | Der Aufruf der Laufzeitumgebung erfolgt nach der Syntax\\ | ||
- | bpr [-i] [ objfile [..]] [# userarg [..]] | ||
- | Dabei gibt die Option –i einen Copyright-Hinweis und die Aufrufsyntax aus. Für die zu ladenden vorkompilierten Module und die Benutzerargumente gelten sinngemäß die Aussagen aus [[software: | ||
- | In Version 1.1 von BOB+ existiert außerdem ein separater Bytecode-Compiler. Er kommt ohne den den Bytecode-Interpreter und die interne Funktionsbibliothek aus und benötigt dadurch gegenüber der Vollversion wesentlich weniger Platz im Arbeitsspeicher und auf dem Datenträger.Der Bytecode-Compiler wird nach der Syntax\\ | ||
- | bpc [-i] [-d][-e][-I] [sourcefile [..]] [-r objfile [..]][-o outfile] | ||
- | aufgerufen. Dabei entspricht die Bedeutung der einzelnen Optionen mit folgenden Ausnahmen denen der Vollversion: | ||
- | * Die Option –c wird nicht unterstützt. Sie ist implizit immer gesetzt. | ||
- | * Die Option –r bindet vorkompilierte Module mit ein, führt sie aber nicht aus. | ||
- | * Da das Programm nicht ausgeführt sondern lediglich in Bytecode übersetzt wird, ist die Option –t (trace) nicht verfügbar und keine Angabe von Benutzer-Argumenten möglich.\\ | ||
- | \\ | ||
- | **Hinweis: | ||
- | In Version 1.1 von BOB+ gibt es sowohl von der Vollversion als auch von der Laufzeitumgebung jeweils eine Variante ohne Unterstützung von Gleitpunkt-Arithmetik. Diese Varianten heißen bpi.exe bzw. bpri.exe und kommen mit etwa 20KB weniger Speicher aus. Sie sind für den Einsatz auf Systemen mit extrem knappen Ressourcen gedacht.\\ | ||
- | \\ | ||
- | |||
- | |||
- | ==== 3.4 Erzeugen ausführbarer Dateien ==== | ||
- | Mit Version 1.1d wird das Erzeugen direkt ausführbarer (EXE-)Dateien unterstützt. Dabei wird jedoch nicht unmittelbar Maschinencode erzeugt sondern der von Compiler erzeugte Byte-Code mit einer der Laufzeitumgebungen (BPR bzw. BPRI) zu einem eigenständigen Programm gebunden. Benötigter Speicherplatz und Laufzeitverhalten entsprechen dabei der Ausführung der jeweiligen Laufzeitumgebung mit einem vorkompilierten Modul. Das Erzeugen eigenständiger Programme erleichtert dagegen die Weitergabe, da nicht zusätzlich eine die Laufzeitumgebung mitgeliefert und installiert werden muss.\\ | ||
- | \\ | ||
- | Beim Zusammenfügen eines solchen Programms wird eine Kopie der Laufzeitumgebung((... also bpr.exe bzw. bpri.exe, die deshalb auch im aktuellen Verzeichnis oder im Suchpfad vorhanden sein muss)) | ||
- | \\ | ||
- | Das einfache Anhängen des Bytecodes an die Laufzeitumgebung hat den Vorteil, dass zur Laufzeit kein zusätzlicher Speicherplatz zur Pufferung des Bytecodes benötigt wird. Außerdem erlaubt es dieses Prinzip auch, für die Laufzeitumgebung selbst eine – z.B mit PKLITE – komprimierte Variante zu verwenden.\\ | ||
- | \\ | ||
- | **Hinweis: | ||
- | Bei der Verwendung so erzeugter eigenständiger Programme verändert sich die Auswertung übergebener Kommandozeilen-Parameter. Weil hier keine Steuerung von BOB+ mehr möglich (bzw. notwendig) ist, werden alle Parameter als Benutzer-Argumente angesehen, so als wären sie hinter dem ‚# | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | ===== 4. Programmstruktur ===== | ||
- | Jedes BOB/ | ||
- | Das nun folgende unvermeidliche „Hello World“-Beispiel zeigt den typischen Programmaufbau: | ||
- | |||
- | <code cpp> | ||
- | /* BOB+ Hello World example */ | ||
- | // write a string to console | ||
- | printString(str; | ||
- | { | ||
- | n = strlen(str); | ||
- | for (i=0; i<n; i++) | ||
- | | ||
- | } | ||
- | |||
- | main() | ||
- | { | ||
- | | ||
- | | ||
- | } | ||
- | </ | ||
- | |||
- | Wie man sieht, besteht eine große syntaktische Ähnlichkeit zu C/ | ||
- | Zunächst ist zu sagen, dass BOB+ (wie auch BOB) formatfrei ist. Das bedeutet, dass Einrückungen, | ||
- | \\ | ||
- | Zeilen 1 und 3 in obigem Beispiel enthalten Kommentare. Danach wird eine Funktion // | ||
- | Die im Funktionskopf hinter dem Semikolon aufgeführte Liste ( i, n) definiert lokal innerhalb der Funktion gültige Variablen.\\ | ||
- | \\ | ||
- | Die Einsprungfunktion //main// ruft nun // | ||
- | In diesem Zusammenhang ist auf die besondere Bedeutung des Rückgabewertes der // | ||
- | \\ | ||
- | |||
- | |||
- | ===== 5 Syntaktische Grundelemente ===== | ||
- | In diesem Abschnitt werden eine Reihe syntaktischer Grundelemente erklärt, die für das Schreiben von BOB+-Programmen von Bedeutung sind. Bitte beachten Sie, dass es sich hierbei um keine vollständige Syntaxbeschreibung handelt. Vielmehr sollen die wichtigsten Sprachelemente im Vergleich zu C/C++ dargestellt werden.\\ | ||
- | \\ | ||
- | |||
- | |||
- | |||
- | ==== 5.1 Kommentare ==== | ||
- | BOB+ kennt drei Arten von Kommentaren: | ||
- | * Kommentare im C-Stil: | ||
- | Solche Kommentare haben die Form /* Kommentartext */.Sie können sich über mehrere Zeilen erstrecken, dürfen jedoch nicht verschachtelt werden.\\ | ||
- | * Kommentare im C++-Stil: | ||
- | Diese Kommentare werden in der Form / / Kommentartext notiert. Sie reichen jeweils bis zum Ende der aktuellen Quelltextzeile.\\ | ||
- | * Mit @ eingeleitete Kommentare: | ||
- | Diese Form des Kommentars dient der Einbettung von BOB+-Quellen in Komando-Scripts | ||
- | (Batch-Dateien) unter DOS. Für BOB+ selbst ist sie identisch mit den C++-Kommentaren. Da | ||
- | das Zeichen @ in Batch-Scripts aber eine gültige Kommandozeile einleitet, deren Ausgabe | ||
- | lediglich unterdrückt wird, lässt sich diese Art des Kommentars verwenden, um BOB+-Code in | ||
- | Stapeldateien einzubinden. Ein Beispiel hierzu findet sich in [[software: | ||
- | |||
- | |||
- | ==== 5.2 Bezeichner ==== | ||
- | Für Bezeichner gelten die gleichen Regeln wie in C bzw. C++:\\ | ||
- | Bezeichner bestehen aus einer Folge von Buchstaben (ohne Umlaute und ß) und Ziffern bzw. dem | ||
- | Unterstrich (_). Sie dürfen nicht mit einer Ziffer beginnen und eine Gesamtlänge von 200 Zeichen ((BOB gestattet maximal 50 Zeichen.)) nicht überschreiten. Die Groß- bzw. Kleinschreibung ist signifikant.\\ | ||
- | Beipiele für Bezeichner: | ||
- | <code cpp> | ||
- | MyClass | ||
- | myValue | ||
- | _anInternalVariable | ||
- | p1 | ||
- | </ | ||
- | Generell sollten Bezeichner so gewählt werden, dass sie das spätere Lesen eines Quelltextes | ||
- | erleichtern. Das bedeutet insbesondere, | ||
- | Verwendungszweck zulassen sollten.\\ | ||
- | |||
- | ==== 5.3 Literale ==== | ||
- | Literale sind direkt im Quellcode notierte Werte. BOB+ kennt hiervon vier Typen:\\ | ||
- | |||
- | |||
- | |||
- | |||
- | === Zeichenliterale === | ||
- | Ein Zeichenliteral ist ein einzelnes Zeichen mit einem Zeichencode zwischen 0 und 255, das in | ||
- | Hochkommata geklammert ist, z.B. '' | ||
- | Das letzte Zeichen weist dabei eine Besonderheit auf. Es repräsentiert kein druckbares Zeichen | ||
- | sondern ein Steuerzeichen. Die Darstellung spezieller Zeichen wird stets mit einem Backslash (\ , | ||
- | oft auch Escape-Zeichen genannt) eingeleitet. Tabelle 1 listet die von BOB+ interpretierten | ||
- | Escape-Codes mit ihrer Bedeutung auf.\\ | ||
- | |||
- | ^Escape-Code ^Bedeutung ^Zeichencode (Hex)^ | ||
- | | \a | Alarmton | ||
- | | \b | Backspace | ||
- | | \f | Seitenvorschub | ||
- | | \n | Zeilenvorschub* | ||
- | | \r | Wagenrücklauf | ||
- | | \t | Tabulator horizontal* | ||
- | | \v | Tabulator vertikal | ||
- | | \ \ | Backslash* | ||
- | | \‘ | Apostroph* | ||
- | | \“ | Anführungszeichen* | ||
- | Tabelle 1 Von BOB+ unterstützte Escape-Codes ((Die mit * gekennzeichneten Codes werden auch von BOB unterstützt.)) | ||
- | |||
- | **Achtung: | ||
- | Zeichencodes in Escape-Sequenzen. Ein Konstrukt wie ‘\0xFF‘ ist also nicht das Zeichen mit dem | ||
- | Code 255 sondern ein ungültiger Ausdruck.\\ | ||
- | Ab Version 1.1b ist es zulässig, hinter dem Backslash ein gannzzahliges Literal (siehe unten) in dezimaler, oktaler oder hexadezimaler Schreibweise zu notieren, dessen niederwertigstes Byte dann als Zeichencode interpretiert wird. | ||
- | |||
- | Intern werden Zeichenliterale wie Ganze Zahlen behandelt, wobei der Zeichencode dem Zahlenwert | ||
- | entspricht. Dem entsprechend können sie im Quelltext überall dort verwendet werden, wo auch eine | ||
- | Ganze Zahl stehen kann.\\ | ||
- | |||
- | |||
- | === Zeichenkettenliterale === | ||
- | Zeichenkettenliterale sind Folgen beliebiger druckbarer Zeichen oder Escape-Codes (vgl. Tabelle | ||
- | 1), die in Anführungszeichen eingeschlossen sind. Kommt das Anführungszeichen selbst in einer | ||
- | Zeichenkette vor, so muss es als Escape-Code angegeben werden. Implementierungsbedingt dürfen | ||
- | Zeichenkettenliterale eine Länge von 200 Zeichen (bei BOB 50 Zeichen) nicht überschreiten. | ||
- | Beispiele für Zeichenkettenliterale: | ||
- | | ||
- | “Er sagte \“Ich bin müde\“.“ | ||
- | | ||
- | | ||
- | |||
- | |||
- | === Ganzzahlige Literale === | ||
- | Ganzzahlige Literale sind Darstellungen Ganzer Zahlen in dezimaler, oktaler oder hexadezimaler | ||
- | Schreibweise, | ||
- | Oktalzahlen – wie in C – dadurch gekennzeichnet, | ||
- | Ziffer im Bereich zwischen 1 und 7 liegt. Hexadezimalzahlen beginnen mit 0x. Alle anderen Zahlen | ||
- | sind Dezimalzahlen. Wegen der internen Darstellung als 32-Bit-Integer (( BOB arbeitet mit 16-Bit-Integer-Werten. Dementsprechend geht der Wertebereich von –2^15 bis + 2^15-1. Außerdem sind nur dezimale Zahldarstellungen zulässig.)) haben ganzzahlige Literale einen Wertebereich von –2^31 bis +2^31-1. | ||
- | |||
- | Beispiele für ganzzahlige Literale: | ||
- | 17 | ||
- | | ||
- | | ||
- | 021 | ||
- | | ||
- | |||
- | |||
- | |||
- | === Fließkommaliterale === | ||
- | Fließkommaliterale sind Darstellungen rationaler Zahlen nach der Syntax\\ | ||
- | '' | ||
- | Dabei ist digit eine Dezimalziffer. Die interne Darstellung erfolgt mit einfacher Genauigkeit (4 | ||
- | Byte, wie Typ float in C), wodurch die Genauigkeit auf 7 Stellen der Mantisse begrenzt ist und der | ||
- | Wertebereich zwischen -3.4E38 und 3.4E+38 liegt. | ||
- | |||
- | Beispiele für Fließkommaliterale: | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | 3E14 | ||
- | |||
- | |||
- | |||
- | |||
- | ==== 5.4 Definitionen, | ||
- | Wie bereits im [[software: | ||
- | \\ | ||
- | Jede dieser Definitionen besteht aus einem //Kopf//, der u.a. den Namen des jeweiligen Codeobjekts beinhaltet sowie einem //Block//, welcher den eigentlichen Inhalt einschließt.\\ | ||
- | Ein Block ist eine Zusammenfassung von aufeinander folgenden Anweisungen und (optional) Variablendeklarationen. In BOB+ wird ein Block – wie u.a. in C/C++ - durch geschwungene Klammern ( { und } ) begrenzt.\\ | ||
- | \\ | ||
- | Jede in einem Block enthaltene Anweisung oder Definition muss – ebenfalls wie in C/C++ - mit einem Semikolon (;) abgeschlossen ((Das ist ein feiner aber wichtiger Unterschied zu Sprachen wie z.B. PASCAL, wo das Semikolon die Anweisungen nicht abschließt sondern trennt. In BOB/BOB+ muss das Semikolon auch hinter der letzten Anweisung eines Blocks oder vor einem Schlüsselwort geschrieben werden.)) werden. Überall dort, wo syntaktisch eine Anweisung vorgesehen ist, kann wiederum ein Block stehen. Dies ist besonders im Zusammenhang mit den Steuerstrukturen (siehe [[software: | ||
- | \\ | ||
- | Nachfolgend werden die beschriebenen Elemente anhand eines etwas ausführlicheren Beispiels veranschaulicht. Es handelt sich dabei um ein Programm, welches die zeilenweise Eingabe von Zeichenketten (z.B. Namen) erwartet, sie in einer sortierten Liste speichert und am Ende den Listeninhalt wieder ausgibt. Das Beispiel geht über das bisher Besprochene hinaus, indem von Elementen (Klassen, Funktionen, Steuerstrukturen) Gebrauch gemacht wird, deren Erläuterung Gegenstand späterer Abschnitte ist. Es ist jedoch ein „typisches“ BOB+-Programm und sollte – einige Programmierkenntnisse in anderen Sprachen vorausgesetzt – leicht nachvollziehbar sein.\\ | ||
- | |||
- | |||
- | <code cpp> | ||
- | |||
- | /* sorted stringlist example */ | ||
- | // ================================================================== | ||
- | // ListEntry class declaration | ||
- | class ListEntry | ||
- | { | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | |||
- | | ||
- | | ||
- | } | ||
- | |||
- | // ================================================================= | ||
- | // Implementation of ListEntry class | ||
- | // constructor | ||
- | ListEntry:: | ||
- | { | ||
- | | ||
- | _next = null; // initially _next points to nothing | ||
- | } | ||
- | |||
- | // get value method | ||
- | ListEntry:: | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | // destructor | ||
- | ListEntry:: | ||
- | { | ||
- | if (_next) | ||
- | delete _next; // destroy next entry | ||
- | } | ||
- | |||
- | // get next method | ||
- | ListEntry:: | ||
- | |||
- | // set next method | ||
- | ListEntry:: | ||
- | |||
- | // =============================================================== | ||
- | // Declaration of List class | ||
- | class List | ||
- | { | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | // ============================================================== | ||
- | // Implementation of List class | ||
- | // constructor | ||
- | List:: | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | // destructor | ||
- | List:: | ||
- | { | ||
- | if (_first) | ||
- | delete _first; // delete contents | ||
- | } | ||
- | |||
- | // add new entry to sorted list | ||
- | List:: | ||
- | { | ||
- | | ||
- | if (!_first) // nothing to compare in empty list | ||
- | _first = newentry; // single statement | ||
- | else | ||
- | { // statement block | ||
- | if (strcmp(_first-> | ||
- | { | ||
- | | ||
- | | ||
- | } | ||
- | else | ||
- | { | ||
- | // Walk through the list until correct position found. | ||
- | // Variable p is used like a pointer. | ||
- | | ||
- | { | ||
- | if (strcmp(p-> | ||
- | { | ||
- | | ||
- | | ||
- | } | ||
- | } | ||
- | | ||
- | } | ||
- | } | ||
- | } | ||
- | |||
- | // print sorted values to console | ||
- | List:: | ||
- | { | ||
- | | ||
- | while ( p != null) | ||
- | { | ||
- | print(p-> | ||
- | p = p-> | ||
- | } | ||
- | } | ||
- | |||
- | // ============================================================ | ||
- | // programs entry point | ||
- | main(; | ||
- | { | ||
- | | ||
- | // read text lines from console until empty line was read | ||
- | while (1) // loops forever | ||
- | { | ||
- | print(" | ||
- | s = gets(); | ||
- | if (strlen(s) == 0) | ||
- | | ||
- | nameList-> | ||
- | } | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | //Bitte beachten Sie, dass das Beispiel Spracherweiterungen und vordefinierte Funktionen verwendet, die in BOB nicht zur Verfügung stehen.//\\ | ||
- | |||
- | |||
- | |||
- | ==== 5.5 Verarbeitungsanweisungen ==== | ||
- | Verarbeitungsanweisungen sind eine mit BOB+ eingeführte Spracherweiterung. Obgleich BOB+ keinen Präprozessor besitzt, haben sie eine gewisse Ähnlichkeit zu Präprozessorbefehlen in C/C++ und werden auch so notiert.\\ | ||
- | \\ | ||
- | Verarbeitungsanweisungen werden – im Gegensatz zu allen anderen Anweisungen – vom Compiler während der Übersetzung des Quellcodes und nicht vom Bytecode-Interpreter ausgeführt. Sie sind syntaktisch außerdem nur auf der äußersten Quelltextebene – also außerhalb aller Klassen- und Funktionsdefinitionen – zugelassen und werden **nicht** mit einem Semikolon abgeschlossen.\\ | ||
- | \\ | ||
- | Die aktuelle Version von BOB+ kennt folgende Verarbeitungsanweisungen: | ||
- | \\ | ||
- | \\ | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | === #use === | ||
- | Die # | ||
- | \\ | ||
- | Verwendung: ''# | ||
- | \\ | ||
- | Dem Dateinamen kann ein relativer oder absoluter Pfad vorangestellt sein. BOB+ sucht die angegebene Datei zunächst im aktuellen Verzeichnis. Hat die Suche dort keinen Erfolg, so werden zusätzlich die in der Umgebungsvariablen PATH angegebenen Verzeichnisse durchsucht.\\ | ||
- | \\ | ||
- | Anwendungsbeispiel: | ||
- | \\ | ||
- | Eine Bibliothek soll den Namen tstfunc.bp haben und eine Funktion mit dem Namen testfunc | ||
- | exportieren. | ||
- | |||
- | <code cpp> | ||
- | |||
- | /* using #use example – module tstfunc.bp */ | ||
- | testfunc(n) | ||
- | { | ||
- | | ||
- | } | ||
- | </ | ||
- | |||
- | Die Bibliothek wird nun in Bytecode übersetzt: | ||
- | bp –c tstfunc –o tstfunc.bpm | ||
- | ... und von nachfolgendem Programm benutzt:\\ | ||
- | |||
- | <code cpp> | ||
- | /* using #use example – main module */ | ||
- | #use “tstfunc.bpm“ | ||
- | |||
- | main() | ||
- | { | ||
- | | ||
- | } | ||
- | </ | ||
- | \\ | ||
- | \\ | ||
- | |||
- | |||
- | |||
- | |||
- | === #defvar === | ||
- | |||
- | Mit #defvar können initialisierte globale Variablen außerhalb von Funktionen definiert werden.\\ | ||
- | \\ | ||
- | Verwendung: ''# | ||
- | \\ | ||
- | Dabei ist //varname// ein gültiger Bezeichner und //value// der zugehörige Wert. Bitte beachten Sie, dass die Initialisierung des Variablenwerts zur Übersetzungs- und nicht zur Laufzeit erfolgt. Deshalb können für //value// nur Literale angegeben werden.\\ | ||
- | \\ | ||
- | Beispiele: | ||
- | <code cpp> | ||
- | #defvar PI 3.141593 | ||
- | #defvar Version “2.1.0“ | ||
- | #defvar maxSize 2048 | ||
- | </ | ||
- | \\ | ||
- | \\ | ||
- | |||
- | |||
- | |||
- | |||
- | === #endsrc === | ||
- | Die #endsrc Anweisung kennzeichnet das (vorzeitige) Ende eines BOB+-Quelltextes, | ||
- | |||
- | <code cpp> | ||
- | @bp graph.bat | ||
- | @goto end | ||
- | // global settings | ||
- | #defvar sizeX 240 | ||
- | #defvar sizeY 64 | ||
- | #defvar graphMode 4 | ||
- | #defvar textMode 7 | ||
- | |||
- | main(; | ||
- | { | ||
- | | ||
- | | ||
- | | ||
- | ms = timer(); | ||
- | n=0; | ||
- | for (x=0; | ||
- | { | ||
- | n++; | ||
- | x2= px -x; | ||
- | line(x, | ||
- | } | ||
- | for (y=0; | ||
- | { | ||
- | n++; | ||
- | y2= py-1 -y; | ||
- | line(0, | ||
- | } | ||
- | ms = timer() - ms; | ||
- | r = n*1000 / ms; | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | #endsrc | ||
- | :end | ||
- | </ | ||
- | |||
- | Das Programm füllt den Bildschirm mit Linien und misst die dafür benötigte Zeit. Am Ende wird die Zeichengeschwindigkeit (Linien je Sekunde) ausgegeben.\\ | ||
- | \\ | ||
- | Die ersten beiden Zeilen enthalten Anweisungen für den DOS-Kommandoprozessor. Das vorangestellte @-Zeichen unterdrückt unter DOS das Bildschirmecho und kennzeichnet die Zeilen unter BOB+ als Kommentare. Der BOB+-Quelltext endet mit der #endsrc Anweisung.\\ | ||
- | \\ | ||
- | Die letzte Zeile gehört wieder dem Kommandoprozessor – es ist die das Programmende kennzeichnende Sprungmarke.\\ | ||
- | \\ | ||
- | |||
- | |||
- | |||
- | |||
- | ===== 6. Variablen und Datentypen ===== | ||
- | BOB+ (und auch BOB) ist eine Sprache, die gewöhnlich als nicht oder schwach typisiert bezeichnet | ||
- | wird. Etwas genauer gilt folgendes: | ||
- | |||
- | //In BOB+ haben nicht die Variablen sondern allein die Werte einen Datentyp.// | ||
- | |||
- | |||
- | |||
- | ==== 6.1 Variablen ==== | ||
- | Variablen sind demnach einfach Ablageorte für einen beliebigen Wert. Da sie selbst über keine Typeigenschaften verfügen, ist es i.a. auch nicht erforderlich, | ||
- | Der Gültigkeitsbereich einer Variablen ist – sofern keine besonderen Vorkehrungen getroffen werden – global, d.h. auf eine Variable kann, gleichgültig wo sie definiert wurde, von jeder Stelle des Programmes zugegriffen werden. Dies kann bei größeren Programmen zu unerwünschten | ||
- | Seiteneffekten führen, wenn man versehentlich an verschiedenen Stellen ein- und dieselbe Variable zu unterschiedlichen Zwecken benutzt. Hierzu ein Beispiel:\\ | ||
- | <code cpp> | ||
- | // calculate n! | ||
- | fac(n) | ||
- | { | ||
- | if (n==0) | ||
- | return 1; | ||
- | | ||
- | f*=i; | ||
- | | ||
- | } | ||
- | |||
- | main() | ||
- | { | ||
- | for (j=1; | ||
- | print(" | ||
- | } | ||
- | |||
- | /* Variable i in this version of main will be modified by fac. | ||
- | main() | ||
- | { | ||
- | for (i=1; | ||
- | | ||
- | } | ||
- | */ | ||
- | </ | ||
- | Wenn Sie die hier auskommentierte Variante der main-Funktion aktivieren, berechnet das Programm bis in alle Ewigkeit die Fakultät von 1. Der Grund dafür ist, dass sowohl fac als auch main die globale Variable i verwenden (ohne etwas von einander zu „wissen“).\\ | ||
- | Um dieses Problem zu beheben, besteht die Möglichkeit, | ||
- | <code cpp> | ||
- | /* using function-level variables */ | ||
- | // calculate n! | ||
- | fac(n; | ||
- | { | ||
- | if (n==0) | ||
- | return 1; | ||
- | | ||
- | f*=i; | ||
- | | ||
- | } | ||
- | |||
- | main(;i) | ||
- | { | ||
- | for (i=1; | ||
- | print(" | ||
- | } | ||
- | </ | ||
- | Wie man sieht, werden hier ausschließlich lokale Variablen verwendet. Wenn Sie wiederverwendbare und gut wartbare Programme schreiben wollen, sollten Sie globale Variablen so weit wie möglich vermeiden – und wenn sie schon unbedingt notwendig sind, gut dokumentieren.\\ | ||
- | \\ | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | ==== 6.2 Datentypen ==== | ||
- | In BOB+ werden alle in einem Programm vorkommenden Werte in sogenannten Value-Objekten abgelegt. Ein solches Objekt besitzt im wesentlichen eine Typinformation sowie den jeweils // | ||
- | * Bei der Zuweisung an Variablen werden Werttypen vollständig kopiert, bei Referenztypen dagegen nur der Verweis auf den Datenbereich. Deshalb betreffen hier Datenänderungen alle Variablen, die auf den jeweiligen Wert verweisen. | ||
- | |||
- | Ein Beispiel: | ||
- | <code cpp> | ||
- | main(; | ||
- | { | ||
- | s1 = “Hello“; | ||
- | s2 = s1; // assign variable s1 to s2 | ||
- | s2[1] = ‘a‘; // modify second character in s2 | ||
- | | ||
- | } | ||
- | </ | ||
- | Hier wird „Hallo“ und nicht – wie man vielleicht vermuten könnte – „Hello“ ausgegeben.\\ | ||
- | * Die erwähnten Value-Objekte und mit ihnen die Daten der Werttypen werden auf dem Stack angelegt und mit demselben aufgeräumt. Anders verhält es sich mit den Referenztypen. Deren Datenbereich muß (bzw. sollte) – sofern sie zur Laufzeit des Programms erzeugt werden – vom Benutzer wieder freigegeben werden.\\ | ||
- | |||
- | |||
- | === 6.2.1 Werttypen === | ||
- | Werttypen sind in BOB+ die numerischen Typen sowie der Typ null.\\ | ||
- | |||
- | == Datentyp int: == | ||
- | Der Datentyp int repräsentiert eine Ganze Zahl mit 32 Bit Breite ((In BOB sind int-Werte nur 16 Bit breit.)). Daraus ergibt sich ein Wertebereich von -2^31 bis +2^31-1. Werte dieses Typs werden auch zur Darstellung einzelner Zeichen und boolescher Werte verwendet.\\ | ||
- | Zulässige Operationen für den Typ int sind:\\ | ||
- | * Zuweisung an eine Variable | ||
- | * Verwendung in numerischen Ausdrücken | ||
- | * Verwendung in string-Ausdrücken | ||
- | * Bitoperationen | ||
- | * numerische Vergleiche | ||
- | * Verwendung als Funktionsparameter | ||
- | |||
- | Werte vom Typ int können in numerischen Ausdrücken und Vergleichen ohne explizite Typkonvertierung mit Werten des Typs float kombiniert werden. In diesem Fall erfolgt eine implizite Umwandlung des gesamten Ausdrucks nach float.\\ | ||
- | Bei Verwendung von int-Werten in string-Ausdrücken (Verkettung) wird der int-Wert als Zeichencode interpretiert.\\ | ||
- | |||
- | == Datentyp float == | ||
- | Der Datentyp float ist nur in BOB+ (nicht in BOB) definiert. Er repräsentiert eine Rationale Zahl mit einfacher Genauigkeit (32 Bit). Der Wertebereich liegt zwischen -3.4E38 und 3.4E+38 bei einer numerischen Genauigkeit von 7 Stellen.\\ | ||
- | Zulässige Operationen für den Typ float sind:\\ | ||
- | * Zuweisung an eine Variable | ||
- | * Verwendung in numerischen Ausdrücken | ||
- | * numerische Vergleiche | ||
- | * Verwendung als Funktionsparameter | ||
- | |||
- | Werte vom Typ float können in numerischen Ausdrücken und Vergleichen ohne explizite Typkonvertierung mit Werten des Typs int kombiniert werden. In diesem Fall erfolgt eine implizite Umwandlung des gesamten Ausdrucks nach float.\\ | ||
- | |||
- | == Datentyp null == | ||
- | Der Datentyp null kennzeichnet einen nicht initialisierten Wert.. Im Quelltext eines BOB+-Programmes werden Daten dieses Typs durch das Schlüsselwort **null** ((Zur Wahrung der Abwärtskompatibilität zu BOB existiert außerdem das Schlüsselwort nil, das gleichbedeutend mit null ist.)) beschrieben, | ||
- | Zulässige Operationen für den Typ null sind:\\ | ||
- | * Zuweisung an eine Variable | ||
- | * Verwendung in numerischen Ausdrücken | ||
- | * Verwendung in Vergleichen | ||
- | * Verwendung als Funktionsparameter | ||
- | |||
- | Werte vom Typ null können in Vergleichen ohne explizite Typkonvertierung mit allen anderen Typen kombiniert werden. Dabei ist der Wert null kleiner als jeder andere Wert.\\ | ||
- | |||
- | |||
- | |||
- | === 6.2.2 Referenztypen === | ||
- | Alle Datentypen in BOB+, die keine Werttypen sind, sind Referenztypen.\\ | ||
- | |||
- | == Datentyp string == | ||
- | Der Datentyp string repräsentiert eine Zeichenkette. Werte dieses Typs können mit Hilfe von Zeichenkettenliteralen (vgl. [[software: | ||
- | Zulässige Operationen für den Typ string sind:\\ | ||
- | * Zuweisung an eine Variable | ||
- | * Verwendung in string-Ausdrücken | ||
- | * Verwendung in Vergleichen | ||
- | * Verwendung als Funktionsparameter | ||
- | * Zugriff auf einzelne Zeichen mit Hilfe des Operators [] | ||
- | |||
- | == Datentyp FILE == | ||
- | Der Datentyp FILE ist ein Verweis auf eine geöffnete Datei. Instanzen dieses Typs werden mit der vordefinierten Funktion fopen erzeugt und mit fclose wieder freigegeben. In BOB+ (und auch in BOB) existieren – wie in C – drei vordefinierte Konstanten des FILE-Typs, die auf die Standard Ein und –Ausgabedateien des Systems verweisen: | ||
- | * stdin: Standard-Eingabe | ||
- | * stdout: Standard-Ausgabe | ||
- | * stderr: Standard-Fehlerausgabe | ||
- | |||
- | Diese Standarddateien können nicht mit fopen bzw. fclose geöffnet oder geschlossen werden.\\ | ||
- | Zulässige Operationen für den Datentyp FILE sind:\\ | ||
- | * Zuweisung an eine Variable | ||
- | * Verwendung in Vergleichen | ||
- | * Verwendung als Funktionsparameter (insbesondere bei vordefinierten I/ | ||
- | |||
- | == Datentyp vector == | ||
- | Der Datentyp vector repräsentiert ein Datenfeld fester (d.h. bei der Erzeugung festgelegter) Größe, dessen Elemente beliebige (auch typverschiedene) Werte sein können. Instanzen dieses Typs werden mit den vordefinierten Funktionen newvector oder //Vec// bzw. //T// erzeugt und mit //free// wieder freigegeben.\\ | ||
- | Zulässige Operationen für den Datentyp vector sind:\\ | ||
- | * Zuweisung an eine Variable | ||
- | * Verwendung als Funktionsparameter | ||
- | * Zugriff auf einzelne Elemente mit Hilfe des Operators [] | ||
- | |||
- | == Datentyp function == | ||
- | Der Datentyp function repräsentiert eine innerhalb des Programmes aufrufbare Funktion. Intern werden vordefinierte und benutzerdefinierte (d.h. selbst in BOB+ geschriebene) Funktionen nochmals unterschieden ((Deshalb liefert die Funktion gettypename (siehe 12.2) auch den Typnamen „code“ für vordefinierte und „bytecode“ für benutzerdefinierte Funktionen.)). Aus Benutzersicht ist diese Unterscheidung nicht notwendig. Eine explizite Instanzenbildung von Funktionen ist nicht möglich. Von einer Funktion existiert stets genau eine Instanz, die für vordefinierte Funktionen bei der Initialisierung von BOB+ und für benutzerdefinierte Funktionen während der Übersetzung der Funktionsdeklaration (siehe [[software: | ||
- | Zulässige Operationen für den Datentyp function sind:\\ | ||
- | * Zuweisung an eine Variable (vgl. Abschnitt 9.4) | ||
- | * Aufruf | ||
- | * Verwendung als Funktionsparameter | ||
- | |||
- | == Datentyp class == | ||
- | Der Datentyp class repräsentiert eine innerhalb des Programmes verfügbare Klasse (vgl. [[software: | ||
- | Zulässige Operationen für den Datentyp class sind:\\ | ||
- | * Aufruf in der Klasse definierter statischer Funktionen | ||
- | * Verwendung als Funktionsparameter in den RTTI-Funktionen (siehe Abschnitt 11.2) | ||
- | * Verwendung als Vorlage für die Bildung von Objektinstanzen mit dem Operator new | ||
- | |||
- | == Datentyp object == | ||
- | Der Datentyp object repräsentiert konkrete Instanzen einer Klasse (vgl. [[software: | ||
- | Zulässige Operationen für den Datentyp object sind:\\ | ||
- | * Aufruf von Member-Funktionen | ||
- | * Zuweisung an eine Variable | ||
- | * Verwendung als Funktionsparameter | ||
- | |||
- | |||
- | ===== 7. Operatoren ===== | ||
- | |||
- | Das Konzept der Operatoren in BOB+ (und auch BOB) entspricht weitgehend dem von C. Dieser Abschnitt beschränkt sich daher auf eine kurze Referenz der in BOB+ verfügbaren Operatoren und vorhandener Unterschiede zu C. Für Klassen (bzw. Objekte) können einige der Operatoren neu bzw. umdefiniert werden – siehe hierzu [[software: | ||
- | |||
- | |||
- | |||
- | ==== 7.1 Arithmetische Operatoren ==== | ||
- | Die arithmetischen Operatoren realisieren in Verbindung mit numerischen Operanden (Datentypen int und float) die vier Grundrechenarten. Der Additionsoperator ist darüber hinaus auch auf Zeichenketten (Datentyp string) anwendbar. In diesem Fall dient er als Verkettungsoperator.\\ | ||
- | BOB+ kennt folgende arithmetischen Operatoren: | ||
- | |||
- | ^Operator ^Bedeutung ^Beispiel^ | ||
- | | + (unär) | ||
- | | - (unär) | ||
- | | * | ||
- | | / | ||
- | | % | ||
- | | + | ||
- | | - | ||
- | Tabelle 2 Arithmetische Operatoren in BOB+ | ||
- | |||
- | Hinweise: | ||
- | * Das Verhalten des Divisionsoperators hängt von den Datentypen der Operanden ab. Haben beide Operanden den Typ //int//, so wird eine ganzzahlige Division durchgeführt, | ||
- | * Der Modulo-Operator kann nur auf Operanden des Typs //int// angewendet werden. | ||
- | * Ist ein Operand des Additionsoperators (+) vom Typ //string//, so wirkt der Operator als Verkettungsoperator. Der andere Operand muss dann entweder auch vom Typ //string// oder vom Typ //int// sein. Im letztgenannten Fall wird das niederwertigste Byte des // | ||
- | |||
- | |||
- | ==== 7.2 Vergleichsoperatoren ==== | ||
- | Die Vergleichsoperatoren – auch als relationale Operatoren bezeichnet – dienen dem Größenvergleich ihrer (stets zwei) Operanden. | ||
- | |||
- | BOB+ kennt folgende Vergleichsoperatoren: | ||
- | |||
- | ^Operator ^Bedeutung ^Beispiel^ | ||
- | | == | gleich | ||
- | | != | ungleich | ||
- | | > | größer als | a > b | | ||
- | | >= | größer oder gleich | ||
- | | < | kleiner als | a < b | | ||
- | | < = | kleiner oder gleich | ||
- | Tabelle 3 Vergleichsoperatoren in BOB+ | ||
- | |||
- | Hinweise: | ||
- | * Ist ein Operand vom Typ //int// und der andere vom Typ //float//, so wird der // | ||
- | * Ist einer der Operanden numerisch (//int// oder //float//), so muss auch der andere Operand numerisch sein. | ||
- | * Zeichenketten (// | ||
- | * Werte aller anderen Referenztypen können mit Werten des selben Typs oder mit //null// verglichen werden. Sind beide Operanden vom Referenztyp, | ||
- | * Werte des Typs //null// sind kleiner als alle anderen Werte. | ||
- | |||
- | |||
- | |||
- | ==== 7.3 Logische Operatoren ==== | ||
- | Die logischen Operatoren verknüpfen Wahrheitswerte miteinander. BOB+ besitzt keinen eigenen Datentyp für Wahrheitswerte, | ||
- | * Werte vom Typ //null// haben den Wahrheitswert //false//. | ||
- | * Numerische Werte haben den Wahrheitswert //false//, wenn ihr Betrag 0 ist, sonst //true//. | ||
- | * Alle anderen Werte haben den Wahrheitswert //true//. | ||
- | |||
- | Folgende logische Operatoren sind in BOB+ definiert: | ||
- | ^Operator ^Bedeutung ^Beispiel^ | ||
- | | ! | NOT | !a | | ||
- | | && | ||
- | | ║ | OR | a ║ b | | ||
- | Tabelle 4 Logische Operatoren in BOB+ | ||
- | |||
- | Hinweise: | ||
- | * Der Operator ! liefert als Resultat 1 für //true// und 0 für //false//. | ||
- | * Ausdrücke mit den binären Operatoren ''&&'' | ||
- | |||
- | |||
- | |||
- | ==== 7.4 Bitoperatoren ==== | ||
- | Die Bitoperatoren sind nur auf Operanden des Typs //int// anwendbar. Sie realisieren Operationen auf den einzelnen Bits der Operanden.\\ | ||
- | Folgende Bitoperatoren sind in BOB+ definiert: | ||
- | |||
- | ^Operator ^Bedeutung ^Beispiel^ | ||
- | | ~ | bitweises NOT | ~a | | ||
- | | & | bitweises AND | a & b | | ||
- | | %%|%% | bitweises OR | a %%|%% b | | ||
- | | %%^%% | bitweises XOR | a %%^%% b | | ||
- | | %%<< | ||
- | | %%>> | ||
- | Tabelle 5 Bitoperatoren in BOB+ | ||
- | |||
- | |||
- | |||
- | ==== 7.5 Zuweisungsoperatoren ==== | ||
- | Die Zuweisungsoperatoren dienen der Zuweisung eines Wertes an eine Variable. Wie in C/C++ wird die Zuweisung mit dem Operator = realisiert, der mit einigen arithmetischen Operatoren kombiniert werden kann. Nachfolgende Tabelle zeigt die Möglichkeiten: | ||
- | |||
- | ^Operator ^Bedeutung ^Beispiel^ | ||
- | | = | einfache Zuweisung | ||
- | | += | Zuweisung mit Addition | ||
- | | -= | Zuweisung mit Subtraktion | ||
- | | *= | Zuweisung mit Multiplikation | ||
- | | /= | Zuweisung mit Division | ||
- | | %= | Zuweisung mit Divisionsrest ((Nur in BOB+ definiert.)) | ||
- | Tabelle 6 Zuweisungsoperatoren in BOB+ | ||
- | |||
- | Hinweise: | ||
- | * Der einfache Zuweisungsoperator ist mit allen Datentypen verwendbar. Bitte beachten Sie, dass bei der Zuweisung von Werten der Referenztypen keine Kopie des Wertes sondern lediglich ein Verweis darauf zugewiesen wird. | ||
- | * Die zusammengesetzten Zuweisungsoperatoren sind Kombinationen aus dem einfachen Zuweisungsoperator und einem arithmetischen Operator (vgl. [[software: | ||
- | * Für die Operanden der zusammengesetzten Zuweisungsoperatoren gelten die gleichen Regeln wie für die der entsprechenden arithmetischen Operatoren. | ||
- | |||
- | |||
- | |||
- | ==== 7.6 Inkrement- und Dekrement-Operatoren ==== | ||
- | Die Inkrement- und Dekrement-Operatoren sind unär. Sie erhöhen (Operator ++) bzw. erniedrigen (Operator %%--%%) ihren Operanden jeweils um den Wert 1. Der Operand muss dabei eine mit dem Datentyp int initialisierte Variable sein. | ||
- | |||
- | Beide Operatoren können in Präfix- oder Postfix-Notation verwendet werden. Ein Unterschied zwischen diesen Notationen besteht bei der Verwendung innerhalb von zusammengesetzten Ausdrücken. Bei der Präfix-Notation ist der Wert des Teilausdrucks gleich dem Wert des Operanden nach dem Inkrement/ | ||
- | |||
- | Nachfolgende Tabelle soll die Varianten veranschaulichen: | ||
- | ^Operator ^Bedeutung ^Beispiel ^Entsprechung^ | ||
- | | ++x | Inkrement (Präfix) | ||
- | | x++ | Inkrement (Postfix) | ||
- | | %%--%%x | ||
- | | x%%--%% | ||
- | Tabelle 7 Inkrement und Dekrement | ||
- | |||
- | Hinweise: | ||
- | * Die Inkrement- bzw. Dekrement-Operatoren erzeugen kürzeren und schnelleren Bytecode als ihre „ausgeschriebenen“ Entsprechungen (siehe Tabelle 7). Sie sind deshalb besonders für die Modifikation von Zählvariablen in Schleifen (vgl. [[software: | ||
- | * In zusammengesetzten Ausdrücken sollten diese Operatoren mit Vorsicht und nur dann verwendet werden, wenn die etwas höhere Effizienz wirklich notwendig ist, da neben der schlechteren Lesbarkeit u.U. unerwünschte Seiteneffekte auftreten können. So wird beispielsweise in einem Ausdruck '' | ||
- | |||
- | |||
- | ==== 7.7 Sonstige Operatoren ==== | ||
- | |||
- | |||
- | === Zugriffsoperator === | ||
- | Der Zugriffsoperator wird durch eckige Klammern [] ausgedrückt. Er dient dem indexbasierten Zugriff auf einzelne Elemente eines Vektors oder einer Zeichenkette. | ||
- | |||
- | Beispiel: | ||
- | <code cpp> | ||
- | /* operator [] example */ | ||
- | main() | ||
- | { | ||
- | vec = T(1, | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | Der Operator ist in seiner vordefinierten Form nur auf Variablen der Typen //vector// und //string// anwendbar. Der Operand in der Klammer muss vom Typ int sein. | ||
- | |||
- | |||
- | |||
- | |||
- | === Klammern === | ||
- | Runde Klammern zählen ebenfalls zu den Operatoren. Sie werden in zwei Zusammenhängen verwendet: | ||
- | * als Begrenzung der Argumentliste von Funktionen bei der Deklaration und beim Aufruf\\ '' | ||
- | * zur Steuerung der Auswertungsreihenfolge von Ausdrücken – „Klammern rechnen wir zuerst aus!“\\ '' | ||
- | |||
- | |||
- | === Bedingungsoperator === | ||
- | Der Bedingungsoperator hat die allgemeine Form '' | ||
- | Dabei wird zunächst der Ausdruck // | ||
- | Beispiel:\\ | ||
- | <code cpp> | ||
- | /* get minimum */ | ||
- | min(a, b) | ||
- | { | ||
- | | ||
- | } | ||
- | </ | ||
- | |||
- | Hinweis:\\ | ||
- | Der Typ des Rückgabewerts der Funktion in obigem Beispiel ist nicht unbedingt bekannt. Ist beispielsweise a vom Typ //int// und b vom Typ //float//, so wird der Bedingungsausdruck ('' | ||
- | |||
- | |||
- | === Komma-Operator === | ||
- | Der Komma-Operator gestattet die Verkettung von mehreren Ausdrücken zu einer Ausdrucksliste. Anders ausgedrückt: | ||
- | |||
- | Hinweis:\\ | ||
- | Der // | ||
- | |||
- | |||
- | === Operatoren new, delete, :: und -> === | ||
- | Diese Operatoren haben nur im Zusammenhang mit Klassen und Objekten Bedeutung. Sie werden in den Abschnitten [[software: | ||
- | |||
- | ^Operator ^Bedeutung ^Beispiel^ | ||
- | | new | Objektinstanz aus Klasse erzeugen | ||
- | | delete ((nur in BOB+ verfügbar)) | ||
- | | :: | Definition von Methoden, | ||
- | | %%-> | ||
- | Tabelle 8 Objektbezogene Operatoren in BOB+ | ||
- | |||
- | |||
- | ==== 7.8 Hierarchie der Operatoren ==== | ||
- | Werden mehrere Operatoren innerhalb eines Ausdrucks verwendet, so ergibt sich die Frage nach der Reihenfolge ihrer Auswertung. Um eine solche Reihenfolge festlegen zu können, wird eine Rangfolge (Hierarchie) der Operatoren definiert. BOB/BOB+ hält sich dabei weitgehend an die Regeln von C/C++. In Tabelle 9 ist die Hierarchie der Operatoren in BOB+ aufgeführt. Dabei werden Operatoren höherer Priorität vor jenen niederer Priorität ausgewertet. Bei Operatoren der gleichen Prioritätsstufe erfolgt die Auswertung von links nach recht entsprechend der Notation.\\ | ||
- | |||
- | ^ Priorität | ||
- | | 0 | '','' | ||
- | | 1 | '' | ||
- | | 2 | ''?:'' | ||
- | | 3 | '' | ||
- | | 4 | ''&&'' | ||
- | | 5 | '' | ||
- | | 6 | '' | ||
- | | 7 | ''&'' | ||
- | | 8 | '' | ||
- | | 9 | '' | ||
- | | 10 | '' | ||
- | | 11 | '' | ||
- | | 12 | '' | ||
- | | 13 | '' | ||
- | | 14 | '' | ||
- | Tabelle 9 Operatorhierarchie in BOB+ | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | ===== 8. Schlüsselwörter und reservierte Bezeichner ===== | ||
- | Schlüsselwörter sind im syntaktischen Sinne Terminalsymbole. Das bedeutet, dass sie bereits bei der syntaktischen Analyse identifiziert und speziellen internen Symbolen zugeordnet werden.\\ | ||
- | Innerhalb eines Programms ist den Schlüsselwörtern eine feste (zentrale) Bedeutung zugeordnet. Deshalb können keine benutzerdefinierten Bezeichner definiert werden die den Schlüsselwörtern entsprechen. | ||
- | |||
- | Die Schlüsselwörter in BOB/BOB+ sind im wesentlichen eine Teilmenge der aus C/C++ bekannten. Nachfolgende Tabelle gibt eine Übersicht. Die darin mit (*) gekennzeichneten Schlüsselwörter sind nur in BOB+ definiert, die mit ( < | ||
- | |||
- | ^Schlüsselwort ^Kategorie ^Bedeutung^ | ||
- | | null (*) | Typkonstante | ||
- | | nil (*) | Typkonstante | ||
- | | do | Steuerung | ||
- | | while | Steuerung | ||
- | | for | Steuerung | ||
- | | break | Steuerung | ||
- | | continue | ||
- | | if | Steuerung | ||
- | | else | Steuerung | ||
- | | return | ||
- | | class | OOP | Beginn einer Klassendeklaration | ||
- | | static | ||
- | | new | OOP | Erzeugen einer Objektinstanz | ||
- | | delete (*) | OOP | Zerstören einer Objektinstanz | ||
- | | TRON ( a ) | Debugging | ||
- | | TROFF ( a ) | Debugging | ||
- | | TRSTEP ( a ) | Debugging | ||
- | Tabelle 10 Schlüsselwörter in BOB+\\ | ||
- | |||
- | Die mit Version Bob+ 1.1a eingeführten Schlüsselwörter zum Debugging gehören streng genommen nicht zur Sprache sondern dienen lediglich zur Unterstützung bei der Fehlersuche. Aus Sicht des Compilers werden sie jedoch wie alle anderen Schlüsselwörter behandelt und innerhalb des BOB+-Quelltextes wie eigenständige Anweisungen gebraucht (d.h. insbesondere, | ||
- | |||
- | In den vollständigen Varianten von BOB+ 1.1a (bp bzw. bpi) dienen sie der Erleichterung des Aufspürens von Fehlern während der Programmentwicklung.\\ | ||
- | Die Anweisungen '' | ||
- | Die Anweisung '' | ||
- | |||
- | Im Zusammenhang mit der objektorientierten Programmierung kennt BOB+ noch folgende | ||
- | reservierte Bezeichner (mitunter auch //“magic names”// genannt): | ||
- | * this Verweis auf das aktuelle Objekt in Member-Funktionen ((auch in BOB)) | ||
- | * dtor Alias-Bezeichner für den Destruktor einer Klasse (siehe [[software: | ||
- | * OP_CALL, OP_VREF, OP_VSET, OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_REM, OP_BOR, OP_BAND, OP_XOR, OP_SHL, OP_SHR spezielle Funktionsnamen zur Definition von Operatoren (siehe [[software: | ||
- | |||
- | Die reservierten Bezeichner sind //keine Schlüsselwörter// | ||
- | |||
- | |||
- | ===== 9. Steuerstrukturen ===== | ||
- | Für jedes Programm, das aus mehr als einer bloßen Aneinanderreihung von Befehlen bestehen soll, werden Möglichkeiten zur Steuerung des Programmablaufs benötigt. Grundsätzlich unterscheidet man hier zwischen // | ||
- | Viele Programmiersprachen erlauben zudem noch unbedingte Sprunganweisungen. Solche Anweisungen sind in BOB/BOB+ nicht vorgesehen ((Sie sind auch in keinem BOB+-Programm zwingend erforderlich.)) und werden deshalb nicht weiter behandelt.\\ | ||
- | |||
- | |||
- | ==== 9.1 Bedingungen ==== | ||
- | Zur Steuerung der Programmabarbeitung in Abhängigkeit von einer Bedingung dient die // | ||
- | if ( bedingung ) anweisung1 [ else anweisung2 ] . | ||
- | Ergibt der Ausdruck bedingung den Wahrheitswert //true//, so wird // | ||
- | |||
- | Beispiel:\\ | ||
- | <code cpp> | ||
- | main(;fp) | ||
- | { | ||
- | fp = fopen(“testfile.txt“, | ||
- | if (fp) // same as fp != null | ||
- | { | ||
- | // do anything | ||
- | fclose(fp); | ||
- | } | ||
- | else | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | |||
- | ==== 9.2 Wiederholungen (Schleifen) ==== | ||
- | Für die Formulierung von Wiederholungen von Codeabschnitten kennt BOB/BOB+ die Anweisungen //while//, // | ||
- | |||
- | |||
- | === 9.2.1 Die while-Anweisung === | ||
- | Die while-Anweisung hat die allgemeine Form\\ | ||
- | while ( bedingung ) anweisung | ||
- | Dabei wird // | ||
- | |||
- | Beispiel:\\ | ||
- | <code cpp> | ||
- | /* type contents of file to console */ | ||
- | main(;fp,s) | ||
- | { | ||
- | fp = fopen(“testfile.txt“, | ||
- | if (fp) // same as fp != null | ||
- | { | ||
- | while(!feof(fp)) | ||
- | { | ||
- | s = fgets(fp); | ||
- | print(s); | ||
- | free(s); | ||
- | } | ||
- | fclose(fp); | ||
- | } | ||
- | else | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | |||
- | === 9.2.2 Die do-while-Anweisung === | ||
- | Die do-while-Anweisung hat die allgemeine Form\\ | ||
- | do anweisung while ( bedingung ) | ||
- | Sie ist der while-Anweisung sehr ähnlich. Auch hier wird // | ||
- | |||
- | Beispiel:\\ | ||
- | <code cpp> | ||
- | /* prompt user for input until empty line was entered */ | ||
- | main(;s) | ||
- | { | ||
- | s = null; | ||
- | do | ||
- | { | ||
- | if (s != null) free(s); | ||
- | print(“enter line: “); | ||
- | s = gets(); | ||
- | // do anything | ||
- | } | ||
- | while (strlen(s) > 0); | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | |||
- | === 9.2.3 Die for-Anweisung === | ||
- | Die for-Anweisung ist die mächtigste Form der Formulierung einer Wiederholung. Wie in C/C++ (und im Gegensatz zu Sprachen wie BASIC oder PASCAL) dient sie nicht zwingend der Abarbeitung einer festgelegten Anzahl von Schleifendurchläufen sondern ist eher eine Verallgemeinerung bzw. Erweiterung der // | ||
- | for ( init ; bedingung ; reinit) anweisung | ||
- | Vor dem Beginn der Abarbeitung einer for-Schleife wird zunächst einmalig die Initialisierungsanweisung // | ||
- | |||
- | Beispiel:\\ | ||
- | <code cpp> | ||
- | /* list all arguments of commandline to console */ | ||
- | main(; | ||
- | { | ||
- | | ||
- | n = vecsize(argvec); | ||
- | | ||
- | print(argvec[i]," | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | |||
- | === 9.2.4 Geschachtelte Schleifen === | ||
- | Schleifen können ineinander geschachtelt werden. Ein typischer Fall für die Anwendung geschachtelter Schleifen ist das Füllen eines mehrdimensionalen Feldes, wie in nachfolgendem Beispiel gezeigt:\\ | ||
- | |||
- | <code cpp> | ||
- | /* create and fill a 2-dim array */ | ||
- | main() | ||
- | { | ||
- | rows = 8; | ||
- | cols = 8; | ||
- | /* create a table */ | ||
- | array = newvector(rows); | ||
- | for (i=0; i<rows; i++) array[i] = newvector(cols); | ||
- | /* intialize table */ | ||
- | for (i=0; i<rows; i++) | ||
- | for (j=0; j<cols; j++) | ||
- | | ||
- | // do anything | ||
- | // ... | ||
- | /* free array */ | ||
- | for (i=0; i<rows; i++) free(array[i]); | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | Die maximale Schachtelungstiefe ist dabei in BOB+ auf 20, in BOB auf 10 Ebenen begrenzt.\\ | ||
- | |||
- | |||
- | === 9.2.5 break und continue === | ||
- | Die Anweisungen //break// und // | ||
- | |||
- | Beispiel: | ||
- | <code cpp> | ||
- | /* write all printable characters of testfile.txt to console */ | ||
- | main() | ||
- | { | ||
- | fp = fopen(“testfile.txt“, | ||
- | if (!fp) | ||
- | { | ||
- | print(“error opening file\n“); | ||
- | return 1; | ||
- | } | ||
- | | ||
- | { | ||
- | if (feof(fp)) | ||
- | | ||
- | c = getc(fp); | ||
- | if ((c<‘ ‘) && (c != ‘\n‘)) | ||
- | | ||
- | putc(c, | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | |||
- | ===== 10. Funktionen ===== | ||
- | Wie bereits in [[software: | ||
- | |||
- | |||
- | ==== 10.1 Funktionsdeklaration ==== | ||
- | Eine benutzerdefinierte Funktion hat die allgemeine Form\\ | ||
- | | ||
- | Dabei ist // | ||
- | |||
- | Benannte Parameter werden innerhalb des Funktionsrumpfes wie lokale Variablen behandelt. Alle Variablen, die innerhalb des Funktionsrumpfes verwendet werden und nicht in // | ||
- | |||
- | Anders als in C/C++ geben Funktionen in BOB/BOB+ //immer// einen Funktionswert zurück. Wird eine Funktion mit '' | ||
- | |||
- | Beispiele für Funktionsdeklarationen: | ||
- | <code cpp> | ||
- | /* parameterless function without defined return value */ | ||
- | sayHello() | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | /* named parameter, local variables and return value */ | ||
- | factorial(n; | ||
- | { | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | /* no named parameters but local variable and return value */ | ||
- | queryName(; | ||
- | { | ||
- | name =““; | ||
- | while (strlen(name) == 0) | ||
- | { | ||
- | print(“Tell me your name: “); | ||
- | name = fgets(stdin); | ||
- | } | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | |||
- | |||
- | ==== 10.2 Aufruf von Funktionen ==== | ||
- | Der Aufruf einer Funktion erfolgt durch Nennung des Funktionsnamens, | ||
- | |||
- | Beispiel:\\ | ||
- | <code cpp> | ||
- | main() | ||
- | { | ||
- | | ||
- | f = factorial(17); | ||
- | g = sqrt(2.0) * 0.5; // use function in expression | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | Hinweis:\\ | ||
- | Beim Aufruf einer Funktion müssen mindestens so viele Parameter angegeben werden, wie in der Funktionsdeklaration angegeben. Werden mehr Parameter angegeben, so werden den benannten Parameternamen die letzten (d.h. am weitesten rechts stehenden) Parameterwerte zugewiesen. Wie C/C++ unterstützt BOB/BOB++ den rekursiven Aufruf von Funktionen.\\ | ||
- | |||
- | Beispiel:\\ | ||
- | <code cpp> | ||
- | factorial(n) | ||
- | { | ||
- | if (n > 1) | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | Die mögliche Rekursionstiefe wird dabei durch die Größe des Stacks begrenzt. Für einen Funktionsaufruf werden mindestens vier Stack-Einträge benötigt. Hinzu kommt jeweils ein Eintrag für jeden übergebenen Parameter und jede lokale Variable. Demnach berechnet sich die maximale Rekursionstiefe (Rmax) wie folgt:\\ | ||
- | Rmax = Stackgröße / (Parameterzahl + Anzahl lokaler Variablen + 4) | ||
- | |||
- | In BOB+ (nicht in BOB) besteht die Möglichkeit, | ||
- | |||
- | |||
- | |||
- | |||
- | ==== 10.3 Variable Parameterlisten ==== | ||
- | Wie im vorigen Abschnitt erwähnt, ist es möglich, einer Funktion beim Aufruf mehr Parameter zu übergeben als in der Deklaration angegeben. BOB+ erlaubt unter Ausnutzung dieser Eigenschaft die Konstruktion von Funktionen mit einer beliebigen Anzahl von Parametern. Für den Zugriff auf die übergebenen Parameter wird dann an Stelle von Parameternamen die vordefinierte Funktion //arg// verwendet. Die Bestimmung der Parameteranzahl erfolgt mit //argcnt// (siehe [[software: | ||
- | |||
- | Beispiel: | ||
- | <code cpp> | ||
- | sum(; | ||
- | { | ||
- | result = 0; | ||
- | for (i=0; i< | ||
- | result += arg(i); | ||
- | return result; | ||
- | } | ||
- | |||
- | main() | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | |||
- | ==== 10.4 Funktionszeiger ==== | ||
- | In [[software: | ||
- | |||
- | Beispiel:\\ | ||
- | <code cpp> | ||
- | myFunc() | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | main(;f) | ||
- | { | ||
- | f = myFunc; | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | Hinweis:\\ | ||
- | In BOB+ haben Funktionszeiger neben der Verwendbarkeit als Argumente anderer Funktionen oder Funktionsvariablen ein weiteres Einsatzgebiet: | ||
- | Lokale Variablen einer Funktion werden dagegen in einem per Index adressieren Datenfeld verwaltet((Das gilt auch für Member-Variablen einer Klasse.)). Deshalb ist es zweckmäßig, | ||
- | |||
- | |||
- | ==== 10.5 Überladen von Funktionen ==== | ||
- | BOB/BOB+ identifiziert eine Funktion ausschließlich anhand ihres Namens und nicht (wie z.B. C++) anhand der vollständigen Signatur. Damit ist ein Überladen (d.h. die Definition mehrerer Funktionen gleichen Namens) im eigentlichen Sinne nicht möglich. Die Neudefinition einer bereits vorhandenen Funktion führt zwar nicht zu einem Fehler, ersetzt die vorher definierte gleichnamige Funktion aber vollständig. | ||
- | |||
- | Unter Ausnutzung der in den vorangegangenen Abschnitten beschriebenen variablen Parameterlisten und Funktionszeiger ist in BOB+ jedoch ein Pseudo-Überladen möglich.\\ | ||
- | Betrachten wir dazu nachfolgendes Beispiel:\\ | ||
- | |||
- | <code cpp> | ||
- | myFunc(i) | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | myFunc2() | ||
- | { | ||
- | if (argcnt() != 2) | ||
- | myFunc1(arg(0)); | ||
- | else | ||
- | print(" | ||
- | } | ||
- | |||
- | |||
- | main() | ||
- | { | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | Ziel ist es hier, zwei Funktionen zu definieren, die beide über den Namen '' | ||
- | Zuerst wird unter dem Namen //myFunc// die Variante mit einem Parameter definiert. Die Variante für zwei Parameter erhält zunächst einen anderen Namen (// | ||
- | Die Funktion main weist nun der (globalen) Variablen //myFunc1// den Code von //myFunc// und //myFunc// den Code von //myFunc2// zu.\\ | ||
- | |||
- | ===== 11. Objektorientierte Programmierung ===== | ||
- | Das Konzept der Objektorientierung in BOB/BOB++ ist trotz syntaktischer Ähnlichkeit wesentlich einfacher als das von C++. Dennoch werden die grundlegenden Paradigmen objektorientierter Programmierung – Datenkapselung (zumindest ansatzweise), | ||
- | |||
- | ==== 11.1 Aufbau einer Klasse ==== | ||
- | Zur Erläuterung des Aufbaus einer Klasse in BOB/BOB+ soll nachfolgendes Beispiel dienen. Es stellt den Anfang einer fiktiven Klassenbibliothek mit der Wurzel MyBaseClass und einer davon abgeleiteten Klasse MyDerivedClass dar. Alle Objektinstanzen dieser Bibliothek sollen einen eindeutigen Identifikator (_ID) haben, dessen Vergabe die einzige Aufgabe der Basisklasse ist.\\ | ||
- | |||
- | <code cpp> | ||
- | // declaration of MyBaseClass | ||
- | class MyBaseClass | ||
- | { | ||
- | | ||
- | | ||
- | _ID; | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | // implementation of MyBaseClass | ||
- | MyBaseClass:: | ||
- | MyBaseClass:: | ||
- | MyBaseClass:: | ||
- | |||
- | // declaration of MyDerivedClass | ||
- | class MyDerivedClass : MyBaseClass | ||
- | { | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | // implementation of MyDerivedClass | ||
- | MyDerivedClass:: | ||
- | { | ||
- | | ||
- | _name = name; | ||
- | | ||
- | // following line is needed for BOB (but not BOB+) | ||
- | // return this; | ||
- | } | ||
- | MyDerivedClass:: | ||
- | MyDerivedClass:: | ||
- | MyDerivedClass:: | ||
- | MyDerivedClass:: | ||
- | |||
- | </ | ||
- | |||
- | Die Klassendeklarationen wie auch die Implementierungen ähneln auf den ersten Blick dem von C++ gewohnten. Allerdings gibt es eine Reihe von wichtigen Unterschieden: | ||
- | |||
- | === Keine Zugriffsspezifizierer === | ||
- | In BOB/BOB+ sind Member- und Klassenfunktionen sowie Klassenvariablen (static) implizit öffentlich (public im Sinne von C++).\\ | ||
- | Member-Variablen sind implizit geschützt (protected im Sinne von C++), also nur in der deklarierenden Klasse und ihren Ableitungen sichtbar. Für den Zugriff von außen müssen entsprechende Zugriffsmethoden implementiert werden.\\ | ||
- | |||
- | === Keine Mehrfachvererbung === | ||
- | Anders als in C++ hat eine BOB/ | ||
- | |||
- | |||
- | === Deklaration von Variablen und Methoden === | ||
- | In BOB/ | ||
- | |||
- | <code cpp> | ||
- | MyDerivedClass : MyBaseClass | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | Diese Eigenschaft erlaubt es, Klassen bei Bedarf nachträglich um Methoden zu ergänzen (siehe hierzu auch [[software: | ||
- | |||
- | Member-Variablen und alle statischen Elemente //müssen// deklariert werden. | ||
- | |||
- | Steht der static-Modifizierer vor einer kommaseparierten Variablenliste, | ||
- | |||
- | |||
- | === Eingeschränkte Initialisierung von Klassenvariablen === | ||
- | In BOB können Klassenvariablen nicht explizit initialisiert werden((Sie erhalten hier implizit den Wert nil.)). In BOB+ ist dies möglich, jedoch erfolgt die Initialisierung bereits zur Kompilier- und nicht erst zur Laufzeit. Deshalb sind zur Initialisierung nur Literale (und keine Funktionsaufrufe) verwendbar. Die Initialisierung muss stets innerhalb der Klassendeklaration notiert werden (siehe _maxID in MyBaseClass).\\ | ||
- | |||
- | |||
- | === Objekte werden immer dynamisch erzeugt === | ||
- | Alle Instanzen von Klassen (Objekte) haben den internen Typ object und sind damit Referenztypen (siehe [[software: | ||
- | <code cpp> | ||
- | myObj = new MyDerivedClass(“anumber“, | ||
- | </ | ||
- | Deshalb ist es nicht möglich, wie in C++ direkt im Anschluss an eine Klassendeklaration Variablen dieses Typs anzulegen, was auch erklärt, weshalb hinter der schließenden Klammer der Klassendeklaration kein Semikolon steht.\\ | ||
- | |||
- | |||
- | |||
- | |||
- | ==== 11.2 Konstruktoren und Destruktoren ==== | ||
- | Ein // | ||
- | In BOB/BOB+ hat ein Konstruktor – wie in C++ – den selben Namen wie die Klasse selbst. Da ein Überladen von Funktionen im eigentlichen Sinne nicht möglich ist (siehe [[software: | ||
- | <code cpp> | ||
- | return this; | ||
- | </ | ||
- | verlassen werden muss. Der Compiler von BOB+ fügt den entsprechenden Bytecode automatisch an das Ende jeder Konstruktorfunktion an, so dass die Anweisung hier nur dann notiert werden muss, wenn die Funktion vorzeitig (auf Grund einer Abruchbedingung) verlassen wird. Anders als z.B. in C++ ruft ein Konstruktor in BOB/BOB++ nicht automatisch auch den Konstruktor einer ggf. vorhandenen Basisklasse auf. Ein solcher Aufruf muss explizit kodiert werden. Ein Beispiel zur Verdeutlichung: | ||
- | <code cpp> | ||
- | class Base | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | Base:: | ||
- | { | ||
- | | ||
- | // return this; // uncomment when using BOB | ||
- | } | ||
- | |||
- | class Derived : Base | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | Derived:: | ||
- | { | ||
- | | ||
- | | ||
- | // return this; // uncomment when using BOB | ||
- | } | ||
- | |||
- | main() | ||
- | { | ||
- | obj = new Derived(); | ||
- | // do anything | ||
- | obj = delete obj; // comment out when using BOB | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | Anmerkungen: | ||
- | * Ein Konstruktor lässt sich in BOB/BOB+ bei Bedarf auch wie eine „normale“ Member-Funktion aufrufen. | ||
- | * Von einer Klasse, die keinen eigenen Konstruktor besitzt, können keine Instanzen erzeugt werden. Diese Eigenschaft lässt sich zur Definition // | ||
- | |||
- | Ein // | ||
- | |||
- | BOB hat keine Möglichkeit, | ||
- | * Ein Destruktor wird als parameterlose Member-Funktion deklariert, die den Klassennamen mit vorangestellter Tilde (~) trägt. | ||
- | * Der Destruktor wird unmittelbar vor der Zerstörung des Objekts automatisch aufgerufen, d.h. innerhalb des Destruktors sind alle Elemente (einschließlich des // | ||
- | * Am Ende der Destruktorfunktion werden rekursiv auch die Destruktoren aller Basisklassen aufgerufen, d.h. der Destruktorcode der abgeleiteten Klasse wird immer vor dem der Basisklasse ausgeführt. Klassen ohne Destruktor werden dabei innerhalb der Klassenhierarchie übersprungen. | ||
- | |||
- | Zur Verdeutlichung erweitern wir obiges Beispiel: | ||
- | <code cpp> | ||
- | class Base | ||
- | { | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | Base:: | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | Base:: | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | Base:: | ||
- | |||
- | class Derived : Base | ||
- | { | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | Derived:: | ||
- | { | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | Derived:: | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | Derived:: | ||
- | main() | ||
- | { | ||
- | obj = new Derived(); | ||
- | // do anything | ||
- | obj = delete obj; | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | Anmerkungen: | ||
- | * Der Operator delete gibt in BOB+ immer **null** zurück. Er kann deshalb – wie hier in der Funktion //main// – als rechter Ausdruck einer Zuweisung verwendet werden, um die freigegebene Variable als ungültig zu markieren. | ||
- | * Implementierungsbedingt bildet BOB+ den Destruktor auf eine Member-Funktion mit dem reservierten Bezeichner // | ||
- | |||
- | |||
- | |||
- | ==== 11.3 Zugriff auf Member-Funktionen und -Variablen innerhalb einer Klasse ==== | ||
- | Enthält die Implementierung einer Memberfunktion Funktionsaufrufe oder Variablenzugriffe, | ||
- | aktuellen Klasse und ggf. deren Basisklassen nach einem passenden Member gesucht. Verläuft die Suche ergebnislos, | ||
- | so wird der jeweilige Funktions- oder Variablenbezeichner als globaler Bezeichner angenommen. Wird vor dem Bezeichner das Schlüsselwort **this** mit nachfolgendem Dereferenzierungsoperator (%%->%%) angegeben, so wird der | ||
- | Bezeichner nur im jeweiligen Objekt gesucht. | ||
- | |||
- | Für statische Member ist das Verhalten ähnlich, jedoch wird hier zur Spezifikation einer konkreten Klasse vor dem | ||
- | eigentlichen Bezeichner der Klassenname und der Bereichsauflösungsoperator (::) angegeben. | ||
- | |||
- | In diesem Zusammenhang entsteht das Problem, dass unter Umständen in der Implementierung einer Member-Funktion auf ein globales Symbol (Variable oder Funktion) zugegriffen werden muss, dass namensgleich mit einem Element der | ||
- | aktuellen Klasse ist. BOB bietet dafür keine Lösung, d.h., der Programmierer muss dafür sorgen, dass solche | ||
- | Situationen nicht entstehen. In BOB+ kann – wie in C++ – der Zugriff auf die globalen Symbole mit Hilfe des | ||
- | Bbereichsauflösungsoperators erzwungen werden.\\ | ||
- | |||
- | Beispiel: | ||
- | <code cpp> | ||
- | // globally defined function | ||
- | message() { print(“global function message called\n“) }; | ||
- | |||
- | class MyClass | ||
- | { | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | MyClass() {} | ||
- | MyClass:: | ||
- | MyClass:: | ||
- | { | ||
- | | ||
- | | ||
- | // search only in current class | ||
- | :: | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | |||
- | |||
- | |||
- | ==== 11.4 Virtuelle Methoden ==== | ||
- | Da in BOB/BOB+ nicht die Variablen sondern lediglich die Werte einen Typ besitzen, gibt es keine „frühe Bindung“. Das bedeutet, dass alle Methoden einer Klasse – auch die statischen – // | ||
- | |||
- | <code cpp> | ||
- | main() | ||
- | { | ||
- | obj = new Base(); | ||
- | | ||
- | obj = delete obj; | ||
- | obj = new Derived(); | ||
- | | ||
- | obj = delete obj; | ||
- | } | ||
- | |||
- | </ | ||
- | Hier werden ein- und derselben Variablen (obj) nacheinander Instanzen der Klassen Base bzw. Derived zugewiesen und jeweils deren '' | ||
- | |||
- | Häufig kommt es vor, dass eine abgeleitete Klasse eine Methode ihrer Basisklasse mit dem Ziel überschreibt, | ||
- | |||
- | //Um innerhalb der Implementierung einer überschreibenden Methode die geerbte Vorfahrmethode aufzurufen, wird dem Funktionsnamen das Präfix **BC_** (für BaseClass) vorangestellt.// | ||
- | |||
- | Beispiel:< | ||
- | class MyBaseClass | ||
- | { | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | MyBaseClass:: | ||
- | MyBaseClass:: | ||
- | |||
- | MyDerivedClass : MyBaseClass | ||
- | { | ||
- | MyDerivedClass(); | ||
- | writeInfo(); | ||
- | } | ||
- | |||
- | MyDerivedClass:: | ||
- | MyDerivedClass:: | ||
- | { | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | main(;obj) | ||
- | { | ||
- | obj = new MyDerivedClass(); | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | __Hinweise: | ||
- | Der Aufruf der geerbten Vorfahrmethode muss über den // | ||
- | Der Aufruf mit dem // | ||
- | Ab Version 1.1e erkennt der Bytecode-Interpreter solche Situationen, | ||
- | |||
- | ==== 11.5 Partielle Klassen ==== | ||
- | BOB/BOB+ unterstützt partielle Klassen in ähnlicher Form wie C# 2.0. Dabei meint **// | ||
- | * Verteilen umfangreicher Klassen auf mehrere Dateien | ||
- | * Behandlung inhaltlich verschiedener Aspekte einer Klasse in getrennten Abschnitten | ||
- | * Klasseninhalte lassen sich variabel gestalten, d.h. in Abhängigkeit vom jeweiligen Kontext kann eine konkrete Klasse aus unterschiedlichen Teilen zusammengesetzt werden. | ||
- | * Nutzung zur Vorwärtsdeklaration von zur Kompilierzeit eines Moduls unbekannten Klassen | ||
- | * Bestehende Klassen können „nachträglich“ erweitert werden. | ||
- | |||
- | Für das folgende Beispiel nehmen wir an, dass ein Programm eine Klasse '' | ||
- | |||
- | <code cpp> | ||
- | /* doAction example – main module action.bp */ | ||
- | |||
- | class Class1 | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | main(;obj) | ||
- | { | ||
- | obj = new Class1(); | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | Class1 wird hier nur als leerer Prototyp definiert((Die Deklaration von doAction hätte man auch weglassen können.)) – den fordert der Compiler. Eine erste Version der vollständigen Definition und Implementierung erfolgt in einem Modul actcl1_1: | ||
- | |||
- | <code cpp> | ||
- | |||
- | /* first version of Class1 module – actcl1_1.bp */ | ||
- | |||
- | class Class1 | ||
- | { | ||
- | Class1(); | ||
- | ~Class1(); | ||
- | doAction(); | ||
- | _callCnt; | ||
- | } | ||
- | // implementation | ||
- | |||
- | Class1:: | ||
- | Class1:: | ||
- | Class1:: | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | Nun können Hauptprogramm und Modul jeweils in Bytecode übersetzt und anschließend das Hauptprogramm unter Nutzung des Bibliotheksmoduls Bibliothek gestartet werden:\\ | ||
- | bp –c action –o action.bpm | ||
- | bp –c actcl1_1 –o actcl1_1.bpm | ||
- | bp –r action actcl1_1 | ||
- | |||
- | Ohne Änderung am Hauptprogramm können wir jetzt die Klasse Class1 in einem anderen Modul | ||
- | erneut implementieren und alternativ zur obigen Variante verwenden: | ||
- | |||
- | <code cpp> | ||
- | /* second version of Class1 module – actcl1_2.bp */ | ||
- | |||
- | class Class1 | ||
- | { | ||
- | Class1(); | ||
- | ~Class1(); | ||
- | doAction(); | ||
- | } | ||
- | // implementation | ||
- | |||
- | Class1:: | ||
- | Class1:: | ||
- | Class1:: | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | Übersetzung und Aufruf erfolgen analog:\\ | ||
- | bp –c actcl1_2 –o actcl1_2.bpm | ||
- | bp action –r actcl1_2.bpm | ||
- | |||
- | |||
- | Hinweis:\\ | ||
- | Um das Beipiel mit BOB benutzen zu können, müssen die Konstruktor-Implementierungen um die | ||
- | Anweisung '' | ||
- | entfernt werden. Ein Vorkompilieren ist hier nicht möglich.\\ | ||
- | |||
- | |||
- | ==== 11.6 Ersetzen von Member-Funktionen (Redefinition) ==== | ||
- | So, wie man bestehende „normale“ Funktionen durch einfache Neudefinition ersetzen kann (siehe | ||
- | [[software: | ||
- | Variante ersetzt die alte vollständig. Diese Eigenschaft lässt sich zur nachträglichen Änderung des | ||
- | Verhaltens einer Klasse nutzen. Betrachten wir dazu wieder das Beispiel aus dem vorangegangenen | ||
- | Abschnitt. Jetzt wird jedoch die Klasse Class1 sofort implementiert.\\ | ||
- | |||
- | <code cpp> | ||
- | /* doAction example – main module action.bp */ | ||
- | |||
- | class Class1 | ||
- | { | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | Class1:: | ||
- | Class1:: | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | main(;obj) | ||
- | { | ||
- | obj = new Class1(); | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | Das Beispiel sollte in BOB+ direkt lauffähig sein. Nun wollen wir ein Patch-Modul schreiben, das das Verhalten der doAction-Methode aus Class1 ändert:\\ | ||
- | |||
- | <code cpp> | ||
- | /* module patch.bp replaces doAction method of Class1 */ | ||
- | Class1:: | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | Bitte beachten Sie, dass unser Patch-Modul nicht separat übersetzbar ist, da es keine Deklaration | ||
- | von Class1 enthält, folgender Aufruf ist aber möglich:\\ | ||
- | bp action patch | ||
- | Hier wird der Patch nach dem ursprünglichen Programm übersetzt, so dass Class1 bereits | ||
- | vorhanden und der Compiler zufrieden ist.\\ | ||
- | |||
- | |||
- | ==== 11.7 Defineren von Operatoren ==== | ||
- | In BOB+ (nicht in BOB) ist es möglich, einige Operatoren für Objekte (oder genauer: deren | ||
- | Klassen) umzudefinieren bzw. überhaupt zu definieren. Die Möglichkeiten sind in dieser Hinsicht | ||
- | nicht so umfangreich wie bei C++, sollten in vielen Fällen aber dennoch ausreichend sein. | ||
- | |||
- | Generell wird ein Operator indirekt definiert, indem eine Klasse eine Memberfunktion definiert, | ||
- | deren Namen einem der reservierten Bezeichner der Form OP_XXX (siehe [[software: | ||
- | |||
- | |||
- | === 11.7.1 Definieren des Funktionsoperators === | ||
- | Wenn eine Klasse den Funktionsoperator () umdefiniert, | ||
- | Funktionsobjekten (mitunter auch als // | ||
- | Programms wie Funktionen gebraucht werden. | ||
- | |||
- | Der Operator wird mit Hilfe einer Member-Funktion OP_CALL definiert. | ||
- | |||
- | Beispiel: | ||
- | <code cpp> | ||
- | /* operator () example */ | ||
- | class StringWriter | ||
- | { | ||
- | | ||
- | | ||
- | | ||
- | _fp; | ||
- | } | ||
- | |||
- | StringWriter:: | ||
- | { | ||
- | _fp = fopen(file, | ||
- | } | ||
- | |||
- | StringWriter:: | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | StringWriter:: | ||
- | { | ||
- | n = argcnt(); | ||
- | for (i=0; | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | main() | ||
- | { | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | |||
- | === 11.7.2 Definieren des Zugriffsoperators === | ||
- | Der Zugriffsoperator [] dient normalerweise dem indizierten Zugriff auf einzelne Elemente einer | ||
- | Zeichenkette oder eines Vektors. Wird der Operator für Objekte definiert, so sind hierfür zwei | ||
- | Member-Funktionen – eine für den Lesezugriff (OP_VREF) und eine für den Schreibzugriff | ||
- | (OP_VSET) – zu definieren((Wird nur eine der Funktionen implementiert, | ||
- | das Index-Argument nicht zwingend eine Ganzzahl sein. | ||
- | |||
- | Als Beispiel soll ein Fragment einer Klasse Point dienen, die einen n-dimensionalen Punkt | ||
- | repräsentiert. Die Koordinaten sollen mit Hilfe des Zugriffsoperators gelesen und geschrieben | ||
- | werden können. | ||
- | <code cpp> | ||
- | class Point() | ||
- | { | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | Point:: | ||
- | { | ||
- | | ||
- | for (i=0; | ||
- | } | ||
- | Point:: | ||
- | |||
- | Point:: | ||
- | |||
- | Point:: | ||
- | |||
- | main(; | ||
- | { | ||
- | point = new Point(2); | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | |||
- | |||
- | |||
- | === 10.7.3 Weitere Operatoren === | ||
- | Neben dem Funktions- und dem Zugriffsoperator können folgende weitere Operatoren umdefiniert werden:\\ | ||
- | |||
- | |||
- | ^Operator^ Funktionsname^ | ||
- | | Arithmetische Operatoren || | ||
- | | + | OP_ADD | ||
- | | - | OP_SUB | ||
- | | * | OP_MUL | ||
- | | / | OP_DIV | ||
- | | % | OP_REM | ||
- | | Bitweise Operatoren | ||
- | | %%|%% | OP_BOR | ||
- | | & | OP_BAND | ||
- | | %%^%% | OP_XOR | ||
- | | Verschiebeoperatoren | ||
- | | %%<< | ||
- | | %%>> | ||
- | Tabelle 11 Weitere umdefinierbare Operatoren in BOB+ | ||
- | |||
- | |||
- | Das Prinzip ist für alle diese Operatoren gleich und soll hier am Beispiel des Additionsoperators | ||
- | gezeigt werden. Dazu erweitern wir die Klasse Point aus [[software: | ||
- | den Operator + so, dass mit seiner Hilfe ein neuer Punkt erzeugt wird, dessen Koordinaten als | ||
- | Summe der Koordinaten der Operanden gebildet werden. | ||
- | |||
- | <code cpp> | ||
- | class Point | ||
- | { | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | Point:: | ||
- | { | ||
- | _dim = dim; | ||
- | | ||
- | for (i=0; | ||
- | } | ||
- | |||
- | Point:: | ||
- | |||
- | Point:: | ||
- | { | ||
- | n = otherPoint-> | ||
- | if (n > _dim) n = _dim; | ||
- | | ||
- | for (i=0; | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | main(; | ||
- | { | ||
- | p1 = new Point(2); | ||
- | p1[0] = 12; // set x-coordinate | ||
- | p1[1] = 4.7; // set y-coordinate; | ||
- | p2 = new Point(2); | ||
- | p2[0] = 24; // set x-coordinate | ||
- | p2[1] = 14.7; // set y-coordinate; | ||
- | pt = p1 + p2; | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | Hinweis:\\ | ||
- | Bitte beachten Sie, dass der Additionsoperator in diesem Beispiel ein neues Objekt erzeugt, das | ||
- | explizit wieder freigegeben werden sollte. | ||
- | |||
- | ===== 12. Vordefinierte Funktionen ===== | ||
- | Nachfolgend werden die verfügbaren vordefinierten Funktionen im Sinne einer Referenz | ||
- | beschrieben. Die Typen der Parameter und Rückgabewerte werden in den jeweiligen Signaturen mit | ||
- | angegeben.\\ | ||
- | |||
- | ==== 12.1 Speicherverwaltungs- und Testfunktionen ==== | ||
- | Die mit (*) gekennzeichneten Funktionen dieses Abschnitts stehen nur in BOB+ zur Verfügung. | ||
- | |||
- | |||
- | === Funktion free (*): === | ||
- | |||
- | '' | ||
- | Die Funktion gibt den Speicherplatz einer Variablen des Typs String, Vektor oder Objekt frei.\\ | ||
- | |||
- | Parameter: | ||
- | variable: freizugebende Variable\\ | ||
- | |||
- | Rückgabewert: | ||
- | Die Funktion gibt stets den Wert **null** zurück.\\ | ||
- | |||
- | Hinweise:\\ | ||
- | Die Funktion dient der Freigabe des Speicherplatzes von nicht mehr benötigten Variablen | ||
- | der Typen String, Vektor und Objekt. Wird sie auf andere („einfache“) Datentypen | ||
- | angewendet, bleibt sie wirkungslos. | ||
- | |||
- | Achtung: Die versehentliche mehrmalige Anwendung auf ein- und dieselbe Variable kann | ||
- | zum Programmabsturz führen. Deshalb sollte einer freigegebenen Variablen stets explizit | ||
- | der Wert **null** zugewiesen werden (als Funktionsergebnis von // | ||
- | |||
- | Beispiel:\\ | ||
- | |||
- | <code cpp> | ||
- | /* example for using free-function */ | ||
- | main(;text) | ||
- | { | ||
- | text = “This Text “; | ||
- | text += “should be disposed after using.\n“; | ||
- | | ||
- | /* free memory and set variable to null */ | ||
- | text = free(text); | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | |||
- | === Funktion memsize (*): === | ||
- | |||
- | '' | ||
- | Die Funktion prüft die Größe des noch verfügbaren freien Speichers.\\ | ||
- | |||
- | Parameter((nur in BOB+ 1.1)):\\ | ||
- | farmem: legt fest, ob die Größe des freien lokalen (0) oder globalen (!= 0) Speichers bestimmt werden soll | ||
- | |||
- | Rückgabewert: | ||
- | Größe des verfügbaren freien Speichers in Bytes | ||
- | |||
- | Hinweis:\\ | ||
- | In Version 1.1 von BOB+ kann mit dem optionalen Parameter //farmem// festgelegt werden, ob die Größe des für das aktuelle Programm verfügbaren Speichers oder die außerhalb des lokalen Heaps verfügbare Speichergröße bestimmt werden soll. Da BOB+ im Small-Modell übersetzt wurde, sind für den lokalen Heap stets weniger als 64KB verfügbar. Der global verfügbare Speicherplatz ist z.B. vor dem Laden dynamischer Bibliotheken interessant. | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | === Funktion newstring: === | ||
- | |||
- | '' | ||
- | Die Funktion erzeugt einen neuen String aus //size// Zeichen. Alle Elemente werden mit '' | ||
- | |||
- | Parameter: | ||
- | size: Anzahl der Elemente\\ | ||
- | |||
- | Rückgabewert: | ||
- | neu erzeugter String\\ | ||
- | |||
- | |||
- | Hinweise:\\ | ||
- | Genau genommen erzeugt die Funktion einen Zeichenpuffer (Zeichen-Array) der angegebenen | ||
- | Größe. Die Größe des Puffers ist fest, d.h. es gibt keine Möglichkeit einer dynamischen | ||
- | Größenänderung. Der Zugriff auf die einzelnen Elemente erfolgt über den Zugriffsoperator | ||
- | [].\\ | ||
- | |||
- | Ein mit dieser Funktion angelegter Puffer sollte, sobald er nicht mehr benötigt wird, | ||
- | mit // | ||
- | |||
- | |||
- | |||
- | === Funktion newvector: === | ||
- | |||
- | '' | ||
- | Die Funktion erzeugt einen neuen Vektor aus //size// Elementen. Alle Elemente werden mit **null** | ||
- | initialisiert\\ | ||
- | |||
- | Parameter: | ||
- | size: Anzahl der Elemente\\ | ||
- | |||
- | Rückgabewert: | ||
- | neu erzeugter Vektor\\ | ||
- | |||
- | Hinweise:\\ | ||
- | Ein mit dieser Funktion angelegter Vektor sollte, sobald er nicht mehr benötigt wird, | ||
- | mit // | ||
- | |||
- | Die Größe des so angelegten Vektors ist fest, d.h. es gibt keine Möglichkeit einer | ||
- | dynamischen Größenänderung. | ||
- | |||
- | Die Elemente eines Vektors können beliebigen Typs sein. Insbesondere können sie auch | ||
- | selbst Vektoren sein, was den Aufbau mehrdimensionaler Strukturen erlaubt. Der Zugriff | ||
- | auf die einzelnen Elemente erfolgt über den Zugriffsoperator [].\\ | ||
- | |||
- | |||
- | |||
- | === Funktion T oder Vec (*): === | ||
- | |||
- | '' | ||
- | '' | ||
- | |||
- | Beide Funktionen sind synonym verwendbar. Sie konstruieren einen neuen Vektor, dessen | ||
- | Elemente die übergebenen Argumente in der angegebenen Reihenfolge sind.\\ | ||
- | |||
- | Parameter: | ||
- | kommaseparierte Liste beliebiger Werte\\ | ||
- | |||
- | Rückgabewert: | ||
- | neu erzeugter Vektor\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Ein mit dieser Funktion angelegter Vektor sollte, sobald er nicht mehr benötigt wird, | ||
- | mit // | ||
- | **Achtung: | ||
- | Funktion nicht kopiert. Deshalb ist darauf zu achten, dass sie nicht mehrfach freigegeben | ||
- | werden dürfen.\\ | ||
- | |||
- | Beispiel:\\ | ||
- | |||
- | <code cpp> | ||
- | /* T() example */ | ||
- | main(; | ||
- | { | ||
- | /* make a vector using strsplit-function */ | ||
- | vec = strsplit(" | ||
- | | ||
- | print(vec[i]," | ||
- | /* make new vector using T-Function | ||
- | Note that element at index 3 is the vector constructed above. */ | ||
- | vec = T(1, | ||
- | | ||
- | print(vec[i]," | ||
- | /* free inner vector */ | ||
- | | ||
- | /* free outer vector */ | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | |||
- | |||
- | === Funktion vecsize (*): === | ||
- | |||
- | '' | ||
- | Die Funktion liefert die Anzahl der Elemente von v\\ | ||
- | |||
- | Parameter: | ||
- | v: Vektor\\ | ||
- | |||
- | Rückgabewert: | ||
- | Anzahl der Elemente von v | ||
- | |||
- | |||
- | ==== 12.2 Typkonvertierungen und RTTI ==== | ||
- | BOB/BOB+ kennt keine impliziten Typumwandlungen und keinen cast-Operator. Deshalb sind | ||
- | Werte verschiedener Typen innerhalb eines Ausdrucks im allgemeinen inkompatibel((BOB+ erlaubt das Mischen von int und float bei Operanden von arithmetischen und Vergleichsoperatoren. Dabei wird implizit eine Konvertierung nach float durchgeführt.)). Zur Lösung | ||
- | dieses Problems wurden Funktionen für die explizite Umwandlung einfacher Datentypen (int, float, | ||
- | string) eingeführt. | ||
- | |||
- | Alle Funktionen dieses Abschnitts stehen nur in BOB+ zur Verfügung.\\ | ||
- | |||
- | |||
- | === Funktion dynamic_cast: | ||
- | |||
- | '' | ||
- | |||
- | Die Funktion verhält sich ähnlich dem dynamic_cast-Operator in C++. Zunächst wird der Ausdruck | ||
- | //expr// ausgewertet. Ist das Ergebnis ein Objekt der Klasse //dest// oder einer ihrer Ableitungen, | ||
- | |||
- | Parameter: | ||
- | dest: Klasse, zu der die Zugehörigkeit von expr geprüft werden soll\\ | ||
- | expr: Ausdruck beliebigen Typs\\ | ||
- | |||
- | Rückgabewert: | ||
- | Ergebnis von //expr// bei erfolgreichem Test, sonst **null**\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Im Gegensatz zu C++ wird kein Laufzeitfehler erzeugt, wenn //expr// kein Objekt ist. | ||
- | |||
- | Beispiel: | ||
- | <code cpp> | ||
- | /* dynamic_cast example */ | ||
- | class Base | ||
- | { | ||
- | | ||
- | } | ||
- | Base:: | ||
- | |||
- | class Derived : Base | ||
- | { | ||
- | | ||
- | } | ||
- | Derived:: | ||
- | |||
- | main() | ||
- | { | ||
- | obj1 = new Base(); | ||
- | obj2 = new Derived(); | ||
- | o = dynamic_cast(Base, | ||
- | o = dynamic_cast(Base, | ||
- | o = dynamic_cast(Derived, | ||
- | o = dynamic_cast(Derived, | ||
- | i = dynamic_cast(Base, | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | |||
- | === Funktion float: === | ||
- | |||
- | '' | ||
- | |||
- | Die Funktion konvertiert einen Ausdruck der Typen int, float oder string in einen float-Wert.\\ | ||
- | |||
- | Parameter: | ||
- | expr: Ausdruck des Typs int, float oder string\\ | ||
- | |||
- | Rückgabewert: | ||
- | float-Wert von //expr//\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Bei der Umwandlung aus einer Ganzzahl können bis zu vier Stellen Genauigkeit verloren | ||
- | gehen. Bei der Umwandlung aus einem String wird das Ergebnis des entsprechenden | ||
- | Aufrufs der C-Funktion sscanf zurückgegeben. | ||
- | |||
- | |||
- | === Funktion getclassname: | ||
- | |||
- | '' | ||
- | |||
- | Die Funktion wertet den Ausdruck //expr// aus und gibt den Klassennamen des Resultats zurück, falls | ||
- | //expr// ein Objekt oder eine Klasse ergibt.\\ | ||
- | |||
- | Parameter: | ||
- | expr: Ausdruck des Typs class oder object\\ | ||
- | |||
- | Rückgabewert: | ||
- | Klassenname von //expr// bei Erfolg, sonst **null**\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Das Ergebnis wird dynamisch erzeugt und sollte mittels // | ||
- | werden. | ||
- | |||
- | |||
- | === Funktion gettype: === | ||
- | |||
- | '' | ||
- | |||
- | Die Funktion wertet den Ausdruck //expr// aus und gibt dessen Typ zurück.\\ | ||
- | |||
- | Parameter: | ||
- | expr: beliebiger Ausdruck\\ | ||
- | |||
- | Rückgabewert: | ||
- | Datentyp-ID von expr\\ | ||
- | |||
- | Hinweise:\\ | ||
- | Das Ergebnis kann mit // | ||
- | Die ermittelte ID ist zum Typvergleich mit anderen Ausdrücken verwendbar.\\ | ||
- | |||
- | |||
- | |||
- | === Funktion gettypename: | ||
- | |||
- | '' | ||
- | |||
- | Die Funktion ermittelt den Namen des durch //typeid// spezifizierten Typs.\\ | ||
- | |||
- | Parameter: | ||
- | typeid: ID des Datentyps, dessen Name ermittelt werden soll.\\ | ||
- | |||
- | Rückgabewert: | ||
- | Typname von typeid\\ | ||
- | |||
- | Hinweise:\\ | ||
- | Das Ergebnis wird dynamisch erzeugt und sollte mittels // | ||
- | werden.\\ | ||
- | Die ID eines Datentyps kann mit //gettype// ermittelt werden.\\ | ||
- | |||
- | |||
- | |||
- | === Funktion int: === | ||
- | |||
- | '' | ||
- | |||
- | Die Funktion konvertiert einen Ausdruck der Typen int, float oder string in einen int-Wert. | ||
- | |||
- | Parameter: | ||
- | expr: Ausdruck des Typs int, float oder string\\ | ||
- | |||
- | Rückgabewert: | ||
- | int-Wert von expr\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Bei der Umwandlung aus float kann ein Überleuf des Zahlbereichs eintreten. Bei der | ||
- | Umwandlung aus einem String wird das Ergebnis des entsprechenden Aufrufs der C-Funktion | ||
- | sscanf zurückgegeben.\\ | ||
- | |||
- | |||
- | === Funktion string: === | ||
- | |||
- | '' | ||
- | |||
- | Die Funktion konvertiert einen Ausdruck der Typen int, float oder string in einen string-Wert. | ||
- | Optional kann in BOB+ 1.1 als zweiter Parameter eine Format-Spezifikation nach den Regeln der C-Funktion sprintf | ||
- | |||
- | Parameter: | ||
- | expr: Ausdruck des Typs int, float oder string\\ | ||
- | format: Format-String nach den Regeln der C-Funktion sprintf | ||
- | |||
- | Rückgabewert: | ||
- | string-Wert von //expr//\\ | ||
- | |||
- | Hinweise:\\ | ||
- | Die Implementierung von BOB+ 1.0 begrenzt die Länge des zurückgegebenen Strings auf maximal 199 Zeichen, in Version 1.1 besteht diese Beschränkung nicht mehr.\\ | ||
- | Das Ergebnis wird dynamisch erzeugt und sollte mittels // | ||
- | Die optionale Formatangabe muss – wenn verwendet – //genau eine Variable// enthalten, die zum Typ des Wertes von //expr// passt. Die Funktion verwendet intern die C-Funktion '' | ||
- | |||
- | ==== 12.3 Ein-/ | ||
- | Die mit (*) gekennzeichneten Funktionen dieses Abschnitts stehen nur in BOB+ zur Verfügung.\\ | ||
- | |||
- | === Funktion fclose: === | ||
- | |||
- | int fclose(FILE fp)\\ | ||
- | Die Funktion schließt eine vorher mit fopen geöffnete Datei.\\ | ||
- | |||
- | Parameter: | ||
- | fp: Handle der zu schließenden Datei\\ | ||
- | |||
- | Rückgabewert: | ||
- | Bei Erfolg 0, sonst Wert ungleich 0\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Die Funktion darf nicht mit den Standard-Streams stdin, stdout und stderr verwendet | ||
- | werden.\\ | ||
- | |||
- | === Funktion feof (*): === | ||
- | |||
- | int feof(FILE fp)\\ | ||
- | Die Funktion testet, ob das Ende der angegebenen Datei erreicht ist..\\ | ||
- | |||
- | Parameter: | ||
- | fp: Handle der zu überprüfenden Datei\\ | ||
- | |||
- | Rückgabewert: | ||
- | Wert ungleich 0, wenn Dateiende erreicht, sonst 0\\ | ||
- | |||
- | === Funktion fgets (*): === | ||
- | |||
- | string fgets(FILE fp)\\ | ||
- | Die Funktion liest eine Zeichenkette bzw. Zeile aus der in fp angegebenen geöffneten Textdatei. | ||
- | Das Lesen endet, wenn ein Zeilenumbruch oder das Dateiende erreicht bzw. die interne Puffergröße | ||
- | von 200 Zeichen ausgeschöpft ist.\\ | ||
- | |||
- | Parameter: | ||
- | fp: Handle der Datei\\ | ||
- | |||
- | Rückgabewert: | ||
- | Bei Erfolg wird die gelesene Zeile als Zeichenkette zurückgegeben. Bei Fehler oder | ||
- | erreichtem Dateiende ist das Ergebnis eine leere Zeichenkette.\\ | ||
- | |||
- | Hinweise:\\ | ||
- | Das Erreichen des Dateiendes sollte mit der Funktion feof geprüft werden. | ||
- | Ein ggf. aus der Datei gelesener Zeilenumbruch (‘\n‘) bleibt im Ergebnis erhalten. | ||
- | Da für das Funktionsergebnis dynamisch Speicher belegt wird, sollte dieser mit Hilfe von | ||
- | free wieder freigegeben werden.\\ | ||
- | |||
- | |||
- | === Funktion fopen: === | ||
- | |||
- | FILE fopen(string filename, string mode)\\ | ||
- | Die Funktion versucht, eine Datei mit dem in filename angegebenen Namen im durch mode | ||
- | spezifizierten Modus zu öffnen. Sie entspricht in ihrem Verhalten der gleichnamigen C-Funktion.\\ | ||
- | |||
- | Parameter: | ||
- | filename: Name der zu öffnenden Datei. Hier ist die Angabe eines einfachen Dateinamens oder | ||
- | eines Dateipfades (absolut oder relativ) im DOS-Stil möglich.\\ | ||
- | mode: Der Parameter beschreibt den Öffnungsmodus der Datei. Dabei sind folgenden Modi | ||
- | möglich:\\ | ||
- | * r: Öffnen einer existierenden Datei zum Lesen. | ||
- | * w: Anlegen einer Datei und Öffnen zum Schreiben. Existiert die angegebene Datei bereits, so wird sie überschrieben. | ||
- | * a: Öffnen einer Datei zum Schreiben ab dem aktuellen Dateiende (anhängen von Daten). Ist die Datei noch nicht vorhanden, so wird sie neu angelegt. | ||
- | * r+: Öffnen einer vorhandene Datei zum Lesen und Schreiben. | ||
- | * w+: Anlegen einer Datei und Öffnen zum Lesen und Schreiben. Existiert die angegebene Datei bereits, so wird sie überschrieben. | ||
- | * t: Öffnen der Datei im Textmodus (kombinierbar mit a, r, r+, w und w+). | ||
- | * b: Öffnen der Datei im binären Modus (kombinierbar mit a, r, r+, w und w+). | ||
- | |||
- | Rückgabewert: | ||
- | FILE-Handle bei Erfolg, sonst NULL\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Mit dieser Funktion geöffnete Dateien sollten stets mit fclose geschlossen werden.\\ | ||
- | |||
- | |||
- | === Funktion fputs (*): === | ||
- | |||
- | int fputs(string text, FILE fp)\\ | ||
- | Die Funktion schreibt die Zeichenkette in text in die durch fp angegebenee geöffnete Textdatei.\\ | ||
- | |||
- | Parameter: | ||
- | text: zu schreibende Zeichenkette\\ | ||
- | fp: Handle der Datei\\ | ||
- | |||
- | Rückgabewert: | ||
- | Bei Erfolg der Zeichencode des zuletzt geschriebenen Zeichens, andernfalls der Code von | ||
- | EOF zurückgegeben.\\ | ||
- | |||
- | |||
- | === Funktion freadval (*): === | ||
- | |||
- | var freadval(FILE fp)\\ | ||
- | Die Funktion liest einen (beliebigen) Wert aus einer Binärdatei und gibt ihn als Ergebnis zurück. | ||
- | Das Format der Datei muss dem von der Funktion fwriteval erzeugten entsprechen.\\ | ||
- | |||
- | Parameter: | ||
- | fp: Handle einer geöffneten Binär-Datei\\ | ||
- | |||
- | Rückgabewert: | ||
- | Bei Erfolg wird der gelesene Wert, andernfalls null zurückgegeben.\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Der Rückgabewert sollte i.a. einer Variablen zugewiesen und mit free wieder | ||
- | freigegeben werden, sobald er nicht mehr benötigt wird.\\ | ||
- | |||
- | |||
- | === Funktion fwriteval (*): === | ||
- | |||
- | int fwriteval(value, | ||
- | Die Funktion schreibt einen (beliebigen) Wert in eine geöffnete Binärdatei.\\ | ||
- | |||
- | Parameter: | ||
- | value: beliebiger Wert\\ | ||
- | fp: Handle einer geöffneten Binär-Datei\\ | ||
- | |||
- | Rückgabewert: | ||
- | Bei Erfolg 1, sonst 0\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Mit Hilfe der Funktionen fwriteval und freadval lassen sich komplexe Datenstrukturen – | ||
- | insbesondere auch Objekthierarchien – serialisieren und deserialisieren. Dabei werden bei | ||
- | der Deserialisierung Querverweise zwischen Objekten automatisch wieder hergestellt.\\ | ||
- | |||
- | Beispiel:\\ | ||
- | |||
- | <code cpp> | ||
- | /* Serialization example using fwriteval and freadval */ | ||
- | /* first we define a class */ | ||
- | class ListEntry | ||
- | { | ||
- | | ||
- | _a; | ||
- | _b; | ||
- | _ID; | ||
- | | ||
- | } | ||
- | |||
- | | ||
- | { | ||
- | if (!_maxID) | ||
- | _maxID = 0; | ||
- | _ID = ++_maxID; | ||
- | _a=a; | ||
- | _b=b; | ||
- | _next = null; | ||
- | } | ||
- | |||
- | | ||
- | |||
- | | ||
- | { | ||
- | print(" | ||
- | } | ||
- | |||
- | | ||
- | |||
- | | ||
- | |||
- | | ||
- | { | ||
- | if (_next) | ||
- | | ||
- | else | ||
- | { | ||
- | _next = var; | ||
- | } | ||
- | } | ||
- | |||
- | | ||
- | { | ||
- | if (_next) | ||
- | _next = delete _next; | ||
- | print(" | ||
- | } | ||
- | |||
- | main() | ||
- | { | ||
- | lst = new ListEntry(-1, | ||
- | for(i=0; | ||
- | { | ||
- | | ||
- | } | ||
- | for(p = l; | ||
- | | ||
- | fp=fopen(" | ||
- | fwriteval(lst, | ||
- | fclose(fp); | ||
- | lst = delete lst; // free list | ||
- | print(lst, | ||
- | fp=fopen(" | ||
- | lst=freadval(fp); | ||
- | fclose(fp); | ||
- | for(p = lst; | ||
- | | ||
- | lst = delete lst; // free list | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | === Funktion getc: === | ||
- | |||
- | int getc(FILE* fp)\\ | ||
- | Die Funktion liest ein einzelnes Zeichen aus der durch fp spezifizierten Datei.\\ | ||
- | |||
- | Parameter: | ||
- | fp: Handle der Datei\\ | ||
- | |||
- | Rückgabewert: | ||
- | Zeichencode des gelesenen Zeichens. Bei Fehler oder Dateiende wird EOF zurückgegeben.\\ | ||
- | |||
- | |||
- | === Funktion gets (*): === | ||
- | |||
- | string gets()\\ | ||
- | Die Funktion liest eine Zeichenkette von maximal 199 Zeichen von der Standardeingabe. Das | ||
- | Lesen endet bei Eingabe eines Zeilenwechsels.\\ | ||
- | |||
- | Rückgabewert: | ||
- | Bei Erfolg wird die gelesene Zeile als Zeichenkette andernfalls eine leere Zeichenkette.\\ | ||
- | |||
- | Hinweise:\\ | ||
- | Der abschließende Zeilenumbruch (‘\n‘) ist nicht im Ergebnis enthalten. | ||
- | Da für das Funktionsergebnis dynamisch Speicher belegt wird, sollte dieser mit Hilfe von free | ||
- | wieder freigegeben werden.\\ | ||
- | |||
- | |||
- | === Funktion print: === | ||
- | |||
- | void print(...)\\ | ||
- | Die Funktion schreibt die Werte der übergebenen Argumente auf die Standardausgabe.\\ | ||
- | |||
- | Parameter: | ||
- | Kommaseparierte Liste von Argumenten beliebigen Typs. Die Argumente werden in der | ||
- | angegebenen Reihenfolge in die Standardausgabe geschrieben. Dabei werden für primitive | ||
- | Typen die jeweiligen Werte implizit in Zeichenketten konvertiert. Für alle anderen Typen | ||
- | (File, Vektor, Klasse, Objekt, Funktion) wird der jeweilige Typ mit der zugehörigen Adresse | ||
- | ausgegeben.\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Im Gegensatz zu printf aus der C-Standardbibliothek kennt print keine Format- | ||
- | Spezifikation.\\ | ||
- | |||
- | |||
- | === Funktion putc: === | ||
- | |||
- | int putc(int c, FILE* fp)\\ | ||
- | Die Funktion schreibt ein einzelnes Zeichen in die durch fp spezifizierte Datei.\\ | ||
- | |||
- | Parameter: | ||
- | c: Zeichencode des zu schreibenden Zeichens\\ | ||
- | fp: Handle der Datei\\ | ||
- | |||
- | Rückgabewert: | ||
- | Zeichencode des geschriebenen Zeichens. Bei Fehler wird EOF zurückgegeben.\\ | ||
- | |||
- | ==== 12.4 Zeichenkettenfunktionen ==== | ||
- | Alle Funktionen dieses Abschnitts stehen nur in BOB+ zur Verfügung.\\ | ||
- | |||
- | === Funktion strcmp: === | ||
- | |||
- | int strcmp(string s1, string s2)\\ | ||
- | Die Funktion vergleicht die Zeichenketten s1 und s2 zeichenweise, | ||
- | Kleinschreibung unterschieden wird. Sie verhält sich wie die gleichnamige Standard-C-Funktion.\\ | ||
- | |||
- | Parameter: | ||
- | s1: erster Operand\\ | ||
- | s2: zweiter Operand\\ | ||
- | |||
- | Rückgabewert: | ||
- | < 0, falls s1 < s2\\ | ||
- | 0, falls s1 == s2\\ | ||
- | > 0, falls s1 > s2\\ | ||
- | |||
- | |||
- | |||
- | === Funktion stricmp: === | ||
- | int stricmp(string s1, string s2)\\ | ||
- | Die Funktion vergleicht die Zeichenketten s1 und s2 zeichenweise, | ||
- | Kleinschreibung nicht unterschieden wird. Sie verhält sich wie die gleichnamige Standard-CFunktion.\\ | ||
- | |||
- | Parameter: | ||
- | s1: erster Operand\\ | ||
- | s2: zweiter Operand\\ | ||
- | |||
- | Rückgabewert: | ||
- | < 0, falls s1 < s2\\ | ||
- | 0, falls s1 == s2\\ | ||
- | > 0, falls s1 > s2\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Die Funktion arbeitet nur fehlerfrei, wenn in s1 und s2 keine Zeichen mit einem ASCII-Code > 128 (z.B. Umlaute) vorkommen.\\ | ||
- | |||
- | |||
- | |||
- | === Funktion strlen: === | ||
- | |||
- | '' | ||
- | |||
- | Die Funktion liefert die Länge der Zeichenkette //s//. Sie verhält sich wie die gleichnamige Standard-C-Funktion. | ||
- | Parameter: | ||
- | s: Zeichenkette\\ | ||
- | |||
- | Rückgabewert: | ||
- | Anzahl der Zeichen in s | ||
- | |||
- | === Funktion strsize: === | ||
- | |||
- | '' | ||
- | |||
- | Die Funktion existiert nur in BOB+ 1.1. Sie liefert die maximal mögliche Länge der Zeichenkette // | ||
- | |||
- | Parameter: | ||
- | s: Zeichenkette\\ | ||
- | |||
- | Rückgabewert: | ||
- | Maximale Anzahl der Zeichen in s | ||
- | |||
- | |||
- | |||
- | === Funktion strsplit: === | ||
- | |||
- | vector strsplit(string source, string delimiter)\\ | ||
- | Die Funktion zerlegt die in source übergebene Zeichenkette in Teilketten entsprechend der in | ||
- | delimiter angegebenen Trennzeichen. Sie verwendet intern die Standard-C-Funktion strtok.\\ | ||
- | |||
- | Parameter: | ||
- | source: zu zerlegende Zeichenkette\\ | ||
- | delimiter: Zeichenkette mit einem oder mehreren Trennzeichen\\ | ||
- | |||
- | Rückgabewert: | ||
- | Die Funktion gibt einen Vektor zurück, dessen Elemente vom Typ string sind und die | ||
- | einzelnen Teilketten enthalten.\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Sowohl der zurückgegebene Vektor als auch dessen Elemente werden dynamisch | ||
- | erzeugt. Sie sollten deshalb mit free wieder freigegeben werden.\\ | ||
- | |||
- | Beispiel:\\ | ||
- | |||
- | <code cpp> | ||
- | /* strsplit example */ | ||
- | main(; | ||
- | { | ||
- | text = “This text will be splitted.“; | ||
- | | ||
- | cnt = vecsize(result); | ||
- | /* print result */ | ||
- | for (i=0; | ||
- | print(result[i], | ||
- | /* free allocated memory */ | ||
- | for (i=0; i<cnt; i++) | ||
- | free(result[i]); | ||
- | | ||
- | text = free(text); | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | ==== 12.5 Datum und Uhrzeit ==== | ||
- | Alle Funktionen dieses Abschnitts stehen nur in BOB+ zur Verfügung\\ | ||
- | |||
- | === Funktion ctime: === | ||
- | |||
- | string ctime(int t)\\ | ||
- | Die Funktion erzeugt aus der numerischen Datums- und Zeitangabe in t eine druckbare | ||
- | Zeichenkette. Sie verhält sich wie die gleichnamige C-Funktion.\\ | ||
- | |||
- | Parameter: | ||
- | t: numerischer Datums- und Zeitwert (wie time_t in C)\\ | ||
- | |||
- | Rückgabewert: | ||
- | Zeichenkettendarstellung von t in der Form\\ | ||
- | Wed Aug 10 21:52:54 2005\n\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Die zurückgelieferte Zeichenkette sollte mit free explizit freigegeben werden.\\ | ||
- | |||
- | |||
- | === Funktion localtime: === | ||
- | |||
- | vector localtime(int t)\\ | ||
- | Die Funktion erzeugt aus der numerischen Datums- und Zeitangabe in t einen Vektor mit den | ||
- | Bestandteilen der lokalisierten Zeitangabe.\\ | ||
- | |||
- | Parameter: | ||
- | t: numerischer Datums- und Zeitwert (wie time_t in C)\\ | ||
- | |||
- | Rückgabewert: | ||
- | Vektor aus neun ganzzahligen Elementen entsprechend der tm-Struktur aus C mit folgender | ||
- | Bedeutung: | ||
- | |Index| | ||
- | |Wert|sec |min |hour |mday |mon |year |wday |yday |isdst | | ||
- | Dabei erfolgt die Jahresangabe (year) relativ zum Jahr 1900. Das Feld isdst hat den Wert 1, | ||
- | wenn sich die Zeitangabe auf Sommerzeit bezieht, sonst 0.\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Der zurückgelieferte Vektor sollte mit free explizit freigegeben werden.\\ | ||
- | |||
- | |||
- | === Funktion time: === | ||
- | |||
- | int time()\\ | ||
- | Die Funktion liefert die aktuelle Zeit in Sekunden seit dem 1. Januar 1970 0:00 Uhr GMT. Sie | ||
- | verhält sich wie die gleichnamige C-Funktion.\\ | ||
- | |||
- | Rückgabewert: | ||
- | Vergangene Sekunden seit dem 1. Januar 1970 0:00 Uhr GMT\\ | ||
- | |||
- | |||
- | === Funktion timer: === | ||
- | |||
- | int timer()\\ | ||
- | Die Funktion liefert die verstrichene Zeit seit dem Programmstart in Millisekunden.\\ | ||
- | |||
- | Rückgabewert: | ||
- | Vergangene Zeit seit dem Programmstart in ms.\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Die Funktion verwendet clock()-Funktion aus C. Deshalb ist die tatsächliche | ||
- | Auflösung geringer als 1 ms. Unter MS-DOS liegt sie bei etwa 55 ms.\\ | ||
- | |||
- | |||
- | ==== 12.6 Mathematische Funktionen ==== | ||
- | Alle Funktionen dieses Abschnitts stehen nur in BOB+ zur Verfügung. Wenn nicht gesondert | ||
- | ausgewiesen, | ||
- | Typ int.\\ | ||
- | |||
- | === Funktion abs: === | ||
- | |||
- | int abs(int x) oder float abs(float x)\\ | ||
- | Die Funktion berechnet den Absolutbetrag des als Argument übergebenen Wertes.\\ | ||
- | |||
- | Parameter: | ||
- | x: numerischer Wert vom Typ int oder float\\ | ||
- | |||
- | Rückgabewert: | ||
- | Betrag von x. Der Typ des Rückgabewertes entspricht dem des Arguments.\\ | ||
- | |||
- | |||
- | === Funktion atan: === | ||
- | |||
- | float atan(float x)\\ | ||
- | Die Funktion berechnet den Arcus-Tangens des als Argument übergebenen Wertes.\\ | ||
- | |||
- | Parameter: | ||
- | x: Argument\\ | ||
- | |||
- | Rückgabewert: | ||
- | Winkel im Bogenmaß im Bereich (-pi/2, +pi/2)\\ | ||
- | |||
- | |||
- | === Funktion cos: === | ||
- | |||
- | float cos(float rad)\\ | ||
- | Die Funktion berechnet den Kosinus des als Argument übergebenen Winkels.\\ | ||
- | |||
- | Parameter: | ||
- | rad: Winkelangabe im Bogenmaß\\ | ||
- | |||
- | Rückgabewert: | ||
- | Kosinus von rad\\ | ||
- | |||
- | |||
- | === Funktion exp: === | ||
- | |||
- | float exp(float x)\\ | ||
- | Die Funktion berechnet Wert der Expotentialfunktion ex.\\ | ||
- | |||
- | Parameter: | ||
- | x: Exponent\\ | ||
- | |||
- | Rückgabewert: | ||
- | Wert von ex\\ | ||
- | |||
- | |||
- | === Funktion log: === | ||
- | |||
- | float log(float x)\\ | ||
- | Die Funktion berechnet natürlichen Logarithmus ln(x).\\ | ||
- | |||
- | Parameter: | ||
- | x: Argument\\ | ||
- | |||
- | Rückgabewert: | ||
- | Wert von ln(x)\\ | ||
- | |||
- | |||
- | === Funktion pow: === | ||
- | |||
- | float pow(float x, float y)\\ | ||
- | Die Funktion berechnet Wert der Expotentialfunktion xy.\\ | ||
- | |||
- | Parameter: | ||
- | x: Basis\\ | ||
- | y: Exponent\\ | ||
- | |||
- | Rückgabewert: | ||
- | Wert von xy\\ | ||
- | |||
- | |||
- | === Funktion sin: === | ||
- | |||
- | float sin(float rad)\\ | ||
- | Die Funktion berechnet den Sinus des als Argument übergebenen Winkels.\\ | ||
- | |||
- | Parameter: | ||
- | rad: Winkelangabe im Bogenmaß\\ | ||
- | |||
- | Rückgabewert: | ||
- | Sinus von rad\\ | ||
- | |||
- | |||
- | === Funktion sqrt: === | ||
- | |||
- | float sqrt(float x)\\ | ||
- | Die Funktion berechnet die Quadratwurzel von x.\\ | ||
- | |||
- | Parameter: | ||
- | x: Argument\\ | ||
- | |||
- | Rückgabewert: | ||
- | Quadratwurzel von x\\ | ||
- | |||
- | |||
- | === Funktion tan: === | ||
- | |||
- | float tan(float rad)\\ | ||
- | Die Funktion berechnet den Tangens des als Argument übergebenen Winkels.\\ | ||
- | |||
- | Parameter: | ||
- | rad: Winkelangabe im Bogenmaß\\ | ||
- | |||
- | Rückgabewert: | ||
- | Tangens von rad\\ | ||
- | |||
- | |||
- | |||
- | |||
- | ==== 12.7 Systemfunktionen ==== | ||
- | Die Funktionen dieses Abschnitts ermöglichen es, Systemaufrufe durchzuführen. Sie sind nur in BOB+ verfügbar. Die mit (*) gekennzeichneten Funktionen existieren nur in der Version 1.1 von BOB+. Mit (*c) gekennzeichnete Funktionen sind erst ab Version 1.1c verfügbar.\\ | ||
- | |||
- | |||
- | |||
- | === Funktion addr: === | ||
- | |||
- | '' | ||
- | Die Funktion liefert die Adresse der Variablen var. Sie wird u.a. für Interrupt-Aufrufe benötigt, die | ||
- | Adressen als Eingabeparameter erwarten.\\ | ||
- | |||
- | Parameter: | ||
- | var: Variablenbezeichner\\ | ||
- | |||
- | Rückgabewert: | ||
- | Offset-Adresse der angegebenen Variablen.\\ | ||
- | |||
- | Hinweise:\\ | ||
- | **Das Verhalten der Funktion unterscheidet sich in BOB+ 1.1 von dem der Version 1.0!** | ||
- | |||
- | Für Version 1.0 gilt: | ||
- | * Die Funktion liefert nicht die vollständige Adresse sondern nur deren Offset-Anteil. | ||
- | * Der zurückgelieferte Wert ist für Variablen vom Typ String der Offset des Anfangs der tatsächlichen Zeichenkette, | ||
- | |||
- | |||
- | Für Version 1.1 gilt: | ||
- | * Die Funktion liefert eine vollständige Adresse. Dabei steht der Offset-Teil der Adresse im niederwertigen und der Segment-Teil im höherwertigen (16-Bit) Wort des Resultats. Damit ist das Funktionsergebnis sowohl als NEAR- als auch als FAR-Zeiger verwendbar. Der Zweck der Änderung besteht darin, Zeiger auf BOB+-Daten an Funktionen in Dynamischen Bibliotheken (DLLs – vgl Abschnitt 13) weitergeben zu können. | ||
- | * Der zurückgelieferte Wert hängt von Datentyp der als Argument übergebenen Variablen ab, wobei folgendes gilt: | ||
- | * Für den Typ String ist der Rückgabewert die Adresse des Anfangs der Zeichenkette innerhalb des String-Objekts. Dies ermöglicht die Verwendung eines Strings als Zeichenpuffer. | ||
- | * Für die numerischen Typen (int, float) wird die Adresse des Wertes zurückgegeben. Damit können Referenzen auf numerische Werte als Argumente von Funktionen in DLLs verwendet werden. | ||
- | * Für alle anderen Typen ist das Ergebnis der Wert selbst (als Zeiger zu interpretieren). Damit ist auch der Zugriff auf Referenztypen in DLL-Funktionen möglich. | ||
- | |||
- | === Funktion CallLibFunc (*): === | ||
- | |||
- | '' | ||
- | |||
- | Die Funktion ruft die durch proc spezifizierte Funktion in einer dynamischen Bibliothek auf. | ||
- | |||
- | Parameter: | ||
- | * proc: Zeiger auf die Funktion. Als Wert ist das Resultat eines vorangegangenen Aufrufs der Funktion GetProcAddress zu übergeben. | ||
- | * Weitere Argumente werden in der Reihenfolge ihrer Angabe an die aufgerufene Funktion weitergeleitet. Ihre Art und Anzahl hängt von den Erfordernissen der jeweiligen Funktion ab. | ||
- | |||
- | Rückgabewert: | ||
- | Der Rückgabewert und die Art seiner Interpretation hängt von der Implementierung der aufgerufenen Funktion ab. | ||
- | |||
- | Hinweise:\\ | ||
- | * BOB+ weiß nichts darüber, wie eine bestimmte Funktion in einer DLL aufgerufen werden muss und kann deshalb selbst keinerlei Überprüfungen vornehmen. Die Bereitstellung der korrekten Parameter liegt allein in der Verantwortung des Benutzers, der also ggf. die Dokumentation der DLL und der von ihr exportierten Funktionen zu Rate ziehen sollte. | ||
- | * Die aufgerufene Funktion muss eine nach C-Konventionen implementierte FAR-Funktion sein, deren Parameter und Rückgabewert jeweils 32 Bit breit sind. Aus Sicht des aufrufenden BOB+-Programms können die übergebenen Werte Zeiger oder Zahlen (int bzw. float) repräsentieren. Um Referenztypen (insbesondere Zeichenketten) als Zeiger zu übergeben, sollte das aufrufende Programm die Funktion addr zur Konvertierung verwenden. | ||
- | |||
- | Beispiel: | ||
- | Zur Veranschaulichung wollen wir annehmen, dass eine dynamische Bibliothek für den Zugriff auf eine Datenbank existiert, die „database.dll“ heißt und eine Anmeldefunktion mit der C-Signatur | ||
- | |||
- | '' | ||
- | |||
- | unter dem Namen „login“ exportiert. Diese Funktion erwartet also als Argumente einen Benutzernamen und ein Passwort (beides Zeichenketten). Sie soll bei erfolgreicher Anmeldung eine 1, sonst eine 0 zurückgeben. | ||
- | |||
- | Nachfolgender Code-Ausschnitt zeigt alle zum Aufruf der Funktion nötigen Schritte: | ||
- | <code cpp> | ||
- | // Example for DLL function call | ||
- | main(; | ||
- | { | ||
- | // first load dynamic library | ||
- | hdll = LoadLibrary(“database.dll”); | ||
- | // get address of exportet function | ||
- | proc = GetProcAddress(hdll, | ||
- | // now ask user for her/his name and password | ||
- | | ||
- | name = gets(); | ||
- | | ||
- | pwd = gets(); | ||
- | // try to login | ||
- | // don’t forget to pass addresses of strings | ||
- | if (CallLibFunc(proc, | ||
- | { | ||
- | // do anything | ||
- | } | ||
- | else | ||
- | | ||
- | // release strings | ||
- | | ||
- | | ||
- | // release library | ||
- | | ||
- | } | ||
- | </ | ||
- | |||
- | |||
- | === Funktion FreeLibrary (*): === | ||
- | |||
- | '' | ||
- | |||
- | Die Funktion gibt eine mit LoadLibrary geladene dynamische Bibliothek wieder frei. | ||
- | |||
- | Parameter: | ||
- | hdll: Handle der freizugebenden Bibliothek | ||
- | |||
- | Rückgabewert: | ||
- | 1 bei Erfolg, sonst (d.h. wenn //hdll// ungültig war) 0 | ||
- | |||
- | === Funktionen getmemb, getmemw und getmemdw (*c): === | ||
- | '' | ||
- | '' | ||
- | '' | ||
- | |||
- | Die Funktionen lesen einen Byte- (8 Bit), Wort- (16 Bit) oder Doppelwort-Wert von der durch //addr// angegebenen Speicherposition. | ||
- | |||
- | Parameter: | ||
- | addr: Speicheradresse (FAR). Das höherwertige 16-Bit-Wort enthält die Segmentadresse, | ||
- | |||
- | Rückgabewert: | ||
- | Gelesener Wert (8 Bit bei getmemb, 16 Bit bei getmemw, 32 Bit bei getmemdw). | ||
- | |||
- | Beispiel:\\ | ||
- | Nachfolgende Beispielfunktion verwendet '' | ||
- | <code cpp> | ||
- | listIntVecs(; | ||
- | { | ||
- | | ||
- | { | ||
- | pvec = getmemdw(p); | ||
- | s = string(pvec, | ||
- | print(“Int: | ||
- | free(s); // release string | ||
- | | ||
- | } | ||
- | </ | ||
- | |||
- | === Funktion GetProcAddress (*): === | ||
- | |||
- | '' | ||
- | |||
- | Die Funktion liefert die Adresse der unter dem Namen // | ||
- | |||
- | Parameter: | ||
- | hdll: Handle der DLL, die die Funktion exportiert | ||
- | funcname: Bezeichnung der exportierten Funktion in der Exporttabelle der DLL | ||
- | |||
- | Rückgabewert: | ||
- | Adresse (FAR Pointer) der exportierten DLL-Funktion. Der Rückgabewert wird als Argument für den Aufruf der Funktion '' | ||
- | |||
- | Hinweise: | ||
- | Existiert die angegebene Funktion nicht, so wird das aktuelle Programm unter Ausgabe einer entsprechenden Fehlermeldung abgebrochen.\\ | ||
- | Exportiert die Bibliothek unter dem angegebenen Namen keine Funktion sondern einen Datenbereich, | ||
- | |||
- | === Funktion getreg: === | ||
- | |||
- | int getreg(string regname)\\ | ||
- | Die Funktion liest den aktuellen Wert der angegebenen Register-Variablen.\\ | ||
- | |||
- | Parameter: | ||
- | regname: Name eines Prozessorregisters, | ||
- | ax, bx, cx, dx, di, si, al, ah, bl, bh, cl, ch, dl, dh, cflag, flags, ds, es, ss, cs.\\ | ||
- | Die Groß- und Kleinschreibung wird bei der Angabe der Registernamen ignoriert.\\ | ||
- | |||
- | Rückgabewert: | ||
- | aktueller Wert der angegebenen Register-Variablen.\\ | ||
- | |||
- | |||
- | Hinweis:\\ | ||
- | Die Funktion liest nicht die tatsächlichen aktuellen Werte der Prozessorregister aus sondern | ||
- | greift auf eine interne Datenstruktur zu, die vorher innerhalb des Programms explizit (mit | ||
- | setreg bzw. segread) oder implizit (in Folge eines int86- oder int86x-Aufrufs) initialisiert | ||
- | wurde.\\ | ||
- | |||
- | |||
- | === Funktion inport: === | ||
- | |||
- | int inport(int portid)\\ | ||
- | Die Funktion liest ein Wort (16 Bit) ab Portadresse portid. Dabei wird das Low-Byte direkt von | ||
- | portid und das High-Byte von portid+1 gelesen.\\ | ||
- | |||
- | Parameter: | ||
- | portid: Port-Nummer\\ | ||
- | |||
- | Rückgabewert\\ | ||
- | gelesenes Wort\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Die Funktion benutzt intern die gleichnamige Turbo-C-Funktion und verhält sich | ||
- | entsprechend.\\ | ||
- | |||
- | |||
- | === Funktion inportb: === | ||
- | |||
- | int inportb(int portid)\\ | ||
- | Die Funktion liest ein einzelnes Byte von Portadresse portid.\\ | ||
- | |||
- | Parameter: | ||
- | portid: Port-Nummer\\ | ||
- | |||
- | Rückgabewert: | ||
- | gelesenes Byte\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Die Funktion benutzt intern die gleichnamige Turbo-C-Funktion und verhält sich | ||
- | entsprechend.\\ | ||
- | |||
- | |||
- | === Funktion int86: === | ||
- | |||
- | int int86(int intnr)\\ | ||
- | Die Funktion führt löst einen Aufruf des durch intnr spezifizierten x86-Interrupts aus. Vor dem | ||
- | Aufruf werden die Prozessorregister AX, BX, CX, DX, DI, SI, FLAGS mit den Inhalten der | ||
- | entsprechenden internen Registervariablen geladen. Nach dem Aufruf werden die Registerwerte in | ||
- | die internen Variablen übernommen und die ursprünglichen Registerinhalte wieder hergestellt.\\ | ||
- | |||
- | Parameter: | ||
- | intnr: Nummer des aufzurufenden Interrupts\\ | ||
- | |||
- | Rückgabewert: | ||
- | Wert des Registers AX nach dem Interrupt-Aufruf\\ | ||
- | |||
- | |||
- | |||
- | === Funktion int86x: === | ||
- | |||
- | '' | ||
- | |||
- | Die Funktion löst einen Aufruf des durch //intnr// spezifizierten x86-Interrupts aus. Vor dem | ||
- | Aufruf werden die Prozessorregister AX, BX, CX, DX, DI, SI, FLAGS, DS und ES mit den | ||
- | Inhalten der entsprechenden internen Registervariablen geladen. Nach dem Aufruf werden die | ||
- | Registerwerte in die internen Variablen übernommen und die ursprünglichen Registerinhalte wieder | ||
- | hergestellt.\\ | ||
- | |||
- | Parameter: | ||
- | intnr: Nummer des aufzurufenden Interrupts\\ | ||
- | |||
- | Rückgabewert: | ||
- | Wert des Registers AX nach dem Interrupt-Aufruf\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Vor Benutzung der Funktion sollten die internen Variablen der Segmentregister mit | ||
- | Hilfe der Funktion // | ||
- | |||
- | Beispiel:\\ | ||
- | |||
- | <code cpp> | ||
- | /* interrupt call example – prints current directory path */ | ||
- | main() | ||
- | { | ||
- | buf = newstring(200); | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | |||
- | === Funktion LoadLibrary (*): === | ||
- | |||
- | '' | ||
- | |||
- | Die Funktion lädt die dynamische Bibliothek //name// in den aktuellen Prozessraum und liefert ein Handle auf die Bibliothek. | ||
- | |||
- | Parameter: | ||
- | * name: Dateiname der Bibliothek. Der Name muss mit Erweiterung angegeben werden und kann außerdem eine absolute oder relative Pfadangabe enthalten. Die Suche nach der Datei erfolgt zuerst ausgehend vom aktuellen Verzeichnis und dann entlang der in der Umgebungsvarieblen PATH angegebenen Pfade. | ||
- | |||
- | Rückgabewert: | ||
- | Handle auf die Bibliothek | ||
- | |||
- | Hinweise: | ||
- | Das zurückgegebene Handle wird als Argument für Aufrufe der Funktionen '' | ||
- | Kann die angegebene Bibliothek nicht geladen werden, wird das aktuelle Programm unter Ausgabe einer entsprechenden Fehlermeldung abgebrochen.\\ | ||
- | Eine mit '' | ||
- | |||
- | === Funktion movedata (*c): === | ||
- | |||
- | '' | ||
- | |||
- | Die Funktion kopiert einen Speicherblock von cnt Byte Länge von Adresse src nach Adresse dest. | ||
- | |||
- | Parameter: | ||
- | * src: Quelladresse | ||
- | * dest: Zieladresse | ||
- | * cnt: Anzahl der zu kopierenden Bytes (1 bis 0xffff) | ||
- | |||
- | Hinweise:\\ | ||
- | Die Funktion benutzt intern die gleichnamige Turbo-C-Funktion und verhält sich entsprechend. Die maximal kopierbare Blockgröße beträgt wegen der Speichersegmentierung 64 KB.\\ | ||
- | Vorsicht: Mit der Funktion können beliebige Speicherbereiche überschrieben werden. Sie sollte deshalb mit entsprechender Vorsicht eingesetzt werden. | ||
- | |||
- | === Funktion outport: === | ||
- | |||
- | '' | ||
- | |||
- | Die Funktion schreibt ein Wort (16 Bit) nach Portadresse portid. Dabei wird das Low-Byte direkt | ||
- | nach //portid// und das High-Byte nach // | ||
- | |||
- | Parameter: | ||
- | portid: Port-Nummer\\ | ||
- | value: auszugebender Wert\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Die Funktion benutzt intern die gleichnamige Turbo-C-Funktion und verhält sich | ||
- | entsprechend. Es wird das niederwertige Wort von //value// berücksichtigt.\\ | ||
- | |||
- | |||
- | === Funktion outportb: === | ||
- | |||
- | void outportb(int portid, int value)\\ | ||
- | Die Funktion schreibt ein einzelnes Byte nach Portadresse portid.\\ | ||
- | |||
- | Parameter: | ||
- | portid: Port-Nummer\\ | ||
- | value: auszugebender Wert\\ | ||
- | |||
- | Rückgabewert: | ||
- | gelesenes Byte\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Die Funktion benutzt intern die gleichnamige Turbo-C-Funktion und verhält sich | ||
- | entsprechend. Es wird das niederwertigste Byte von value berücksichtigt.\\ | ||
- | |||
- | |||
- | |||
- | === Funktion segread: === | ||
- | |||
- | '' | ||
- | |||
- | Die Funktion lädt die aktuellen Werte der Segmentregister des Prozessors (DS, ES, SS, CS) in die | ||
- | entsprechenden internen Variablen.\\ | ||
- | |||
- | === Funktionen setmemb, setmemw und setmemdw (c*): === | ||
- | '' | ||
- | '' | ||
- | '' | ||
- | |||
- | Die Funktionen schreiben einen Byte- (8 Bit), Wort- (16 Bit) oder Doppelwort-Wert an die durch addr angegebene Speicherposition. | ||
- | |||
- | Parameter: | ||
- | * addr: Speicheradresse (FAR). Das höherwertige 16-Bit-Wort enthält die Segmentadresse, | ||
- | * val: Zu schreibender Wert (8 Bit bei setmemb, 16 Bit bei setmemw, 32 Bit bei setmemdw). | ||
- | |||
- | Hinweis:\\ | ||
- | Diese Funktionen erlauben die direkte Manipulation beliebiger Speicherstellen. Sie sollten in Anwendungsprogrammen deshalb mit entsprechender Vorsicht verwendet werden. | ||
- | |||
- | === Funktion setreg: === | ||
- | void setreg(string regname, int value)\\ | ||
- | Die Funktion setzt den Wert der angegebenen internen Register-Variablen.\\ | ||
- | |||
- | Parameter: | ||
- | regname: Name eines Prozessorregisters, | ||
- | ax, bx, cx, dx, di, si, al, ah, bl, bh, cl, ch, dl, dh, cflag, flags, ds, es, ss, cs. | ||
- | Die Groß- und Kleinschreibung wird bei der Angabe der Registernamen ignoriert.\\ | ||
- | value: neuer Wert | ||
- | |||
- | Hinweis:\\ | ||
- | Die Werte der internen Register-Variablen werden beim Aufruf der Funktionen int86 bzw. | ||
- | int86x in die entsprechenden Prozessorregister übernommen.\\ | ||
- | |||
- | ==== 12.8 Grafikfunktionen ==== | ||
- | Die Grafikfunktionen ermöglichen elementare Ausgaben im Grafikmodus. Intern werden BIOSAufrufe | ||
- | verwendet.\\ | ||
- | Alle Funktionen dieses Abschnitts stehen nur in BOB+ zur Verfügung.\\ | ||
- | |||
- | |||
- | === Funktion setscrmode: === | ||
- | |||
- | void setscrmode(int mode)\\ | ||
- | Die Funktion löscht den Bildschirm und schaltet die Anzeige in den angegebenen Modus um.\\ | ||
- | |||
- | Parameter: | ||
- | mode: neuer Bildschirmmodus\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Die konkrete Bedeutung von mode hängt vom verwendeten Grafik-Adapter bzw. dessen | ||
- | BIOS ab. Allgemein steht der Wert 7 für den MDA-Modus (monochromer Textmodus) ((Auf dem Atari-Portfolio hängt die Zeilen- und Spaltenzahl im Textmodus von der eingestellten Bildschirm-Betriebsart ab. Der Grafikmodus hat dort immer eine Auflösung von 240 x 64 Pixeln und lässt sich mit den Werten 4 oder 10 aufrufen.)). | ||
- | |||
- | |||
- | === Funktion setpixel: === | ||
- | |||
- | void setpixel(int x, int y, int color)\\ | ||
- | Die Funktion setzt einen einzelnen Bildschirmpunkt auf den mit color spezifizierten Farbwert.\\ | ||
- | |||
- | Parameter: | ||
- | x: x-Koordinate\\ | ||
- | y: y-Koordinate\\ | ||
- | color: Farbwert\\ | ||
- | |||
- | Hinweise:\\ | ||
- | Die Funktion ist nur bei eingeschaltetem Grafikmodus sinnvoll verwendbar. | ||
- | Die Werte für die Koordinaten sollten stets nichtnegativ sein und werden nach oben | ||
- | durch die jeweilige Bildschirmauflösung begrenzt. Der Punkt (0,0) bezeichnet die linke | ||
- | obere Bildschirmecke.\\ | ||
- | Beim in color angegebenen Wert sind nur die niederwertigsten 8 Bit signifikant. Die | ||
- | konkrete Bedeutung hängt vom Bildschirmmodus ab ((Beim Atari-Portfolio steht der Wert 0 für einen nicht gesetzten, alle anderen Werte für einen gesetzten Punkt.)).\\ | ||
- | |||
- | |||
- | === Funktion line: === | ||
- | void line(int x1, int y1, x2, y2, int color)\\ | ||
- | Die Funktion zeichnet eine Linie in der mit color spezifizierten Farbe vom Punkt (x1,y1) nach | ||
- | Punkt (x2,y2).\\ | ||
- | |||
- | Parameter: | ||
- | x1: x-Koordinate des Anfangspunktes\\ | ||
- | y1: y-Koordinate des Anfangspunktes\\ | ||
- | x2: x-Koordinate des Endpunktes\\ | ||
- | y2: y-Koordinate des Endpunktes\\ | ||
- | color: Farbwert\\ | ||
- | |||
- | Hinweise:\\ | ||
- | Die Funktion ist nur bei eingeschaltetem Grafikmodus sinnvoll verwendbar. | ||
- | Die Werte für die Koordinaten sollten stets nichtnegativ sein und werden nach oben | ||
- | durch die jeweilige Bildschirmauflösung begrenzt. Der Punkt (0,0) bezeichnet die linke | ||
- | obere Bildschirmecke.\\ | ||
- | Beim in color angegebenen Wert sind nur die niederwertigsten 8 Bit signifikant. Die | ||
- | konkrete Bedeutung hängt vom Bildschirmmodus ab.\\ | ||
- | |||
- | Beispiel:\\ | ||
- | |||
- | <code cpp> | ||
- | /* Portfolio-example for using graphic functions */ | ||
- | main() | ||
- | { | ||
- | /* resolution */ | ||
- | | ||
- | | ||
- | /* switch to graphic mode */ | ||
- | | ||
- | /* get current time */ | ||
- | ms = timer(); | ||
- | n=0; | ||
- | /* draw some lines */ | ||
- | for (x=0; | ||
- | { | ||
- | n++; | ||
- | x2= px -x; | ||
- | line(x, | ||
- | } | ||
- | for (y=0; | ||
- | { | ||
- | n++; | ||
- | y2= py-1 -y; | ||
- | line(0, | ||
- | } | ||
- | /* get elapsed time */ | ||
- | ms = timer() - ms; | ||
- | r = n*1000 / ms; | ||
- | | ||
- | /* switch to text mode */ | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | |||
- | ==== 12.9 Sonstige Funktionen ==== | ||
- | In diesem Abschnitt werden einige Funktionen beschrieben, | ||
- | zuordnen lassen. Alle diese Funktionen sind nur in BOB+ verfügbar.\\ | ||
- | |||
- | |||
- | === Funktion argcnt: === | ||
- | |||
- | int argcnt()\\ | ||
- | Die Funktion liefert einen die Anzahl der Argumente, die der aufrufenden Funktion übergeben | ||
- | wurden.\\ | ||
- | |||
- | Rückgabewert: | ||
- | Anzahl der Argumente der aufrufenden Funktion\\ | ||
- | |||
- | |||
- | |||
- | === Funktion arg: === | ||
- | |||
- | var arg(int idx)\\ | ||
- | Die Funktion liefert das Argument mit dem Index idx der aufrufenden Funktion. Sie kann in | ||
- | Verbindung mit der Funktion argcnt zur Konstruktion von Funktionen mit variablen Argumentlisten | ||
- | verwendet werden.\\ | ||
- | |||
- | Parameter: | ||
- | idx: Index eines Arguments der aufrufenden Funktion\\ | ||
- | |||
- | Rückgabewert: | ||
- | Argument mit dem Index idx\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Die Funktion prüft die Gültigkeit des in idx übergebenen Wertes.\\ | ||
- | |||
- | Beispiel:\\ | ||
- | <code cpp> | ||
- | /* using functions argcnt() and arg(idx) */ | ||
- | |||
- | |||
- | f(x; | ||
- | { | ||
- | n = argcnt(); | ||
- | | ||
- | for (i=0; | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | main() | ||
- | { | ||
- | | ||
- | /* should print | ||
- | 3 arguments : | ||
- | 1 3 test | ||
- | --- | ||
- | 1 | ||
- | */ | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | === Funktion getargs: === | ||
- | |||
- | vector getargs()\\ | ||
- | Die Funktion liefert einen Vektor mit allen beim Aufruf von BOB+ übergebenen | ||
- | Kommandozeilenargumenten zurück. Dabei ist das Element mit dem Index 0 der Name des | ||
- | ausgeführten Programms (i.a. also BP.EXE oder BPR.EXE).\\ | ||
- | |||
- | Rückgabewert: | ||
- | Vektor mit allen Kommandozeilenargumenten\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Der zurückgelieferte Vektor sollte mit free explizit freigegeben werden.\\ | ||
- | |||
- | |||
- | === Funktion getusrargs: === | ||
- | |||
- | vector getusrargs()\\ | ||
- | Die Funktion liefert einen Vektor mit allen beim Aufruf übergebenen Benutzer-Argumenten zurück. | ||
- | Dabei ist das Element mit dem Index 0 das erste Kommandozeilenargument, | ||
- | Kennzeichen # angegeben wurde.\\ | ||
- | |||
- | Rückgabewert: | ||
- | Vektor mit allen Benutzer-Argumenten\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Der zurückgelieferte Vektor sollte mit free explizit freigegeben werden. Er kann leer | ||
- | sein, wenn keine benutzerdefinierten Argumente angegeben wurden.\\ | ||
- | |||
- | Beispiel:\\ | ||
- | <code cpp> | ||
- | /* using functions getargs() and getusrargs() */ | ||
- | main(; | ||
- | { | ||
- | vec1 = getargs(); | ||
- | vec2 = getusrargs(); | ||
- | | ||
- | n = vecsize(vec1); | ||
- | for (i=0; | ||
- | print(vec1[i]," | ||
- | | ||
- | n = vecsize(vec2); | ||
- | for (i=0; | ||
- | print(vec2[i]," | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | === Funktion rand: === | ||
- | |||
- | int rand()\\ | ||
- | Die Funktion berechnet eine Pseudo-Zufallszahl. Sie verhält sich wie die gleichnamige C-Funktion.\\ | ||
- | |||
- | Rückgabewert: | ||
- | Zufallszahl zwischen 0 und 0x7FFF\\ | ||
- | |||
- | Hinweis:\\ | ||
- | Bei mehreren Aufrufen der Funktion ergibt sich eine annähernd gleichverteilte | ||
- | Zufallsfolge, | ||
- | Initialisierung des Zufallsgenerators (vgl. Funktion srand) wird nach dem Programmstart | ||
- | immer die gleiche Folge generiert.\\ | ||
- | |||
- | |||
- | === Funktion srand: === | ||
- | |||
- | void srand(int seed)\\ | ||
- | Die initialisiert den internen Zufallsgenerator mit dem Wert seed. Sie verhält sich wie die | ||
- | gleichnamige C-Funktion.\\ | ||
- | |||
- | Parameter: | ||
- | seed: Initialwert für den Zufallsgenerator\\ | ||
- | |||
- | Hiweis:\\ | ||
- | Beim Programmstart wird der Zufallsgenerator implizit mit dem Wert 1 initialisiert. | ||
- | Um tatsächlich „zufällige Zufallsfolgen“ zu erhalten, ist eine Initialisierung mit einem | ||
- | zeitabhängigen Wert üblich.\\ | ||
- | |||
- | Beispiel:\\ | ||
- | <code cpp> | ||
- | /* random number generator example */ | ||
- | main() | ||
- | { | ||
- | | ||
- | { | ||
- | seed = timer(); | ||
- | srand(seed); | ||
- | print(“initial value: “, | ||
- | for (i=0; | ||
- | { | ||
- | for (j=0; | ||
- | print(rand(), | ||
- | | ||
- | } | ||
- | } | ||
- | } | ||
- | |||
- | </ | ||
- | |||
- | |||
- | |||
- | === Funktion compile: === | ||
- | |||
- | '' | ||
- | |||
- | Die Funktion bindet zur Laufzeit Quellcode in das aktuelle Programm ein. Die durch // | ||
- | spezifizertee Datei wird gelesen und in Bytecode übersetzt.\\ | ||
- | |||
- | Rückgabewert: | ||
- | 1 bei Erfolg, sonst 0\\ | ||
- | Dabei bedeutet „Erfolg“ das erfolgreiche Übersetzen der Quelle in Bytecode.\\ | ||
- | |||
- | Hinweise:\\ | ||
- | Die Funktion unterscheidet sich grundsätzlich von include-Anweisungen anderer | ||
- | Programmiersprachen. Der in filename enthaltene Code wird nicht zur Übersetzungssondern | ||
- | zur Laufzeit eingebunden.\\ | ||
- | Der Aufruf von '' | ||
- | möglich ist. Die Einbindung der übersetzten Quellcodes erfolgt immer in den globalen | ||
- | Kontext des Programms. Bereits vorhandene gleichnamige Symbole (Bezeichner) werden | ||
- | dabei durch die neuen ersetzt. Diese Eigenschaft lässt sich verwenden, um z.B. abhängig | ||
- | von Bedingungen bestimmte Funktionen zur Laufzeit auszutauschen, | ||
- | verwendenden Clientcode ändern zu müssen.\\ | ||
- | |||
- | Achtung: Diese Funktion ist in den Laufzeitumgebungen der Version 1.1 nicht verfügbar! | ||
- | |||
- | Beispiel:\\ | ||
- | <code cpp> | ||
- | /* using compile() example – main module */ | ||
- | testfunc(n) | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | main() | ||
- | { | ||
- | | ||
- | if (compile(„tstfunc.bp“)) | ||
- | testfunc(“Hello World“); | ||
- | } | ||
- | |||
- | /* using compile() example – module tstfunc.bp */ | ||
- | testfunc(n) | ||
- | { | ||
- | | ||
- | } | ||
- | |||
- | |||
- | </ | ||
- | |||
- | |||
- | === Funktion loadmodule: === | ||
- | |||
- | int loadmodule(string filename)\\ | ||
- | Die Funktion bindet zur Laufzeit ein bereits vorkompiliertes Bytecode-Modul in das aktuelle | ||
- | Programm ein.\\ | ||
- | |||
- | Rückgabewert: | ||
- | 1 bei Erfolg, sonst 0\\ | ||
- | Dabei bedeutet „Erfolg“ das erfolgreiche Lesen des Bytecodes.\\ | ||
- | |||
- | Hinweise:\\ | ||
- | Die Funktion unterscheidet sich von der Verarbeitungsanweisung #use insofern, als der in | ||
- | filename enthaltene Bytecode nicht zur Übersetzungs- sondern zur Laufzeit eingebunden | ||
- | wird.\\ | ||
- | Der Aufruf von loadmodule kann an jeder beliebigen Stelle erfolgen, an der ein | ||
- | Funktionsaufruf möglich ist. Die Einbindung des geladenen Bytecodes erfolgt immer in den | ||
- | globalen Kontext des Programms. Bereits vorhandene gleichnamige Symbole (Bezeichner) | ||
- | werden dabei durch die neuen ersetzt. Diese Eigenschaft lässt sich verwenden, um z.B. | ||
- | abhängig von Bedingungen bestimmte Funktionen zur Laufzeit auszutauschen, | ||
- | verwendenden Clientcode ändern zu müssen.\\ | ||
- | |||
- | |||
- | |||
- | |||
- | ===== 13 Erweitern von BOB+ mit dynamischen Bibliotheken ===== | ||
- | |||
- | Der Satz an vordefinierten Funktionen, den BOB+ bereitstellt, | ||
- | |||
- | Wie schon erwähnt ist es mit den von BOB+ bereitgestellten Mitteln möglich, nahezu jede benötigte Funktion selbst zu implementieren. Wenn es allerdings auf | ||
- | * hohe Ausführungsgeschwindigkeit, | ||
- | * direkte Zugriffe auf Betriebssystem und/oder Hardware bzw. | ||
- | * besonders niedrigen Platzbedarf | ||
- | |||
- | ankommt, ist es wünschenswert, | ||
- | |||
- | Mit Version 1.1 unterstützt BOB+ deshalb ein Konzept // | ||
- | |||
- | Dynamische Bibliotheken lassen sich zur Laufzeit laden und auch wieder entladen. Sie benötigen demnach nur so lange Speicherlatz, | ||
- | |||
- | |||
- | |||
- | ==== 13.1 Entwickeln von dynamischen Bibliotheken für BOB+ ==== | ||
- | |||
- | Eine DLL wird zunächst einmal wie ein ganz normales Programm geschrieben, | ||
- | * eine Exporttabelle | ||
- | * eine Registrierungsstruktur | ||
- | * eine spezielle Einsprung-Funktion | ||
- | |||
- | Für das Erstellen von DLLs in (Turbo-/ | ||
- | |||
- | // | ||
- | Anders als in [4] beschrieben, | ||
- | |||
- | Im Folgenden wird die Implementierung einer DLL in C++ und Assembler((Hier wird der Assembler A86 (Version 3.22) verwendet.)) demonstriert. Die Beispielbibliothek soll den Namen SYSTEM.EXE((Die Erweiterung kann im Prinzip beliebig gewählt werden, naheliegender wäre möglicherweise .DLL . Die Turbo-/ | ||
- | * '' | ||
- | * '' | ||
- | * '' | ||
- | * '' | ||
- | |||
- | Die Wahl der Signaturen der exportierten Funktionen ist dabei nicht beliebig. BOB+ stellt mit der Standardfunktion '' | ||
- | * Argumente sind 32 Bit breite Ganz- bzw. Realzahlen oder FAR-Zeiger. | ||
- | * Der Rückgabewert einer DLL-Funktion ist immer eine 32 Bit breite Ganzzahl. | ||
- | |||
- | In der Praxis bedeutet dies keine Einschränkung, | ||
- | |||
- | |||
- | === 13.1.1 Implementierung in Turbo-C/C++ === | ||
- | |||
- | Die Implementierung in C/C++ nutzt die durch den Header '' | ||
- | |||
- | <code cpp> | ||
- | #define _NOFLOAT_ | ||
- | |||
- | #include < | ||
- | #include < | ||
- | #include < | ||
- | #include < | ||
- | #include < | ||
- | #include < | ||
- | #include " | ||
- | |||
- | long huge getLastError(long size,char* errBuf) | ||
- | { | ||
- | strncpy(errBuf, | ||
- | return 0; | ||
- | } | ||
- | |||
- | long huge execProgram(const char* cmd, const char* cmdArgs) | ||
- | { | ||
- | return (long) Spawn((char*)cmd, | ||
- | } | ||
- | |||
- | long huge getEnv(const char* name, long size, char* buf) | ||
- | { | ||
- | |||
- | long result = 0; | ||
- | const char* pvar = getenv(name); | ||
- | if (pvar != 0) | ||
- | { | ||
- | result = strlen(pvar); | ||
- | if (buf != 0) | ||
- | strncpy(buf, | ||
- | } | ||
- | return result; | ||
- | } | ||
- | |||
- | long huge searchPath(const char* name, long size, char* buf) | ||
- | { | ||
- | long result = 0; | ||
- | | ||
- | if (pvar != 0) | ||
- | { | ||
- | result = strlen(pvar); | ||
- | if (buf != 0) | ||
- | strncpy(buf, | ||
- | } | ||
- | return result; | ||
- | } | ||
- | |||
- | BEGIN_EXPTABLE | ||
- | EXPENTRY(execProgram), | ||
- | EXPENTRY(getLastError), | ||
- | EXPENTRY(getEnv), | ||
- | EXPENTRY(searchPath), | ||
- | END_EXPTABLE | ||
- | |||
- | IMPLEMENT_DEFAULT_ENTRYFUNC_ENV | ||
- | |||
- | REGISTERENTRYFUNC | ||
- | |||
- | #if __TURBOC__ >= 0x0300 | ||
- | static char dummybuf[255]; | ||
- | #endif | ||
- | |||
- | |||
- | int main(int, | ||
- | { | ||
- | puts(" | ||
- | return 1; | ||
- | } | ||
- | </ | ||
- | |||
- | Die '' | ||
- | |||
- | Mit den ''# | ||
- | |||
- | Die exportierten Funktionen selbst sind wenig spektakulär und machen im wesentlichen von vorhandenen Bibliotheksfunktionen Gebrauch. Ein paar Anmerkungen scheinen dennoch angebracht: | ||
- | |||
- | * Die '' | ||
- | * Die Funktionen '' | ||
- | * Die Funktion '' | ||
- | |||
- | |||
- | Auf die Implementierung der eigentlichen Funktionen folgt die der DLL-Schnittstelle mit Hilfe von Makros, die //**genau in der hier angegebenen Reihenfolge**// | ||
- | |||
- | * Zunächst wird mit die Exporttabelle mit Hilfe von '' | ||
- | * Das Makro '' | ||
- | * Mit dem Makro '' | ||
- | |||
- | Was nun folgt, ist eine Verbeugung vor den 3.x-Versionen von Borland C++. Es wird ein statischer Datenbereich angelegt, der notwendig ist, um die Funktion der Standard-I/ | ||
- | |||
- | Die '' | ||
- | |||
- | |||
- | |||
- | === 13.1.2 Implementierung in Assembler === | ||
- | |||
- | Die Assembler-Variante der DLL kann weder die C-Standardbibliothek noch vordefinierte Makros zur Implementierung der DLL-Schnittstelle benutzen – hier ist Handarbeit angesagt. Dem entsprechend ist der Quellcode der Assembler-Version auch wesentlich länger((Deshalb werden hier auch nur einige Auszüge angegeben. Die vollständigen Quellen liegen der BOB+-Distribution bei.)) – dafür wird man aber durch eine wesentlich kleinere DLL entschädigt. | ||
- | |||
- | Auch die Assembler-Version muss eine Datei im EXE-Format sein und mindestens ein Code- und ein Datensegment besitzen. Ein eigenes Stack-Segment ist dagegen nicht unbedingt erforderlich, | ||
- | |||
- | Im Datensegment sind – wie nachfolgend gezeigt – mindestens | ||
- | * die Namen der exportierten Funktionen, | ||
- | * die Exporttabelle sowie | ||
- | * die Registrierungsstruktur der Tabelle | ||
- | |||
- | zu definieren. Unser Beispiel verwendet zusätzlich noch ein paar Zeichenketten zur Meldungsausgabe, | ||
- | |||
- | <code asm> | ||
- | ; data segment | ||
- | DSEG SEGMENT ' | ||
- | ; some messages | ||
- | msg DB " | ||
- | msg1 DB "Error messages not supported.", | ||
- | pathbuffer DB 256 DUP (0) | ||
- | pathvar DB " | ||
- | |||
- | ;Pointers to C Functions exported by main program | ||
- | pGetMem DW 0, 0 | ||
- | pFreeMem DW 0, 0 | ||
- | pSpawn DW 0, 0 | ||
- | |||
- | ;names of exported functions | ||
- | fname0 DB ' | ||
- | fname1 DB ' | ||
- | fname2 DB ' | ||
- | fname3 DB ' | ||
- | fname4 DB " | ||
- | |||
- | ;export table | ||
- | ; each entry consists of far pointer to name followed by far pointer to function | ||
- | ; | ||
- | funcEntry0 DW OFFSET fname0 | ||
- | DW SEG DSEG | ||
- | DW execProgram | ||
- | DW SEG CSEG | ||
- | ; | ||
- | funcEntry1 DW OFFSET fname1 | ||
- | DW SEG DSEG | ||
- | DW getLastError | ||
- | DW SEG CSEG | ||
- | ; | ||
- | funcEntry2 DW OFFSET fname2 | ||
- | DW SEG DSEG | ||
- | DW getEnv | ||
- | DW SEG CSEG | ||
- | ; | ||
- | funcEntry3 DW OFFSET fname3 | ||
- | DW SEG DSEG | ||
- | DW searchPath | ||
- | DW SEG CSEG | ||
- | ; | ||
- | funcEntry4 DW OFFSET fname4 | ||
- | DW SEG DSEG | ||
- | DW searchEnv | ||
- | DW SEG CSEG | ||
- | |||
- | ; | ||
- | regTag DB ' | ||
- | oEntryFunc DW OFFSET entryFunc | ||
- | sEntryFunc DW SEG CSEG ; segment of entry point function | ||
- | oEntryArray DW funcEntry0 | ||
- | sEntryArray DW SEG DSEG | ||
- | entryCnt | ||
- | |||
- | DSEG ENDS | ||
- | </ | ||
- | |||
- | Die einzelnen Einträge der Exporttabelle bestehen jeweils aus einem FAR-Zeiger auf den exportierten Funktionsnamen, | ||
- | |||
- | Die Registrierungsstruktur beginnt immer mit einem festen Tag in Form der Zeichenfolge „D_O_S_L_I_B0“. Nach dieser Zeichenfolge sucht die DLL-Laderoutine, | ||
- | |||
- | **Schreiben von Funktionen** | ||
- | |||
- | Alle aus DLLs exportierten Funktionen sind FAR-Funktionen, | ||
- | * die Rücksprungadresse ist 32 Bit breit, | ||
- | * die Funktionsargumente werden in umgekehrter Reihenfolge auf den Stack gelegt, also das letzte zuerst und | ||
- | * der Aufrufer ist für die Bereinigung des Stacks zuständig. | ||
- | |||
- | Zusätzlich gilt – wie schon erwähnt – die Festlegung, dass alle Argumente mit 32 Bit Breite übergeben werden. Demnach sieht der Stack unmittelbar nach dem Eintritt in eine Funktion wie folgt aus: | ||
- | |||
- | < | ||
- | | | | ||
- | | Offset Argument n | | ||
- | +-----------------------------+-- SP + 4n | ||
- | | | | ||
- | | | | ||
- | | | ||
- | | | ||
- | | | ||
- | | | | ||
- | | Offset Argument 2 | | ||
- | +-----------------------------+-- SP + 8 | ||
- | | | ||
- | +-----------------------------+ | ||
- | | Offset Argument 1 | | ||
- | +-----------------------------+-- SP + 4 | ||
- | | Segment Rückssprungadresse | ||
- | +-----------------------------+ | ||
- | | Offset Rücksprungadresse | ||
- | +-----------------------------+-- SP | ||
- | | | | ||
- | </ | ||
- | **Abbildung: | ||
- | |||
- | Eine von einer DLL bereitgestellte Funktion sollte alle Register, die sie verwendet (mit Ausnahme der allgemeinen Register AX, BX, CX und DX) zwischenspeichern und am Ende wiederherstellen. | ||
- | |||
- | Die Rückgabe des Funktionswertes erfolgt immer im Registerpaar DX:AX, wobei DX das höherwertige und AX das niederwerige Wort enthält. | ||
- | |||
- | Nachfolgend sollen die Eintrittsfunktion der DLL ('' | ||
- | |||
- | **Die Eintrittsfunktion: | ||
- | |||
- | Diese Funktion wird automatisch aufgerufen, wenn die DLL in den Prozess geladen wird((Genau genommen wird sie auch beim Entladen der DLL sowie bei jeder Änderung der Anzahl bestehender Referenzen aufgerufen. Dies spielt im Beispiel jedoch keine Rolle.)).\\ Zunächst der Quelltext: | ||
- | |||
- | <code asm> | ||
- | ; Entry point function | ||
- | ; void __DllEntry(int mode, DLLGLOBSTRUCT* pGlobals) | ||
- | entryFunc PROC FAR | ||
- | PUSH BP ; save BP | ||
- | MOV BP, SP | ||
- | PUSH ES ; save segment registers | ||
- | PUSH DS | ||
- | MOV AX, SS: | ||
- | CMP AX, DllModeLoad | ||
- | JNE endEntryFunc | ||
- | MOV AX, DSEG ; make DS and ES pointing to DSEG | ||
- | MOV ES, AX | ||
- | MOV DS, AX | ||
- | MOV DI, OFFSET pGetMem | ||
- | LDS SI, SS: | ||
- | MOV CX, 6 ; copy three function pointers (i.e. 6 words) | ||
- | CLD | ||
- | REP MOVSW | ||
- | endEntryFunc: | ||
- | POP DS | ||
- | POP ES | ||
- | POP BP ; restore BP | ||
- | RET | ||
- | entryFunc ENDP | ||
- | </ | ||
- | |||
- | Der Aufruf der Funktion erfolgt mit zwei Parametern. Der erste gibt den Aufrufmodus an, wobei hier nur der Modus '' | ||
- | |||
- | <code cpp> | ||
- | typedef void far* huge (*GetMemFunc)(unsigned long size); | ||
- | typedef void huge (*FreeMemFunc)(void far* block); | ||
- | typedef int huge (*SpawnFunc)(char far* cmd, char far* args); | ||
- | struct DLLGLOBSTRUCT | ||
- | { | ||
- | GetMemFunc huge GetMem; | ||
- | FreeMemFunc huge FreeMem; | ||
- | SpawnFunc huge Spawn; | ||
- | // more compiler specific variables may follow here | ||
- | // … | ||
- | }; | ||
- | </ | ||
- | |||
- | An dieser Stelle ist wichtig, dass die Struktur mit Zeigern auf drei Funktionen beginnt, die BOB+ für DLLs bereitstellt, | ||
- | |||
- | **Die Funktion execProgram: | ||
- | |||
- | Die Implementierung der Funktion ruft die von BOB+ bereitgestellte Funktion '' | ||
- | |||
- | <code asm> | ||
- | ; implementation of long execProgram(const char* cmd, const char* cmdArgs) | ||
- | ; we simply call Spawn function in main program | ||
- | execProgram PROC FAR | ||
- | PUSH DS | ||
- | PUSH BP | ||
- | MOV BP, SP | ||
- | MOV AX, DSEG | ||
- | MOV DS, AX | ||
- | PUSH SS: | ||
- | PUSH SS:[BP+12] | ||
- | PUSH SS:[BP+10] | ||
- | PUSH SS:[BP+8] | ||
- | CALL DWORD PTR DS: | ||
- | ADD SP, 8 ; remove arguments from stack | ||
- | POP BP | ||
- | POP DS | ||
- | | ||
- | | ||
- | execProgram ENDP | ||
- | </ | ||
- | Dabei muss sie selbst für die Einhaltung der C-Konventionen für den Funktionsaufruf sorgen.\\ Deshalb werden zunächst die Register DS und BP auf den Stack gerettet, dann die eigenen Funktionsargumente in umgekehrter Reihenfolge auf den Stack gelegt und anschließend die Rückruffunktion über den Zeiger '' | ||
- | Nach dem Aufruf werden mit dem Befehl '' | ||
- | |||
- | ==== 13.2 Verwenden dynamischer Bibliotheken ==== | ||
- | |||
- | Der direkte Weg zur Verwendung von dynamischen Bibliotheken besteht inder Benutzung der von BOB+ bereitgestellten Funktionen '' | ||
- | |||
- | <code cpp> | ||
- | main(; | ||
- | { | ||
- | | ||
- | // testdll will be handled directly | ||
- | // first load the library | ||
- | | ||
- | // assign address of sayHello function | ||
- | proc = GetProcAddress(hdll," | ||
- | // call function and print returned result | ||
- | | ||
- | // release library | ||
- | | ||
- | } | ||
- | </ | ||
- | |||
- | Die einzelnen Schritte sind also: | ||
- | * Laden der DLL | ||
- | * Bestimmen der Adresse einer exportierten Funktion in der DLL | ||
- | * Aufruf der Funktion | ||
- | * Freigeben der DLL | ||
- | |||
- | Dies ist im Vergleich zum Aufruf eingebauter Funktionen ein recht aufwendiges Verfahren. Zudem ist insbesondere der Aufruf der '' | ||
- | |||
- | Deshalb ist es ratsam, die Benutzung dynamischer Bibliotheken auf der Seite von BOB+ in Klassen zu kapseln und so die Details für den Anwendungsprogrammierer zu verbergen. Als Beispiel hierfür soll eine BOB+-Klasse „System“ dienen, die die Kapselung der unter [[software: | ||
- | |||
- | <code cpp> | ||
- | /** | ||
- | This class completely encapsulates using of SYSTEM.EXE library. This | ||
- | includes loading and unloading of library as soon as memory management, | ||
- | assignment of function pointers and calls to exported functions. | ||
- | */ | ||
- | class System | ||
- | { | ||
- | // method declarations | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | |||
- | // member variables | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | /** | ||
- | Constructor loads library, assigns function pointers and creates the result buffer. | ||
- | */ | ||
- | System:: | ||
- | { | ||
- | | ||
- | // We need not check hdll value since GetProcAddress returns null on | ||
- | // invalid handle. | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | /** | ||
- | Destructor frees result buffer and releases the library. | ||
- | */ | ||
- | System:: | ||
- | { | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | /** | ||
- | Method encapsulates call to execProgram library function. | ||
- | @param cmd name of program to execute (string) | ||
- | @param args command line arguments for program (string) | ||
- | @return return code of execution (or -1 on error) | ||
- | */ | ||
- | System:: | ||
- | { | ||
- | return CallLibFunc(execproc, | ||
- | } | ||
- | |||
- | /** | ||
- | Method encapsulates call to getEnv library function. | ||
- | @param name name of environment variable to get value from (string) | ||
- | @return value of environment variable (empty string if not found) | ||
- | @note If length of result exceeds 400 characters it is truncated. | ||
- | */ | ||
- | System:: | ||
- | { | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | /** | ||
- | Method encapsulates call to searchPath library function. | ||
- | @param name name of file to searchfor in PATH | ||
- | @return full file path if found, otherwise empty string | ||
- | */ | ||
- | System:: | ||
- | { | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | /** | ||
- | Method encapsulates call to getLastError library function. | ||
- | @return description of last error occurred in DLL | ||
- | @note Currently error description is supported only by C++ version | ||
- | of system library. | ||
- | */ | ||
- | System:: | ||
- | { | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | </ | ||
- | |||
- | Den wichtigsten Teil ihrer Arbeit erledigt diese Klasse im Konstruktor bzw. Destruktor. | ||
- | |||
- | Der Konstruktor übernimmt das Laden der Bibliothek, ermittelt die Adressen der benötigten DLL-Funktionen und weist sie an entsprechende Member-Variablen zu. Außerdem legt er einen internen Zeichenpuffer an, der für die Rückgabe von Ergebnissen der Funktionsaufrufe benötigt wird. | ||
- | |||
- | Der Destruktor sorgt bei der Zerstörung einer Objektinstanz der Klasse automatisch für die Freigabe des Puffers und der Bibliothek. | ||
- | |||
- | Die bereitgestellten Methoden schließlich sorgen für die korrekte Ausführung der '' | ||
- | |||
- | Entsprechend einfacher und übersichtlicher wird nun die Benutzung der Bibliothek im Anwendungsprogramm: | ||
- | <code cpp> | ||
- | // import precompiled System class | ||
- | #use " | ||
- | |||
- | main(; | ||
- | { | ||
- | // create instance of System class | ||
- | sys = new System(); | ||
- | // now execute system library directly | ||
- | // a message should be printed | ||
- | | ||
- | if (result < 0) | ||
- | { | ||
- | // on error print error message | ||
- | print(" | ||
- | } | ||
- | // ... and print result | ||
- | | ||
- | // get value of PATH environment variable | ||
- | s = sys-> | ||
- | // ... and print it | ||
- | | ||
- | // search for command.com and print its path | ||
- | | ||
- | // release system library | ||
- | | ||
- | } | ||
- | </ | ||
- | |||
- | In diesem Beispiel werden alle Funktionen der System-DLL aufgerufen. Der zusätzliche Aufwand reduziert sich hier auf das Anlegen und abschließende Freigeben der Variablen //sys//. | ||
- | |||
- | Eine Ergänzung ist noch im Zusammenhang mit der Verwendung dynamischer Bibliotheken bei knappen Speicherressourcen vonnöten: | ||
- | |||
- | Normalerweise benutzt BOB+ den //lokalen Heap// (der wegen des SMALL-Speichermodells immer kleiner als 64 KB ist) für Speicheranforderungen aus dem ausgeführten Programm. Für das Laden dynamischer Bibliotheken und Anforderungen dynamischen Speichers aus diesen Bibliotheken über die '' | ||
- | |||
- | |||
- | |||
- | |||
- | ===== 14 Quellen ===== | ||
- | [1] Bob-Source http:// | ||
- | [2] Betz, D. M.: Bob: A Tiny Object-Oriented Language.\\ | ||
- | In: Dr.Dobbs Journal, Sep. 1991, S.26ff. http:// | ||
- | [3] Neue Bob-Sourcen von D. M. Betz: XLISP HomePage, http:// | ||
- | [4] Ebert, R.-E.: DOS-DLL – Dynamische Bibliotheken für MS-DOS. Berlin 2007\\ | ||
- | http:// | ||
software/diy/andere/bob.txt · Zuletzt geändert: 26/12/2013 00:12 (Externe Bearbeitung)