Ich meine, das wäre nicht komplett hires, sondern gemischt.
Ich hatte es früher einmal durchgespielt und jetzt noch einmal angespielt. Es ist tatsächlich Hires-Bitmap (und an ein Multicolour-Endbild kann ich mich nicht erinnern).
You are about to leave Forum64 to get redirected to the following address:
Please note, that the target website is not operated by us. We are not responsible for it's content nor does our privacy policy apply there.
Ich meine, das wäre nicht komplett hires, sondern gemischt.
Ich hatte es früher einmal durchgespielt und jetzt noch einmal angespielt. Es ist tatsächlich Hires-Bitmap (und an ein Multicolour-Endbild kann ich mich nicht erinnern).
(Kann den obigen Post leider nicht mehr editieren)
- Portal
- Psi 5 Trading Company
- Stifflip & Co
- The Hobbit und andere Adventures wie Gremlins
- Cholo
- Stellar 7
Impossible Mission
Impossible Mission und schlechte Grafik? Ernsthaft?
"Elite" hat "simple" Vektorgrafik. Aus heutiger Sicht sicherlich "mies". Gilt auch für andere 3d-Spiele wie "Mercenary" oder "Cholo". Bei Adventures kann man über Grafikgeschmack auch schön streiten. Die Bilderkonvertierungen auf den C64 von "Transsylvania" und Co waren damals schon nicht sonderlich gelungen, obwohl noch immer besser als die kleinen HiRes-Bilder von Level-9 oder Scott Adams. Und wie sieht es aus mit den PETSCII-Grafiken von "Zauberschloss" und anderen Basic-Adventures? Hmm... Und gelten die Grafiken von "Ultima" oder "Wasteland" eigentlich als "gut"?
(verspätete Antwort... )
Viele Programme sind aber in Basic entstanden, weil die Leute keine Alternativen hatten (sich keine anderen Sprachen leisten wollten, sie damals noch nicht nicht gelernt hatten, keinen Overhead wollten wegen geringer Komplexität etc) und die haben tatsächlich in solchen Fällen z.B. die Integer-Arithmetik "gemeint" (wobei es auch andere solche Fälle "gemeinter" Semantik geben mag), und haben Basic V2 mit seinen diesbezüglichen Mangelerscheinungen eigentlich nur in Kauf genommen. Wenn die einen Compiler kriegen, mit dem ihre Programme schnell compiliert werden können, und dann tatsächlich in solchen Fällen auch viel schneller werden, und genau das tun, was die damals "gemeint" haben, ist das kein Problem, sondern eine Lösung. Es kommt halt immer auf das Motiv an.
Da hast Du völlig Recht. Es dürfte zahlreiche Basic-Programme geben, die von den Fließkommazahlen keinen Gebrauch gemacht haben. So kenne ich da einen komischen Typen (seinen Namen will ich nicht nennen, aber er schreibt hier im Forum gelegentlich so merkwürdige Posts), der hat damals[tm] ein Adventure in Basic geschrieben, und ich kann Dir versichern, daß ich im ganzen Programm garantiert keinen einzigen Fließkommawert verwendet habe. Zur Probe hatte ich das Adventure mal mit dem Austrocompiler übersetzt, was gefühlt Jahre brauchte, und das Ergebnis war tatsächlich ein wenig schneller, wenn auch nicht so viel wie erhofft. Grund u. a.: weiterhin langsame und unnötige Fließkommaberechnungen. Von daher kann ich nur zustimmen, daß es sicherlich Bedarf gab nach z. B. reinen Integer-Compilern.
Ich habe daher auch kein Problem mit diversen spezialisierten Compilern. Ich habe ein Problem damit, daß so getan wird, als würden sie Basic V2 übersetzen. Meines Erachtens wäre es sinnvoller gewesen, gleich offen ein Integer-Basic anzubieten so wie das erste Basic von Wozniak auf dem AppleII. Da wäre bereits die Interpreter-Ausführung während der Entwicklung schneller gewesen. Dazu kommt dann ein Compiler, der komplett auf Integer-Arithmetik aufbaut und entsprechend schnellen Code erzeugt. Und am besten gibt es noch ein paar Strukturelemente und Grafikbefehle gratis dazu. Das wäre mal eine Möglichkeit gewesen, in Basic auch kleine Actionspiele auf dem C64 zu programmieren. Und vielleicht hat es sowas auf dem C64 auch tatsächlich gegeben (darüber weiß ich zu wenig), aber die mir bekannten Compiler bauen alle auf dem Basic V2-Rom auf und tun so, als wären alle diese Basic-Varianten irgendwie Basic V2, was nicht stimmt.
Es ist leider so, wie Du schreibst: Die Leute hatten zu Basic V2 und Assembler auf dem C64 keine echte Alternative. "Pascal auf dem C64" fand ich z. B. ganz gut (hatte mir sogar das Buch gekauft). doch der Editor war m. M. n. zu kompliziert geraten und konnte nur kurze Textdateien editieren, was die Motivation, mal in Pascal ein Projekt zu entwickeln, arg dämpfte. Die anderen Pascal-Compiler kannte ich nicht. Was ich aber bisher von Peter so gesehen habe, war auch nicht sehr ermunternd. Da wäre ein echtes alternatives Basic sinnvoll gewesen, hat es aber anscheinend nicht gegeben, was ich im Nachhinein dann schade finde. (Im C64-Wiki finde ich nur eine Reihe von Basic V2-Erweiterungen, aber keinen vollständigen Ersatz, bin aber kein Basic-Experte. Falls jemand mehr weiß, bitte um Mitteilung.)
die ganzen theoretischen Erklärungen haben auch andere Themen wie z.B. Entscheidbarkeit ((Wann) kann man mit einer Grammatik entscheiden, ob ein gegebenes Programm der Grammatik entspricht? Welche Grammatiken sind überhaupt entscheidbar? Und so weiter), wofür man das entsprechende theoretische Handwerkszeug braucht (und die zitierten "Formeln" nunmal die ersten Schritte davon sind)
Du sagst es: andere Themen. Das Thema des Buches ist aber "Compilerbau" und nicht "Grammatiken".
Stell Dir vor, Du kaufst ein Buch zum Thema "Porträtmalen", und die ersten hundert Seiten beschäftigen sich allein mit netten Theorien zu solchen Sachen wie Farbkreis, Komplementärfarbe, Farbempfinden und Farbraum. Letzteres auch gerne mit diversen mathematischen Umrechnungsverfahren. Alles Sachen, die irgendwie mit dem Malen zu tun haben, aber für das Porträtmalen nicht wirklich relevant sind. Würdest Du Dich da nicht verschaukelt vorkommen?
Ich habe hier noch ein weiteres Compilerbuch als PDF vorliegen: "Basics of Compiler Design". Die ersten 100 von 300 Seiten widmen sich einzig der lexikalischen und der syntaktischen Analyse. Das Kapitel "machine code generation" hat dagegen mal gerade 10 Seiten. Es ist dieses Ungleichgewicht, was so fürchterlich nervt, besonders wenn man es in einer Vorlesung erlebt hat, die sich die ganze Zeit nur um den langweiligen trivialen Grammatikteil dreht, aber nie zum Wesentlichen vorstößt. Die ganzen Theorien zur Grammatik sind für einen üblichen Compiler einer üblichen Programmiersprache irrelevant. Da stehen ganz andere Themen im Vordergrund:
- Genereller Aufbau des Compilers (Frontend/Backend?)
- Gestaltung des Zwischencodes
- Gestaltung der Objekttabelle
- Identifikation von Bezeichnern
- Analyse eines Ausdrucks, Operatorenpriorität, constant folding, implizite Casts...
- Registerallokation
- Register spilling (insbesondere bei Funktionsaufrufen)
- Stackbehandlung
- Wann wird welche Optiminierung durchgeführt?
- Bei 1-Pass-Compilern: Patchen von Sprungadressen bei Vorwärtssprüngen
- Abbilden von Zwischencode auf die Zielsprache
usw. usf.
Ja, Informatik heißt nicht Programmieren, sondern beschäftigt sich (frei nach Wirth) mit "Algorithmen und Datenstrukturen". Aber gerade davon gibt es beim Compiler ausreichend genug, die einer ausgiebigen Behandlung bedürfen. Es gibt hingegen keinen einzigen Grund, Papier und Zeit mit unwichtigen Theorien zu Grammatiken zu verschwenden.
Eine gar nicht allzu schlechte (wenn auch sehr verkürzte) Einführung zum Thema Compiler (in dem Fall zu M-Code) hat die 64'er übrigens hier: https://archive.org/details/64er_1985_02/page/n38/mode/1up
Das ist eine gute Zusammenfassung von einigen Sachen, die hier bereits erwähnt wurden. Auf S. 39 unten rechts gibt es außerdem ein Beispiel für genau die Formel, die oobdoo in dem Buch gefunden hat. Zumindest sollte das Beispiel da stehen, aber irgendwie finde ich nur die erste Regel in der Backus-Naur-Form:
1. <Satz> ::= <Subjekt> <Prädikat>
entsprechend
1. <S> ::= <A> <B>
im Buch, aber die anderen beiden scheinen zu fehlen...?
Darf ich vorsichtig widersprechen?
Nein, auf keinen Fall! (
)
Wenn klar ist, dass das Ergebnis wieder ein Integer ist
Hier zitiere ich mal einen Berufeneren als mich (aus Post #100):
Und ich nehme weiterhin an, dass du davon ausgehst, man könne, sofern nur Integerzahlen an einer Berechnung beteiligt sind, auch immer mit Integer-Arithmetik rechnen. [...] Und das ist eben falsch. Der Interpreter wandelt alle Integer in Floats, rechnet und wandelt dann das Ergebnis zurück. Soll ein Compiler in allen Situationen zum Interpreter identische Ergebnisse liefern, dann muss er das in vielen Fällen auch tun. Einfach weil die Zwischenergebnisse größer oder kleiner als der 16-Bit-Integerbereich sein können und weil während der Rechnung nicht ganzzahlige Zwischenergebnisse vorkommen können und der Compiler zur Compilierzeit oft nicht entscheiden kann, ob das der Fall sein wird oder nicht. Klar, kann man alles ignorieren und so tun, als gäbe es das nicht. Aber dann hat man irgendwas compiliert und nicht mehr Commodore BASIC.
Das kommt halt drauf an, ob besagte Compilate dann stets völlig gleiche Resultate erzielen wie die interpretierten Programme, mit anderen Worten: ob sie semantisch äquivalent sind.
Genau das ist mein Argument: Viele "Basic"-Compiler erlauben Compileranweisungen oder andere Ergänzungen, wodurch das Kompilat sich extrem stark von einem herkömmlichen Commodore Basic-Code unterscheidet. Die verwendeten "Basic"-Dialekte sind eben nicht semantisch äquivalent zum Commodore Basic. Sie sind weder Fisch noch Fleisch, weder Basic noch eine brauchbare Hochsprache wie Pascal. Vielmehr heftet man diesen Mischmaschsprachen das Etikett "Basic" an, um den massiven Einfluß anderer Hochsprachen zu verschleiern, obgleich weder die Deklaration von Variablen mit ihrer Typisierung noch die Strukturelemente einer annehmenden oder abweisenden Schleife mit festem Sprungziel (dieses ebenso bei FOR-Schleifen) irgendwie Basic entsprechen.
Letztendlich komme ich immer wieder zur gleichen Schlußfolgerung: Wer eine strukturierte Programmiersprache haben möchte mit diversen Datentypen und angepaßten Operatoren, sollte eine Sprache nehmen, die diese Elemente bereits von Natur aus mitbringt. Wer hingegen einen Compiler haben will, der tatsächlich semantisch äquivalenten Code zu Commodore Basic ausgibt, sollte den MOSpeed von EgonOlsen71 verwenden.
Ähm? Die Diagramme sind doch die Grammatiken.
Ja, aber anschaulich dargestellt, wohingegen die von oobdoo erwähnten Formeln halt das typische mathematische Geblubber sind, das wichtig und bedeutsam wirken soll., aber im Grunde genommen trivial ist. Man kann die ganze Seite aus dem Buch rausreißen und würde beim praktischen Schreiben eines Compilers nichts vermissen.
Statische Arrays bringen also einen (etwas) einfacheren Compiler, (etwas) einfacherer Runtime und ein (etwas) schnelleren Code (da sich das Kompilat ein paar Lookups und Checks zur Dimensionierung des Arrays sparen kann), aber letztendlich macht's in Sachen Komplexität des Compilers den Braten nicht wirklich fett.
Umgekehrt wird ein Schuh draus. Statische Arrays sind, sofern man Optimierungen wie die Adreßberechnung vornimmt, komplexer. Mein Punkt war aber, daß Basic nicht vollständig kompiliert werden kann, sondern immer wieder Sprünge in Unterprogramme der Runtime-Bibliothek vornehmen muß, auch für Aktionen, die in anderen Hochsprachen keine Runtime benötigen. Das macht den Code nicht nur etwas langsamer, sondern reichlich langsamer, allein schon dadurch, daß die Parameter einer arraySet-Prozedur beim 6502 nicht in den 3 Registern übergeben werden können. Stattdessen muß man auf umständliche Methoden wie Übergabe in der Zeropage oder Übergabe als Konstanten im Code nach dem JSR-Befehl zurückgreifen, die auch noch den Code ziemlich aufblähen. Bei einem P-Code wäre es nicht ganz so schlimm, da die 3 Parameter im günstigen Fall nur 3 Bytes plus einem Byte für den Aufruf von arraySet brauchen. (Sofern die Elementgröße in dem Aufruf bereits enthalten ist. Ansonsten wäre noch ein Byte dafür nötig).
BTT Pascal-Compiler auf dem C64:
Ich habe mir mal das Profi-Pascal System angesehen. Es fällt auf, daß viele Fehlermeldungen mit den Fehlermeldungen des UCSD-Pascal-Compilers übereinstimmen. Auch der Bytecode-Interpreter funktioniert ähnlich wie der von ApplePascal, was die vergleichbare Ausführungszeit erklärt. Da außerdem Profi-Pascal ein eigenes Dateiformat verwendet, fragt man sich, inwieweit hier Verbindungen bestehen. Leider kenne ich die Version 1.3 von ApplePascal nicht (nur bis 1.2), so daß ich dies nicht beurteilen kann.
diese Formel
Genau das ist das Problem. Diesen ganzen Kram braucht man gar nicht, um einen Compiler zu schreiben. Es ist reines Theoriegelaber in bezug auf Grammatiken. Was Du wirklich brauchst, sind die von 1570 genannten Diagramme, die veranschaulichen, welche Elemente der Programmiersprache aufeinander folgen müssen bzw. dürfen.
Wenn z. B. die Anweisung "FOR" im Text auftaucht, geht aus dem Diagram für "statement" hervor, daß danach ein "variable identifier" kommen muß gefolgt wiederum von ":=", einer "expression" usw. Stell Dir einfach vor, daß der Compiler beim Übersetzen diesen Diagrammen Stück für Stück folgt. Er weiß dadurch immer, was für ein Element jetzt als Nächstes kommen muß, und kommt kein passendes, gibt er eine Fehlermeldung aus.
Dieser ganze Vorgang ist leicht als Programm umzusetzen, indem man für jedes Diagramm eine eigene Prozedur schreibt. Es gibt also eine Prozedur "statement" und auch "expression" sowie "factor" oder "variable" usw.
Allerdings mit einem Unterschied: In dem von 1570 verlinkten Diagrammen sieht man oben ein Diagramm für "identifier" und "unsigned integer" und ein paar andere mehr. Das Parsen von Zahlen oder allgemein Konstanten sowie von Bezeichnern und fest eingebauten Schlüsselwörtern würde man in ein eigenes Unterprogramm auslagern. Dieses hat die Aufgabe, aus einem Text ein abgeschlossenes Element (ein sogenanntes "Token") zu holen. Ein Token ist z. B. das Schlüsselwort "AND" oder "BEGIN" oder "PROCEDURE". Ein Token ist auch eine Zahl wie "1234" oder ein String wie 'Nur ein String'. Oder ein Operator aus einem oder mehreren Sonderzeichen wie "+", "-", "<<". Dazu kommen noch andere Elemente wie Klammern, Semikolon etc.
Die Routine weist nun jedem Token eine feste ID (= z. B. eine Nummer) zu, so daß der Compiler später einfach nur die ID überprüfen und keine eigenen Stringvergleiche (P..R..O..C..E..D..U..R..E... ah, Wort "PROCEDURE" gefunden...) durchführen muß.
Als Letztes werden auch alle vom Programmierer benutzten Bezeichner gesammelt und ihnen ebenfalls eine eigene Bezeichnernummer zugewiesen.
Diese Unterroutine holt also aus dem Sourcecode ein Token, und wenn es sich um einen Bezeichner handelt, gibt sie zusätzlich die Bezeichnernummer zurück. Wenn es sich um eine Konstante handelt (Zahl, Zeichen etc), wird auch noch der Wert der Konstanten zurückgegeben. Auf diese Weise kann man sich das Leben ein wenig einfacher machen.
Besonders in Hinblick auf Retrorechner hilft diese Unterroutine auch dabei, den Compiler zu beschleunigen und den Programmcode des Compilers zu minimieren, denn diese Unterroutine läßt sich gut in der Assemblersprache des Computers schreiben (Z80 und selbst 6502), wohingegen der Rest des Compilers auch auf P-Code basieren kann.
Danke, sieht interessant aus. Werde ich mir mal genauer anschauen.
Bevor Du das anschaust, klick Dich mal zur letzten Seite des Kurses durch und lies am Ende folgende Aussage:
QuoteSo far, I’ve been implementing a compiler and writing posts as I go. This system worked really well for a while, but now it’s starting to work less well; I realized that some decisions I made in earlier stages made this stage harder to complete, so I had to go back and change them. I think I’m likely to run into more problems like that in later posts. So I’m going to take a break, finish building the compiler (whatever I decide “finished” means), and then come back and write the rest of this series. I probably won’t post another update for six months. So basically…I’m going to keep posting at about the same rate I have been.
Da die letzte Veröffentlichung schon eine ganze Weile her ist, kann man davon ausgehen, daß der Kurs nicht weiterfortgeführt und auch nicht an die erwähnten neuen Erkenntnisse angepaßt wird. Er ist daher mit Vorsicht zu genießen und liefert auch nicht die Lösungen für die wirklich schweren Probleme.
das Buch von Wirth
Das Buch "Compiler Construction" von Wirth in der überarbeiteten Auflage von 2005 kann man sich in der englischen Ausgabe kostenlos im Internet herunterladen. Es behandelt als reales Beispiel die Übersetzung einer (umfangreichen) Untermenge der Sprache Oberon in Befehle für einen RISC-Prozessor. Der Compiler-Sourcecode dazu ist ebenfalls frei erhältlich. Diese zusammen böten prinzipiell ein gutes Anschauungsmaterial, wenn Wirth nicht die Eigenschaft hätte, seinen Code nur äußerst spartanisch zu kommentieren, kryptische Variablennamen zu verwenden und mehrere Befehle in eine Zeile zu quetschen, um nachher sagen zu können: Schaut her, ich habe den kürzesten und kompaktesten Compiler... Mit anderen Worten: Wirth beweist, daß man auch in seiner Sprache schlecht lesbaren Code schreiben kann.
Mein "Problem" mit den meisten Büchern zum Thema (und auch Vorlesungen an der Uni damals) ist, dass sie sich in Grammatiken, Parser und Lexer ergehen und die Codegenerierung oft nur als "Ja, gibt es auch noch...ist aber trivial, das kann jeder Depp" abtun.
Dies entspricht leider auch meiner Erfahrung. Die genannten Bücher habe ich mir damals[tm] ebenfalls angesehen und auch eine Vorlesung zum Thema besucht, die aber nicht über den Lexer/Scanner hinausgekommen ist. Dabei ist es genau umgekehrt: Das vollständige, reine Parsen eines Programms mit Test auf syntaktische Korrektheit (= Frontend) ist trivial. Die Codeerzeugung hingegen äußerst kompliziert, und man wird das Gefühl nicht los, daß die verantwortlichen Lehrenden sich gerne darum herumdrücken. Mein Fazit am Ende war: Vergiß die Literatur und mach es selber frei nach dem Motto "Learning by doing". Letztlich ist ein Compiler auch nur ein Programm, d. h. man geht in der Entwicklung genau so vor wie bei anderen Programmen auch. Zuallererst muß man wissen, was man überhaupt will. Aus "Ich möchte irgendwie ein Spiel schreiben mit irgendeiner Figur, die irgendwas macht." wird ja auch nie ein fertiges Spiel. Falls Du, ogd, also Interesse daran hast, einen eigenen Compiler zu schreiben, solltest Du zunächst die folgenden Fragen beanworten:
1.) Auf welchem Computer soll der fertige Compiler laufen? PC oder C64? Dies bestimmt von vornherein den Umfang des Compilers (z. B. mögliche Codeoptimierungen) und die Vorgehensweise: direkte Übersetzung ohne Zwischencode (sehr wenig Speicherverbrauch) <=> Zwischencode für Prozeduren/Funktionen (geringfügiger Speicherverbrauch, teilweise Optimierungen möglich) <=> Zwischencode für das ganze Programm (immenser Speicherverbrauch, auf Retrorechnern nicht zu erreichen).
2.) Wie sieht die Quellsprache aus? Ist sie Pascalartig? Herzlichen Glückwunsch. Einen Compiler für eine solche Sprache zu erstellen, ist einigermaßen realistisch, Handelt es sich um Basic? Dann kommt man schnell an die Grenzen der Kompilierbarkeit, denn Basic verwendet zu viele Elemente, die erst während der Laufzeit entschieden werden können, und eignet sich daher von vornherein nicht gut als Sprache zum Kompilieren.
Die Wahl der Quellsprache bestimmt auch, wie kompliziert das Parsen ausfällt: Kann ein Programmtext in einem Durchlauf geparst werden oder braucht man mehr als einen Durchgang? Hierbei muß man unterscheiden in zusätzliche Durchgänge, um Programmadressen (z. B. für Sprünge) zu ermitteln. Dies kannmit Hilfe des Zwischencodes durchgeführt werden. Oder handelt es sich um Deklarationen, bei denen die Verwendung eines Bezeichners vor der Deklaration stattfinden kann? Dieser Fall ist schwer zu behandeln. Beispiel:
Der Compiler müßte in Zeile 100 einen Fehler ausspucken, da auf ein Element 50 zugegriffen werden soll, jedoch im späteren Programmcode nur ein Feld mit 41 Elementen erzeugt wird.
Besonders lustig wird es in Basic bei folgendem Code:
Damit sich solche Scherze nicht auswirken auf "normalen" Basiccode, in dem ein Array nur einmal dimensioniert wird mit einer Konstanten, muß man im Compiler einige Verrenkungen vornehmen.
3.) Wie lautet die Zielsprache? Wird in P-Code kompiliert? Das wäre relativ einfach. Assembler hingegen ist recht schwierig, weil z. B. die 8 Bit-Prozessoren nicht über die Adressierungsarten verfügen, die man für ein Hochsprachenprogramm benötigt.
4.) Soll Zwischencode verwendet werden und falls ja, wie sieht dieser aus? Üblicherweise nimmt man entweder einen Code für eine Stackmaschine, die dann bereits dem auszuwerfenden P-Code nahekommt, oder man verwendet eine 3-Adreß-Codierung (aufwendig). Letztere erlaubt einige Optimierungen am Code, ist aber schwerer in der Handhabung. Stackmaschinen-Befehle lassen sich hingegen auch relativ leicht auf eine Registermaschine übertragen (vorausgesetzt man unterscheidet zwischen Evaluationsstack und Datenstack), erzeugen aber keinen optimalen Code.
Solltest Du am Anfang noch keine Ahnung haben, wie der Compiler intern aufgebaut sein soll (Unterscheidung Frontend - Backend? Welcher Zwischencode? etc), folge einfach den Ratschlägen von EgonOlsen71:
1.) Schreib ein Programm in der Programmiersprache Deiner Wahl auf dem PC, welches einen Programmtext in Deiner Quellsprache akzeptiert.
2.) Schreib darauf aufbauend einen Interpreter für Deine Sprache. Dabei lernt man mit Variablenadressen umzugehen, Bezeichnerdeklarationen umzusetzen, Stackallokationen durchzuführen usw. (Hinweis: Es ist relativ leicht, einen Interpreter für Pascal zu schreiben, wenn man zusätzlich ein Flag definiert, welches festhält, ob ein Code ausgeführt werden darf. Zwar wird hierbei auch nicht auszuführender Code wiederholt geparst (= übersprungen), doch war selbst damals[tm] auf meinem Amiga1200 die Ausführungsgeschwindigkeit eines alten Pascal-Programms aus Schulzeiten schneller als original auf dem AppleII.)
3.) Schreib einen Codegenerator auf Basis des Interpreters. Vom Interpreter zum Compiler ist es nur ein kleiner Schritt.
4.) Schreib Deinen Compiler neu in der Quellsprache und übersetze ihn mit sich selber. Wenn das dadurch entstandene Kompilat sich nicht vom Vorgänger unterscheidet, darfst Du Dir gratulieren. Du hast einen self-hosting Compiler geschrieben.
Kurz gesagt: Viel Spaß!
Dem UCSD die source von TP vorsetzen hat leider nicht geklappt.. BAD SOURCE FILE ERROR
Da ist guter Rat teuer. Da es sich wahrscheinlich trotz des Namens nicht um echtes UCSD-Pascal handelt, ist völlig offen, welches Textformat der Compiler erwartet. Es könnte sich um irgendwas mit Basic-Zeilen handeln genauso wie eine Textdatei. Nun könnte man versuchen festzustellen, nur um sicherzugehen, ob eine UCSD-Textdatei kompiliert werden kann, habe aber - wie gesagt - keine große Hoffnung. Angesichts der Tatsache, daß kein Editor beiliegt, würde ich eher darauf tippen, daß das Textformat auf Basic-Zeilen beruht. Aber dann bräuchte man ein System, wodurch bei der Eingabe verhindert wird, daß der Pascaltext in Basic-Token umgewandelt wird, was im Endeffekt bedeutet, daß jede Zeile mit einem REM beginnen müßte... Erscheint also auch nicht ganz stimmig.
Letztendlich braucht er die Klammern um den Zahlenvergleich in der inneren until Bedingung.
Die Klammern dort sind nach der Pascal-Sprachdefinition aufgrund der Auswertungspriorität auch notwendig, da hier bei "a > sz" ein Ausdruck rekursiv aufgerufen wird. Bei NOT hingegen sollten die Klammern weggelassen werden können. Genaueres zur Syntax findet sich z. B. in "Florian Matthes: Pascal auf dem C64" von Markt&Technik, Anhang A: Syntax-Diagramme Pascal 1.4, S. 198 unter "Faktor". Anhand der vier Diagramme "Faktor", "Term", "Einfacher Ausdruck" und "Ausdruck" läßt sich außerdem die Priorität in der Auswertung ablesen. Analog zu diesen vier Diagrammem würde normalerweise ein Compiler vier Parserroutinen verwenden, um einen Ausdruck zu übersetzen.
Was ich in dieser Hinsicht sehr schade und bedauernswert finde, ist, daß die Sourcecodes der Compiler (bis auf den von Florian Matthes) wohl für immer verloren gegangen sind. Es wäre interessant zu sehen, inwieweit sie sich unterscheiden oder aufeinander aufbauen. Der Compiler von Florian Matthes z. B. beruht wohl auf dem quelloffenen Compiler von Wirth aus den 70er Jahren wie auch der UCSD-Compiler. Es fragt sich daher, ob die anderen von Grund auf Neuentwicklungen sind oder ebenfalls aus einer gemeinsamen Quelle heraus entstanden sind.
Nebenbei: Ich habe mal das Pascalprogramm auf einem AppleII mit ApplePascal (= UCSD-Pascal) übersetzen und ausführen lassen. Ergebnis: ca. 34-35 Sekunden, wobei allerdings die Ausgabe auf die 80 Zeichenkarte sehr langsam ist. Man müßte mal einen Bytecodeinterpreter ähnlich dem von ApplePascal für den C64 schreiben um zu schauen, wie schnell das Programm dort ausgeführt wird. Die Wurzelroutinen von Tale-X konnte ich leider nicht einbauen, da ApplePascal - wie oben erwähnt - keinen Rechtsshift-Operator kennt.
Hatte ich schon Assembler erwähnt.. da muss ich auch nochmal ran.
Das wäre meine persönliche Empfehlung. Wenn Du Interesse daran hast, für den C64 zu programmieren, ist Assembler die Sprache der Wahl. (Gilt auch genauso für den AppleII oder den Atari800 als auch für die Z80-Rechner CPC, ZX Spectrum usw.) Wenn Du Dir das Leben erleichtern willst, greif dabei ruhig auf Crossassembler zurück wie ACME oder das C64Studio, d. h. Du schreibst Dein Programm auf dem PC, läßt es mit einem modernen Assembler auf dem PC übersetzen und führst es dann mittels VICE oder einem anderen Emulator auf dem PC aus. Damit erzielst Du am schnellsten Lernerfolge. Das Editieren und Assemblieren auf dem C64 selbst ist beim Erlernen nur hinderlich und verschwendet unnütz viel Zeit.
Tale-X: Vielen Dank fürs Austesten. Das Ergebnis überrascht ein wenig, da der Algorithmus ohne Division eigentlich schneller sein sollte. (Würde man beide Algorithmen in Assembler umsetzen, wäre dies auch definitiv der Fall.) Ich vermute jedoch, daß es daran scheitert, daß die Ausführung des p-Codes in der Schleife zu langsam ist. Bislang habe ich auch noch keinen Bytecode-Interpreter gesehen, der an die Geschwindigkeit von ApplePascal herankommt. Leider kann ich den Algorithmus unter ApplePascal nicht ausprobieren, da es dort den Operator >> nicht gibt.
Peter: Ich habe mal mittels Vice in den Compiler reingeschaut. Danach habe ich große Zweifel daran, daß es sich wirklich um einen UCSD-Compiler handelt. Vielleicht basiert der Compiler auf der ersten Version des UCSD-Compilers, die damals in den 70ern frei verteilt wurde. Aber der Bytecode-Interpreter funktioniert definitiv anders als der von ApplePascal (langsamer). Außerdem finden sich merkwürdigerweise deutsche Strings im Code, und bei $36eb findet sich sogar der Text "Austro - Comp". Sieht wirklich nicht nach UCSD aus.
Daß zu dem Compiler ein Editor fehlt, fiel mir auch auf. Das UCSD-System besteht ja aus mehreren Teilen, u. a. einem Texteditor, einem Linker (fehlt hier auch komplett), einem Assembler, einer Textdatei, welche die Strings für die Fehlermeldungen enthält (gibt es hier auch nicht), und noch einiges mehr. Über das Textformat, das der C64-Compiler akzeptiert, kann nur spekuliert werden. Ich gehe mal davon aus, daß es sich nicht um das gleiche handelt, das von ApplePascal verwendet wird. Übrigens: Die anderen Dateien auf der Diskette (, sofern welche vorhanden sein sollten,) gehören nicht zum Compiler. Vielleicht wäre eine Möglichkeit, einen Text mit dem Turbeo-Pascal-Editor zu erstellen, den Compiler damit zu füttern und zu schauen, was passiert.
Also ein Stück weit bin ich ja echt froh, dass die Basic-Compiler in den 80ern aber auch ALLE mit einem anderen Mindset geschrieben wurden.
Und es ist echt niemand dran gestorben!
Der Punkt ist, daß diese Compiler dann keine Compiler des Commodore Basic waren. Damit z. B. ein Prozentzeichen eine Integerverarbeitung bewirkt, muß die Sprachdefinition geändert werden, was einen neuen Basic-Dialekt produziert, der wieder einmal nicht kompatibel ist zu den vielen anderen. Leider ist der Name "Basic" nicht geschützt, und so kann jeder eine Sprache definieren, in der irgendwie die Befehle PRINT und GOTO vorkommen, und das Ganze dann "Basic" nennen, auch wenn es mit dem Ursprungsbasic oder dem Standardbasic auf dem Gerät (Commdore Basic V2 oder Locomotive Basic etc) nichts zu tun hat. Man kann natürlich das Sprachwirrwarr begrüßen, in dem jeder sein eigenes Süppchen kocht. Für einen Programmierer jedoch ist solch ein Zustand alles andere als angenehm, besonders wenn das Kompilat dann auch noch jeweils andere (Rechen)Ergebnisse liefert.
Kurz: Der Compiler von EgonOlsen71 kompiliert das Standard Basic des C64. Andere Compiler betreiben in dieser Hinsicht Etikettenschwindel, denn ihr Basic ist ein erfundener Dialekt.
Fakt ist, dass die Formelauswertung gegenüber dem Commodore-Basic neu geschrieben werden müsste.
Die Formelauswertung muß bei einem Compiler auf jeden Fall neu geschrieben werden, denn der Compiler wertet einen Ausdruck nicht aus (es sei denn er beherrscht zusätzlich das Constant-Folding), sondern übersetzt ihn.
Mich interessieren neue Programme, die mit den neuen Möglichkeiten eines neuen Basic-Compilers geschrieben werden könnten.
Wenn Du unbedingt in Basic mit Integerarithmetik programmieren willst, kannst Du ja auf Blitz-Basic etc zurückgreifen. Dort lassen sich Integervariablen definieren wie in Pascal usw. Meine Empfehlung ist dann aber, besser ganz auf den Basic-Kram zu verzichten und gleich eine Sprache zu nehmen, die all dies und noch mehr regulär mit sich bringt. Basic ist nun einmal eine Quick-and-Dirty-Sprache für Anfänger. Dazu gehört auch die bewußte Nichtunterscheidung zwischen Integer und Fließkomma. Mit jeder Änderung/Ergänzung der Semantik entfernt man sich immer weiter von Basic und dem Ursprungsgedanken der sehr leichten Programmierbarkeit von kleinen Programmen in Richtung auf ein minderwertiges Pascal. Von daher sehe ich persönlich keinen Sinn darin. Wenn ich an Basic denke, denke ich an die vielen kleinen Programme, die man früher (und auch heute dank ZeHa) in Zeitschriften und Büchern gefunden hat zum Abtippen. Nette Spielereien zum Zeitvertreib. Für alles, was darüber hinausgeht, gibt es Assembler oder eine Hochsprache wie Pascal oder C.
Ich hab das in einigen Game Sourcen schon öfters gesehen.
Könnte es sein, daß am Anfang des Hauptprogramms bzw. der Hauptschleife ein
steht? (So gesehen z. B. bei "Elite") Auch damit wird verhindert, daß der Stapelzeiger einen Überlauf bekommt.
dass die Implementierung von echter Integer-Arithmetik in einen Compiler ein Riesenaufwand ist
Ohm... nein.
Denn dazu muss man die gesammte Formelauswertung neu schreiben.
Nein. Es handelt sich um die gleichen Parserroutinen ((im Falle von Pascal sogar nur um vier Auswertungsebenen), und der zusätzliche Code darin ist überschaubar und übrigens genauso notwendig für Zeichen und Zeichenketten.
dass viele Compiler das nicht können
Integerarithmetik zu kompilieren ist einfacher als Fließkomma, und für die Fließkommazahlen muß man nicht auf die Basic-Rom-Routinen zurückgreifen, sondern kann auch ein eigenes Fließkommapaket verwenden, so wie UCSD-Pascal. Das hat den großen Vorteil, daß man das Basic-Rom ausblenden kann, was den zur Verfügung stehenden Speicher für das Programm erhöht.
Aber dass echte Integer-Arithmetik im Compiler keinen Sinn macht
Imtegerarithmetik macht dann keinen Sinn, wenn die Sprache sie nicht definiert. Im Commodore-Basic sind Integer-Operationen nicht vorgesehen. Es w#re daher ein großer Fehler, wenn ein Compiler von sich aus in den Code eingreifen und die Semantik verändern würde. Der Compiler weiß ja nicht, ob der Programmierer an dieser oder jener Stelle keine Fließkommaarithmetik benötigt. Das Ergänzen von "%" hilft da auch nicht weiter, denn das Prozentzeichen verändert laut Sprachdefinition nicht die Bedeutung der Operatoren, und für den Compilerbauer ist nur eines entscheidend: Wie lautet die Definition der Sprache? Möchte man als Programmierer mit Integerarithmetik arbeiten, sollte man zu einer vernünftigen Sprache wie Pascal greifen, die diese per Definition auch vorsieht.
Es heisst ja auch UCSD-Pascal.
Ja, sorry, Tipfehler. University of California, San Diego.
hast Du eine Idee, wie ich da dran komme?
Ich habe die C64-Version nie ausprobiert. Wäre nett, wenn es Dir gelänge und Du hier etwas dazu schreiben könntest.
aber das sind doch Sonderfälle, die ich vor jeder Division abprüfen muss.. Das IF kostet dann aber bei jedem Durchlauf Zeit.. wenn nicht gerade sehr viel x2 /2 gerechnet wird, sollte das doch langsamer werden.
Der Code enthält keine zusätzlichen IFs. Man ersetzt in den Fällen, wo ein vorzeichenloser Integerwert durch die Konstante 2 (oder ein Vielfaches von 2) geteilt wird, die Division im Code durch den Bitshift, also z. B.
Ich binde daher nen Screenshot ein
Vielen Dank. Kleine Frage; Sind die zusätzlichen Klammern bei WHILE, IF und NOT notwendig für den Pascaldialekt?
Meiner da oben braucht 15s, obwohl der ja nicht soooo viel anders ist.
Wenn ich das richtig verstanden habe, hat das "%" beim Variablennamen im normalen interpretierten Basic keine Auswirkung weder bei der Speicherung des Zahlenwertes noch bei der Verarbeitung. Könnte es aber sein, daß beim wiederholten Parsen des "%" mehr Zeit verloren geht?
Tale-X : Vor einiger Zeit habe ich im Internet folgenden Algorithmus zum Wurzelziehen bei Integers gefunden (ungeprüft!) :
Auch hier sollte man natürlich die Operationen " / 2 " und " / 4 " durch entsprechende Rechtshifts ersetzen und die Werte an 16 Bit anpassen. Unter Umständen könnte der Algorithmus schneller sein, da hier keine Division mehr verwendet wird.
Peter : Eine kleine Bitte: Wäre es vielleicht möglich, uns den Pascalcode zur Verfügung zu stellen? Ich würde mal gerne den Versuch machen, ihn zum Vergleich unter ApplePascal zum Laufen zu bringen. Vielen Dank!
Ich hab mich sehr dicht am C-Code gehalten und auch eine "eigene" SQRT-Routine (https://en.wikipedia.org/wiki/…ample_implementation_in_C) verwendet.
Hmm... Die sieht mir aber recht langsam aus, da in jedem Schritt weiterhin eine Division verwendet wird. Ich glaube, da gibt es für Integer wesentlich schnellere Verfahren.
Außerdem würde ich davon ausgehen, daß die damaligen Compiler schon aus Speicherplatzgründen keine optimierenden Compiler waren. Das bedeutet, daß eine Anweisung " / 2 " wahrscheinlich als eine vollständige Division durch 2 umgesetzt wird anstelle eines bitweisen Shiftens nach rechts um eine Stelle. Man müßte also schauen, ob der Pascaldialekt z. B. den Operator >> oder RSHIFT kennt, und diesen explizit verwenden.
Aber wo es isqrt gibt, hast Du mir noch nicht verraten.
Ob es in einem Pascaldialekt eine spezielle Wurzelroutine gibt für Integer, kann man daran erkennen, ob der Parameter der Routine SQRT sowohl Integer als auch Real als Datentyp akzeptiert und die Routine Rückgabewerte in diesen Datentypen ausgibt. Anhand des Datentypens des Parameters kann ja der Compiler zwei verschiedene Wurzelroutinen einbinden, so wie es auch für Multiplikation, Subtraktion oder bei der Ausgabefunktion WRITE geschieht. Vermutlich hat man es aber nicht gemacht, weil eine Wurzelroutine nur für Integer selten verwendet wird und ansonsten zu viel Platz im Speicher wegnimmt.
Kleine Anmerkung:
Für einen Vergleich zwischen verschiedenen Kompilaten sollte man besser auf eine Ausgabefunktion verzichten, da diese einen zu großen Einfluß hat auf die Gesamtgeschwindigkeit, jedoch vom Compiler nicht beeinflußbar ist. So könnte man vermuten, daß ApplePascal sehr langsam ist, weil die Ausgabe über die 80 Zeichenkarte oder die emulierte 80 Zeichenkarte abgewickelt wird, doch tatsächlich ist der eigentliche Bytecodeinterpreter recht schnell.
Peter: Es gibt ja auch einen USCD-Pascal-Compiler für den C64. Hast Du den schon ausprobiert?
Ich meine, du musst erst das "WORKFILE" festlegen. Existiert es, wird es geladen. Dann kannst du mit "C" compilieren.
Hab ich versucht. Funktioniert leider auch nicht.
bei mir funktioniert es, wenn ich die Frage nach sinngemäß "compile to EXE file" mit yes beantworte..
Bei mir funktioniert es nicht.
1.) Ich wähle C für Compile.
2.) Ich tippe den Namen ein der Datei, die übersetzt werden soll, z. B. grdemo,pas oder fatt.pas gefolgt von einem Return.
3.) Der Compiler wird geladen, was recht lange dauert. Dann erscheint ein blinkender Cursor am linken Rand, sonst nichts.
4.) Wenn ich jetzt wieder Return drücke, wird der Kompilationsprozeß gestartet, jedoch werden mehrere Fehler ausgegeben.
5.) Erst danach werde ich gefragt, ob ich eine EXE-Datei haben will, was aufgrund der vielen Fehlermeldungen eigentlich keinen Sinn macht.
6.) Tippe ich jetzt Y, wird der Bildschirm schwarz und der Rechner hängt sich auf.
Wo liegt der Fehler?
Kleiner Nachtrag:
Hab mir mal den Speicher angesehen. Er enthält keinen 8080-Code. Die Wahrscheinlichkeit eines Zusammenhangs mit dem echten Turbo-Pascal-Compiler ist somit gleich 0. Es handelt sich auch nicht um einen Emulator, sondern um einen Bytecodeinterpreter. Das Compilerprogramm scheint den Interpreter zu enthalten sowie zusätzliche Routinen in Assembler, doch der größte Codeanteil besteht wohl aus Bytecode, d. h. der Compiler wurde wahrscheinlich mit sich selbst übersetzt. Die Einsprungadresse SYS 3672 (= $e58) des Basic-Laders verweist dabei allerdings mitten in eine kleine Unterroutine, sprich: ins Nirvana, so daß man den Compiler mittels Load und Run nicht starten kann.