Forum: Offtopic Gibt es eine Programmiersprache mit diesem Schleifentyp?


von Josef G. (bome) Benutzerseite


Lesenswert?

In einer von mir kreierten Programmiersprache gibt es die
"Schleife mit Hineinsprung" anstelle der while-Schleife.

Kennt jemand sonst eine Sprache mit dieser Struktur?

Beitrag "Re: 8bit-Computing mit FPGA"

von Yalu X. (yalu) (Moderator)


Lesenswert?

In C ist das eine Do-While-Schleife mit eine Goto für den Sprung ins
Innere der Schleife. Wenn man will, kann man mit ein paar Makros den
Goto kaschieren und das Ganze wie eine "echte" Kontrollstruktur aussehen
lassen.

Wenn man die Anweisungen etwas umstellt, kann man auch eine
Endlos-Schleife mit bedingtem Break verwenden. Das ist der Weg, wie so
etwas üblicherweise realisiert wird.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Josef G. schrieb:
> In einer von mir kreierten Programmiersprache gibt es die
> "Schleife mit Hineinsprung" anstelle der while-Schleife.

Das erinnert mich an den Vorschlag, komplementär zum GO TO-Befehl
noch einen COME FROM-Befehl zu implementieren.

> Kennt jemand sonst eine Sprache mit dieser Struktur?

BASIC.

von Josef G. (bome) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Wenn man die Anweisungen etwas umstellt, kann man auch eine
> Endlos-Schleife mit bedingtem Break verwenden. Das ist der
> Weg, wie so etwas üblicherweise realisiert wird.

Sofern der Compiler das nicht optimiert und eine Schleife mit
Hineinsprung daraus macht, hätte diese Lösung allerdings den
Nachteil, dass bei jedem Durchlauf 2 Sprünge ausgeführt oder
Sprungbedingungen getestet werden müssen: der unbedingte
Rücksprung am Schluss und ein bedingter Sprung für break.

von Josef G. (bome) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> BASIC.

In meiner Sprache gibt es kein GOTO, und die Blockstruktur
ist streng und kann nicht durchbrochen werden.

von Josef G. (bome) Benutzerseite


Lesenswert?

Meine Eingangsfrage war so gemeint, ob es eine solche Struktur
in irgendeiner Sprache fertig gibt. Dass man sie mit anderen
Strukturen nachbilden kann ist klar, und wenn man GOTO zulässt
sowieso. Die Antwort auf die Frage lautet nach den bisherigen
Reaktionen: Es gibt keine solche Sprache.

von Robert L. (lrlr)


Lesenswert?

kenne ich auch nicht, bedarf scheint also nicht sehr hoch zu sein ;-)

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@Josef G. (bome) Benutzerseite

>In meiner Sprache gibt es kein GOTO, und die Blockstruktur
>ist streng und kann nicht durchbrochen werden.

Das beschreibt dein (Kommunikations)dilema ziemlich gut!

von Falk B. (falk)


Lesenswert?

@ Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite

>Das erinnert mich an den Vorschlag, komplementär zum GO TO-Befehl
>noch einen COME FROM-Befehl zu implementieren.

Naja, im weitesten Sinne wäre das die Sprungmarke einer ISR ;-)

von Yalu X. (yalu) (Moderator)


Lesenswert?

Josef G. schrieb:
> Sofern der Compiler das nicht optimiert und eine Schleife mit
> Hineinsprung daraus macht, hätte diese Lösung allerdings den
> Nachteil, dass bei jedem Durchlauf 2 Sprünge ausgeführt oder
> Sprungbedingungen getestet werden müssen: der unbedingte
> Rücksprung am Schluss und ein bedingter Sprung für break.

Neue Programmiersprachen werden entworfen, um den Programmierer – und
nicht den Compiler – in seiner Arbeit zu unterstützen. Werden bestimmte
Konstrukte nicht zufriedenstellend optimiert, wird deswegen am Compiler
Hand angelegt, nicht an der Programmiersprache.

Josef G. schrieb:
> Meine Eingangsfrage war so gemeint, ob es eine solche Struktur
> in irgendeiner Sprache fertig gibt.

Nicht dass ich wüsste.

In deiner neuen Kontrollstruktur steht derjenige Teil des
Schleifenrumpfs, der zuerst ausgeführt wird, nach dem Teil, der
danach ausgeführt wird. Dadurch wird die tatsächliche
Ausführungsreihenfolge verschleiert.

Das Konstrukt nimmt also dem Compiler minimal Arbeit ab, belastet aber
auf der anderen Seite den Programmierer, nicht nur, weil er dafür
"vekehrt" herum denken muss, sondern auch, weil er für diesen
zweifelhaften Fortschritt erst eine neue Sprache lernen muss, seinen
bestehenden Code ggf. umschreiben muss usw.

Das ist aber nicht das Ziel moderner Programmiersprachen.

: Bearbeitet durch Moderator
von Josef G. (bome) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> belastet aber auf der anderen Seite den Programmierer,
> nicht nur, weil er dafür "vekehrt" herum denken muss,

Das ist nicht richtig. Der Code steht in der Reihenfolge da,
wie er ausgeführt wird, der Abbruch erfolgt am Ende. Nur beim
Starten der Schleife wird einmalig ein Abschnitt am Anfang
übersprungen. Und das ist kein Problem für den Programmierer,
denn es steht ja am Anfang explizit da: L.JP, JP für"jump".

von Joachim B. (jar)


Lesenswert?

Jörg Wunsch schrieb:
> Das erinnert mich an den Vorschlag, komplementär zum GO TO-Befehl
> noch einen COME FROM-Befehl zu implementieren.

der nicht so unsinnig ist wie es scheint.

Am PC1500 hatte ich relokatiblen Assemblercode einige Unterprogramme im 
Eeprom geschrieben.
Branch war leicht möglich da mein Ziel bekannte Byte vorher oder zurück 
lag, goto jsr jump sub routine schied ja aus wegen relokatibel.
Aber wie zurück kommen wenn ich nicht weiss woher ich kam ?

Deswegen musste ich tricky den PC (Programmcounter) auslesen auf den 
erst mal auf den Stack packen und diesen so manipulieren das er in 
meiner Unterroutine passend richtig liegt für ein RET (return jump)

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Josef G. schrieb:
> Yalu X. schrieb:
>> belastet aber auf der anderen Seite den Programmierer,
>> nicht nur, weil er dafür "vekehrt" herum denken muss,
>
> Das ist nicht richtig. Der Code steht in der Reihenfolge da,
> wie er ausgeführt wird, der Abbruch erfolgt am Ende. Nur beim
> Starten der Schleife wird einmalig ein Abschnitt am Anfang
> übersprungen.

Kann es sein, dass du ein Programm tatsächlich in der Richtung liest,
wie du es hier beschreibst, nämlich von hinten nach vorne bzw. vom Ende
zum Start? Dann ist dein neues Konstrukt für dich genau richtig ;-)

Bei den meisten Leuten ist das aber anders herum. Sie fragen sich: Was
macht das Programm als erstes, was folgt danach?

von Karl H. (kbuchegg)


Lesenswert?

Josef G. schrieb:

> Nur beim
> Starten der Schleife wird einmalig ein Abschnitt am Anfang
> übersprungen.

Ich überleg jetzt schon eine ganze Weile.
Wahrscheinlich hatte ich in all den Jahren durchaus schon mal den Fall, 
der von deiner "Schleife mit Hineinsprung" abgedeckt wird. Aber im 
Moment fällt mir kein Beispiel aus den letzten Jahren ein, bei dem ich 
das mal gebraucht hätte.

In normalem C wäre das ja im Grunde (wenn ich das richtig verstanden 
habe)
1
   xyz;
2
3
   while( Abbruchbedingung ) {
4
     abc;
5
     xyz;
6
  }

wobei xyz bzw. abc für irgendwelche nicht triviale Codeteile stehen.

Solange die Codeteile nicht zu komplex sind, könnte man das auch so 
schreiben
1
   for( xyz; Abbruchbedingung; xyz )
2
     abc;
ich finde allerdings die erste Variante mit dem while trotzdem besser.
Nur. Das ist gar nicht der springende Punkt. Ich bin jetzt sicher nicht 
der repräsentative Programmierer, der das Mass aller Dinge darstellt. 
Trotzdem. Mir fällt ad hoc kein reales Beispiel aus den letzten Jahren 
ein und ich bilde mir ein, vom Code der letzten Jahre noch so einiges im 
Gedächtnis parat zu haben. So häufig dürfte der Fall also nicht sein.

Das erinnert mich irgendwie an 'Duffs Device'. Das ist ein netter 
kleiner Trick, aber ausser auf tiefster Treiberebene braucht das Ding im 
Grude genommen kein Mensch. Und selbst da ist zweifelhaft ob man das 
Loop-Unrolling nicht doch besser dem Compiler überlassen sollte.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Die Frage ist vielmehr.

Gibt es einen Programmierertyp, der mit dieser Schleife was anfangen 
kann?

;-)

von Josef G. (bome) Benutzerseite


Lesenswert?

Da offenbar kaum jemand den im Eröffnungsbeitrag verlinkten
Beitrag im Nachbarforum anschaut, hier eine Kopie:

> *L.JP          / springt zu *HERE
>   oper1
>   oper2
> *HERE
>   oper3
>   oper4        / weist VAR einen Wert zu
> *RP.Z VAR      / springt zu oper1 falls VAR = zero

> In C würde man hier eine function definieren, welche
> oper3/4 ausführt und den Rückgabewert VAR erhält.
> Und man würde eine while-Schleife verwenden, welche
> oper1/2 ausführt, solange die function Null liefert.

> Die Schleife mit Hineinsprung erfüllt den gleichen
> Zweck auf einfachere Weise. Die Hochsprache braucht dann
> auch nicht das Konstrukt einer function mit Rückgabewert,
> sondern es reichen einfache Unterprogramme, bei welchen
> alle Übergabe-Parameter gleichberechtigt sind.

Ergänzend hierzu noch der Hinweis auf obigen Beitrag:

Josef G. schrieb:
> Yalu X. schrieb:
>> Wenn man die Anweisungen etwas umstellt, kann man auch eine
>> Endlos-Schleife mit bedingtem Break verwenden. Das ist der
>> Weg, wie so etwas üblicherweise realisiert wird.
>
> Sofern der Compiler das nicht optimiert und eine Schleife mit
> Hineinsprung daraus macht, hätte diese Lösung allerdings den
> Nachteil, dass bei jedem Durchlauf 2 Sprünge ausgeführt oder
> Sprungbedingungen getestet werden müssen: der unbedingte
> Rücksprung am Schluss und ein bedingter Sprung für break.

von Karl H. (kbuchegg)


Lesenswert?

Josef G. schrieb:

>> Die Schleife mit Hineinsprung erfüllt den gleichen
>> Zweck auf einfachere Weise.

Das ist doch gar nicht der springende Punkt.
Der springende Punkt ist, dass diese Form der Schleife so selten 
vorkommt, dass es sich überhaupt nicht lohnt, dafür ein extra 
Sprachkonstrukt aufzusetzen.

Du tust so, als ob das ein enorm drängendes Problem wäre.
Das ist es nicht.

Deshalb bricht hier auch keiner in Jubelstürme aus.

(Allerdings: warst du nicht der Typ, der einen eigenen Zeichensatz 
vorgeschlagen hat, der für Hex-Ziffern eigene Zeichen benutzt?
Selbiges: Du schlägst eine Lösung für etwas vor, was überhaupt kein 
Problem ist)

: Bearbeitet durch User
von Josef G. (bome) Benutzerseite


Lesenswert?

Karl Heinz schrieb:
> Der springende Punkt ist, dass diese
> Form der Schleife so selten vorkommt

Wie ich im Eröffnungsbeitrag geschrieben habe, gibt es diese
Schleife bei meiner Sprache nicht zusätzlich zur while-Schleife,
sondern anstelle der while-Schleife. Deshalb kommt sie häufig
vor. Und die hier beschriebenen Vorteile kommen dann hinzu.

von Bernd K. (prof7bit)


Lesenswert?

Jörg Wunsch schrieb:
> Das erinnert mich an den Vorschlag, komplementär zum GO TO-Befehl
> noch einen COME FROM-Befehl zu implementieren.

Ein COMEFROM käme wohl noch am ehesten dem EXCEPT eines TRY/EXCEPT 
Konstrukts nahe.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Josef G. schrieb:
> In einer von mir kreierten Programmiersprache gibt es die
> "Schleife mit Hineinsprung" anstelle der while-Schleife.
Das erinnert mich ein wenig an den hier:
Ein Betrunkener tastet sich irritiert ständig um eine Litfassäule herum. 
Nach etwa 10 Runden sinkt er resigniert in sich zusammen und murmelt: 
"Verdammt! Eingesperrt!"

Und genau das kann passiert bei dieser Hineinsprung-Schleife auch: es 
ist eine Frage der Sichtweise. Man stülpt sie einfach um und hat einen 
definierten Anfang, mittendrin einen Absprung und sonst eine einfache 
Schleife...

von Falk B. (falk)


Lesenswert?

@ Karl Heinz (kbuchegg) (Moderator)

>Das ist doch gar nicht der springende Punkt.

In der Tat.

>(Allerdings: warst du nicht der Typ, der einen eigenen Zeichensatz
>vorgeschlagen hat, der für Hex-Ziffern eigene Zeichen benutzt?
>Selbiges: Du schlägst eine Lösung für etwas vor, was überhaupt kein
>Problem ist)

Du hast es erfasst.

Ich verweise auf

Beitrag "wer kann sich noch an den hex-zeichensatz erinnern?"

von Yalu X. (yalu) (Moderator)


Lesenswert?

Wie sieht eigentlich diese neue Programmiersprache insgesamt aus? Gibt
es da eine Spezifikation oder Beispielprogramme?

Gibt es neben der Schleife mit "Hineinsprung" noch weitere Features, die
sie von bestehenden Sprachen unterscheiden?

Noch etwas zum Thema Schleifenoptimierung: Der GCC dreht alle Schleifen
– egal, ob for, while, do-while oder endlos mit break – so hin, dass die
Abbruchbedingung am Ende liegt. Man muss sich darum als Programmierer
also keine Gedanken machen.

von Josef G. (bome) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Gibt es da eine Spezifikation oder Beispielprogramme?

Siehe meine Benutzerseite, da ist meine Website zu finden. Die Sprache
wird beschrieben auf der Seite SYS-doku. Zum Testen auf Linux-PC gibt
es ein Emulationsprogramm des 8bit-Rechners, und Beispielprogramme.

> weitere Features, die sie von bestehenden Sprachen unterscheiden?

Die Sprache ist angepasst an die Hardware des 8bit-Rechners. Sie stellt
Variablen und Strukturelemente (zB. Schleifen) bereit, enthält selber
aber nur ganz wenige Routinen (zB. Inkrementieren/Dekrementieren). Der
Hauptteil der Routinen wird von den 8 Steckkarten geliefert.

Ein Schwachpunkt der Sprache: Sie kennt keine Ausdrücke. Stattdessen
gibt es "Mikrooperationen", welche ebenfalls von den Steckkarten
geliefert werden. Statt VAR1 = VAR2 + VAR3 würde es zB. heissen
GET VAR2   ADD VAR3   STO VAR1  je nach Steckkarten-Software.

Der Compiler erzeugt keinen Maschinencode, sondern einen Code,
welcher interpretativ von der CPU abgearbeitet wird. Sofern die
Steckkarten-Software dafür ausgelegt ist, kann man die Zahl der
Taktzyklen für alle Programmteile exakt berechnen.

von Klaus W. (mfgkw)


Lesenswert?

Josef G. schrieb:
> Die Sprache ist angepasst an die Hardware des 8bit-Rechners.

Josef G. schrieb:
> Ein Schwachpunkt der Sprache: Sie kennt keine Ausdrücke. Stattdessen
> gibt es "Mikrooperationen", welche ebenfalls von den Steckkarten
> geliefert werden. Statt VAR1 = VAR2 + VAR3 würde es zB. heissen
> GET VAR2   ADD VAR3   STO VAR1  je nach Steckkarten-Software.

Josef G. schrieb:
> In der im ROM eingebauten Hochsprache des Gesamtsystems
> wird nach gleichem Muster die "Schleife mit Hineinsprung"
> zur Realisierung von while-Schleifen verwendet.

Jetzt bleibt nur noch die Frage, was man unter einer Hochsprache 
versteht.

von Gregor O. (zappes)


Lesenswert?

Kleiner Hinweis für alle, die sich dem COME-FROM-Thema mit einer 
gewissen Ernsthaftigkeit genähert haben: Seht Euch mal die Spezifikation 
zu INTERCAL an, das ist die Sprache, aus der das Konstrukt stammt. So 
was kommt heraus, wenn ein paar wirklich kluge Leute wie ESR eine 
Spaßsprache entwickeln - kein Vergleich zu diesen kreuzlangweiligen 
Turingmaschinen-Emulatoren mit pseudolustigen Symbolen wie brainfuck, 
Ook!, Whitespace etc.

http://catb.org/esr/intercal/
http://catb.org/esr/intercal/ick.htm

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Klaus Wachtler schrieb:
> Jetzt bleibt nur noch die Frage, was man unter einer Hochsprache
> versteht.

Dieses Ding, was Josef im Nachbarthread

  Beitrag "Re: 8bit-Computing mit FPGA" (1)

unbeirrt anpreist, obwohl es keiner haben will, ist jedenfalls keine 
Hochsprache. Ich würde es "kryptischen Assembler" nennen, wobei die 
Betonung auf kryptisch liegt.

Seine Mnemonics bieten dem Leser leider überhaupt keine Eselsbrücken an, 
um Assoziationen zu bereits bekannten Befehlen zu ziehen. Kurz: Es ist 
für mich genauso unlesbar wie chinesisch.

(1) Link zeigt den vollständigen Befehlssatz.

: Bearbeitet durch Moderator
von Robert L. (lrlr)


Lesenswert?

Josef G. schrieb:
> Jörg Wunsch schrieb:
>> BASIC.
>
> In meiner Sprache gibt es kein GOTO, und die Blockstruktur
> ist streng und kann nicht durchbrochen werden.

Blöcke?

dazu ne Frage..
gibt es diese "Schleife mit Hineinspringen" jetzt eigentlich shon oder 
ist das noch eher theoretsich?

der syntax lässt ja mal keine "blöcke" erkennen, verschachteln scheint 
mir unmöglich..

von Josef G. (bome) Benutzerseite


Lesenswert?

Robert L. schrieb:
> oder ist das noch eher theoretsich?

Es gibt eine fertige Implementierung auf meinem 8bit-Rechner

> der syntax lässt ja mal keine "blöcke" erkennen,

Der Bereich zwischen *L.JP und *HERE zählt als ein Block,
ebenso der Bereich zwischen *HERE und *RP.Z

> verschachteln scheint mir unmöglich..

Doch, ist natürlich möglich.

von Josef G. (bome) Benutzerseite


Lesenswert?

Frank M. schrieb:
> ist jedenfalls keine Hochsprache.

Was du verlinkt hast ist die Tabelle der Assembler-
Mnemonics und hat mit der Hochsprache nichts zu tun.

von Falk B. (falk)


Lesenswert?

@Josef G. (bome) Benutzerseite

>> ist jedenfalls keine Hochsprache.

>Was du verlinkt hast ist die Tabelle der Assembler-
>Mnemonics und hat mit der Hochsprache nichts zu tun.

Was du da fabriziert hast ist eher eine Art Anti-Logikpuzzle und hat mit 
einem ANWENDBAREN Mikrorechnersystem nichts zu tun. :-0

von Yalu X. (yalu) (Moderator)


Lesenswert?

Josef G. schrieb:
> Frank M. schrieb:

>> ist jedenfalls keine Hochsprache.
>
> Was du verlinkt hast ist die Tabelle der Assembler-
> Mnemonics und hat mit der Hochsprache nichts zu tun.

Die Verwechslungsgefahr zwischen den Assemblerm-Mnemonics und den
Hochsprachenschlüsselwörtern kommt aber auch nicht ganz von ungefähr:

*L.JP und *RP.Z sind Hochsprache, die nicht viel anders aussehenden
Befehle LZ.A und S.RP sind Assembler.

Beim folgenden Code dachte ich auch erst, dass das ja nur der vom
Compiler aus der Hininspringschleife generierte Assemblercode sein kann:

> *L.JP          / springt zu *HERE
>   oper1
>   oper2
> *HERE
>   oper3
>   oper4        / weist VAR einen Wert zu
> *RP.Z VAR      / springt zu oper1 falls VAR = zero

Ist es aber nicht, wie ich inzwischen gelernt habe.

Ich habe auch schon versucht, die Dokmentation auf deiner Webseite zu
verstehen. Bei den einzelnen Seiten (home, CPU-doku, SYS-doku, Emul und
Hawa) schmeißt du aber schon in den ersten 10 Zeilen mit Bergiffen und
Konzepten um dich, dass ich dachte, ich müsste erst eine andere Seite
durcharbeiten, um die Grundlagen zu verstehen. Dieses Problem hatte ich
aber auf jeder der fünf Seiten, so dass sich sozusagen eine
fünfschwänzige Katze jeweils fünffach in ihre fünf Schwänze biss.

Deine Hochsprache (oder das, was ich meine, dass sie es ist) erinnert
mich stark an die Assemblersprache der IBM/360-Computer und deren
Nachfolger. Auch dort gab es (gegen Aufpreis, versteht sich) ein
Makropaket für die strukturierte Programmierung (If-Else, verschiedene
Schleifenkonstrukte, Switch-Case usw.). Mit diesem Assembler wurde nicht
nur hardwarenah (Treiber u.ä.) programmiert, er wurde tatsächlich wie
eine Hochsprache für kaufmännische Software (als Alternative zu Cobol)
eingesetzt.

Mittlerweile sind aber viele Jahrzehnte vergangen, und die Software-
entwicklungsmethoden haben sich völlig verändert. Eingefleischte IBMler
nutzen aber immer noch ihren Assembler und verwenden – ähnlich wie auch
du – sogar ihren eigenen Zeichensatz (EBCDIC). Erst vor kurzem hatten
wir eine amüsante Diskussion, in der dieses Thema aufkam:

  Beitrag "Was hat es mit den 'trigraphs' aufsich"

Kann es vielleicht sein, dass du bei IBM beschäftigt bist oder warst?

von Josef G. (bome) Benutzerseite


Lesenswert?

Es gibt in der Tat eine Eins-zu-Eins-Entsprechung zwischen
dem Quelltext und dem erzeugten Code. Und dies ermöglicht
es, durch Addieren von Ausführungszeiten die Dauer von
Programmteilen zu berechnen. Ob es dafür einmal eine
ernsthafte Anwendung geben wird, wird man sehen.

von Manuel X. (vophatec)


Lesenswert?

Josef G. schrieb:
>  Ob es dafür einmal eine
> ernsthafte Anwendung geben wird, wird man sehen.

Da sich offensichtlich niemand damit beschäftigen will, wird sich die 
Verbereitung und damit die Anwendung in Grenzen halten. Vermutlich sind 
die Grenzen gleichzeitig durch deine eigenen 4 Wände definiert...


Oo

von Klaus W. (mfgkw)


Lesenswert?

Manuel X. schrieb:
> Vermutlich sind
> die Grenzen gleichzeitig durch deine eigenen 4 Wände definiert...

Was ja nicht eine ernsthafte Anwendung ausschließt....

von Josef G. (bome) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Mittlerweile sind aber viele Jahrzehnte vergangen, und die
> Software-entwicklungsmethoden haben sich völlig verändert.

> Kann es vielleicht sein,

Richtig ist, dass ich schon etwas älter bin und mir
vieles an den modernen Entwicklungen nicht gefällt.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Josef G. schrieb:
> Richtig ist, dass ich schon etwas älter bin und mir
> vieles an den modernen Entwicklungen nicht gefällt.

Ich bin auch nicht mehr der Jüngste, und auch mir gefällt vieles an den
modernen Entwicklungen nicht.

Aber wie alt musst du sein, dass du die Infixschreibweise arithmetischer
Ausdrücke (wie bspw. y = m * x + b) in einer höheren Programmiersprache
als "moderne Entwicklung" empfindest?

Diese Entwicklung hat immerhin schon vor deutlich über einem halben
Jahrhundert stattgefunden ;-)

von Uhu U. (uhu)


Lesenswert?

Josef G. schrieb:
> Siehe meine Benutzerseite, da ist meine Website zu finden. Die Sprache
> wird beschrieben auf der Seite SYS-doku.

Diese Chaosseiten sind eine Strafe - unklar ist mir eigentlich nur, was 
man ausgefressen haben muss, um dazu verdonnert zu werden, diesen 
Krempel zu lesen.

Josef, du tätest wirklich gut daran, dir endlich die Grundlagen der 
Informatik anzueignen, statt immer wieder Anfänge aus den 1960er Jahren 
"neu" zu "erfinden".

Wenn du dir unbedingt mit Reto-Technologien einen Namen machen willst, 
musst du eine nehmen, was wenigstens ein paar Tausend Jahre alt ist und 
heute nicht mehr gebräuchlich ist, z.B. das Herstellen von 
Steinzeitwerkzeugen und -waffen.

: Bearbeitet durch User
von Josef G. (bome) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Ausdrücke (wie bspw. y = m * x + b) in einer höheren Programmiersprache

Ausdrücke lehne ich keineswegs ab. Ich habe selber geschrieben

Josef G. schrieb:
> Ein Schwachpunkt der Sprache: Sie kennt keine Ausdrücke.

Bei der von mir gewählten Methode, anstelle von Ausdrücken Folgen
von "Mikrooperationen" zu verwenden, hat der Programmierer die volle 
Kontrolle über den tatsächlich ausgeführten Code, und die Dauer lässt
sich einfach berechnen, wenn die Dauer der einzelnen Mikrooperationen
bekannt ist. Andererseits werden diese Folgen recht schnell sehr
umfangreich, insbesondere bei Verwendung von Arrays.

Denkbar wäre, dass es irgendwann so etwas wie einen Präprozessor gibt,
der Ausdrücke im Quelltext in Folgen von Mikrooperationen umwandelt.

von (prx) A. K. (prx)


Lesenswert?

Josef G. schrieb:
> Bei der von mir gewählten Methode, anstelle von Ausdrücken Folgen
> von "Mikrooperationen" zu verwenden, hat der Programmierer die volle
> Kontrolle über den tatsächlich ausgeführten Code,

"Real programmers write Microcode. Assembler is a high level language."

von (prx) A. K. (prx)


Lesenswert?

Josef G. schrieb:
> Denkbar wäre, dass es irgendwann so etwas wie einen Präprozessor gibt,
> der Ausdrücke im Quelltext in Folgen von Mikrooperationen umwandelt.

Manche Leute nennen das einen "Compiler". ;-)

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

A. K. schrieb:
> Manche Leute nennen das einen "Compiler". ;-)

... und das, was Josef einen Compiler nennt, einen Makro-Assembler ;-)

von Josef G. (bome) Benutzerseite


Lesenswert?

A. K. schrieb:
> Josef G. schrieb:
>> Denkbar wäre, dass es irgendwann so etwas wie einen Präprozessor gibt,
>> der Ausdrücke im Quelltext in Folgen von Mikrooperationen umwandelt.
>
> Manche Leute nennen das einen "Compiler". ;-)

Nein. Der Präprozessor würde Text in Text umwandeln. Meine Aussage
war hier missverständlich, da ich Mikrooperationen geschrieben habe,
aber die Text-Kürzel gemeint waren, welche für die Mikrooperationen
stehen und vom Compiler durch die Mikrooperationen ersetzt werden.

Josef G. schrieb:
> Der Compiler erzeugt keinen Maschinencode, sondern einen Code,
> welcher interpretativ von der CPU abgearbeitet wird.

Die "Mikrooperationen" sind keine CPU-Operationen, sondern
Elemente des vom Compiler erzeugten (Zwischen-)Codes.

Die Bezeichnung Compiler ist zB. auch bei der Sprache Java
üblich, wo es ebenfalls einen solchen Zwischencode gibt.

von Josef G. (bome) Benutzerseite


Lesenswert?

Falls jemand sich grundsätzlich für das System interessiert,
aber die Dokumentation für unverständlich hält:

Vielleicht würde es helfen, erst einmal mittels des Emulations-
Programms sich die Quelltexte der Beispielprogramme anzuschauen
und die Programme zu testen. Insbesondere das erste (emtext_a)
würde ich empfehlen.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Josef G. schrieb:
> Insbesondere das erste (emtext_a)
> würde ich empfehlen.

Also ich kriege da nur eine Datei mit lauter Zahlen, nischt mit 
'Quelltext'.
Für mich sieht das ganze wieder mal nach 'Habe Gerät, suche Anwendung' 
aus. Da ist Assembler auf dem 8051 richtig entspannend gegen das, was 
ich da auf deiner Webseite gelesen habe. Wer soll sich denn da 
durchfinden?

Dann doch lieber richtige Herausforderungen wie 'CP/M auf dem 8048' oder 
'Gleitkommaberechnung mit Diodenmatrix'  :-P

Richtig interessant finde ich auch sowas hier:
http://www.vaxman.de/my_machines/hitachi/240/240.html

von Josef G. (bome) Benutzerseite


Lesenswert?

Matthias Sch. schrieb:
> Also ich kriege da nur eine Datei mit lauter Zahlen,

Man braucht das Emulationsprogramm, um den Text anzuschauen.

> Für mich sieht das ganze wieder mal nach 'Habe Gerät,
> suche Anwendung' aus.

Ist richtig, hab ich nie bestritten.

von Uhu U. (uhu)


Lesenswert?

Josef G. schrieb:
> Nein. Der Präprozessor würde Text in Text umwandeln.

Es gab C++ - Compiler, die C++ - Code in C übersetzten. Transpiler 
übersetzen Code einer Sprach in welchen einer anderen.

Ich würde sagen, dass das gemeinsame Kriterium von Compilern der Aufbau 
eines Syntax-Baumes ist, aus dem anschließend das Endprodukt erzeugt 
wird.

Ob das Text, Binärcode, oder sonstwas ist, ist dabei egal.

https://de.wikipedia.org/wiki/Compiler#Einordnung_verschiedener_Compiler-Arten

von Uhu U. (uhu)


Lesenswert?

Josef G. schrieb:
> Vielleicht würde es helfen, erst einmal mittels des Emulations-
> Programms sich die Quelltexte der Beispielprogramme anzuschauen
> und die Programme zu testen. Insbesondere das erste (emtext_a)
> würde ich empfehlen.

Dazu müsstest du erst mal deine elende "Dokumentation" in ein halbwegs 
verdauliches und übersichtliches Format bringen. So wie sie im Moment 
ist, ist sie nur für Masochisten und Buchhalter geeignet.

von Josef G. (bome) Benutzerseite


Lesenswert?

Vielleicht könnte ja mal jemand, der meint, die Dokumentation
sei unverständlich, mir eine konkrete Stelle nennen, wo etwas
unverständlich ist.

von Higg G. (higg)


Lesenswert?

Josef G. schrieb:
> Vielleicht könnte ja mal jemand, der meint, die Dokumentation
> sei unverständlich, mir eine konkrete Stelle nennen, wo etwas
> unverständlich ist.

Im Allgemeinen:
Zuerst einmal wirkt deine Dokumentation so, als ob du während deiner 
Entwicklung, die für dich wesentlichen Teile in reine Textdateien 
geschrieben hast, und diese nun 1:1 auf deinen Server hochgeladen hast. 
Die gesamte Dokumentation erfüllt sicherlich den Zweck für dich als 
persönliche Referenz, ist aber völlig ungeeignet um neue Menschen für 
dein System zu begeistern. Also erschlage den interessierten Leser nicht 
gleich mit Fakten, sondern nimm ihn bei der Hand, und zeige Schritt für 
Schritt, was er mit dem System anstellen kann. In der jetzigen Form, 
muss man die komplette Seite mehrfach lesen um irgendwie einen Einstieg 
zu finden.

Konkret:
Als interessierter Leser klicke ich erstmal auf "SYS-doku", weil ich 
dahinter die Systemdokumentation vermute. Der erste Abschnitt lautet:
> Die Zuordnung der Adressregister zu einer memory-page erfolgt
> durch 2bit-Latches MP,MX,MY,MZ , und es gibt Austauschregister
> NP,NX,NY,NZ . Das CPU-Signal B# tauscht M#-N#  (#= P,X,Y,Z).
Interessiert mich das? Nein! Was spräche dagegen, z.B. deinen Emulator 
zu zeigen, wie man diesen bedient, und ein einfaches Programm zum laufen 
kriegt? Schau dir mal Programmierlehrbücher an, und wie diese aufgebaut 
sind. Wo finde ich eine gegliederte Darstellung? Das ganze ist ein 
einziger Fließtext ohne Struktur.

Zum Webdesign:
Es spricht nichts gegen puristisches Webdesign. Aber Links und Bilder 
gibt es schon ne Weile, und diese kann und sollte man benutzen.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Josef G. schrieb:
> Matthias Sch. schrieb:
>> Also ich kriege da nur eine Datei mit lauter Zahlen,
>
> Man braucht das Emulationsprogramm, um den Text anzuschauen.

Das z.B. ist etwas, das Interessierte schon mal abschreckt - was für ein 
Emulationsprogramm, und wieso kann man einen Quelltext nicht, wie bei 
jedem anderen System seit Urzeiten, im Klartext lesen? Die Token (oder 
was auch immer da drin steht) interessieren mich am Anfang doch gar 
nicht und 'Quelltext' ist für mich eben genau das - Text, der als Quelle 
für einen wie auch immer gearteten Compiler, Assembler, Tokenizer oder 
Interpreter dient, der dann irgendwann Maschinencode erzeugt.
Und wenn ich mir einen Eindruck von einem Rechnersystem verschaffen 
will, dann schau ich mir gerne auch mal den Assemblertext (oder wie auch 
immer das bei dir heisst) an. Dumm eben auch, wenn man vor einem Rechner 
mit z.B. Windows oder Mac OS sitzt, dann kriegt man den Emulationator 
nicht mal ohne Verrenkungen zum Laufen.

Du könntest also ganz einfach mal eines der Programme umschnurzeln und 
als Klartext auf die Webseite setzen.
Nächster Punkt: Du redest zwar von irgendwelche Steckkarten und 
Programmen dadrauf, aber mir ist der Sinn des Ganzen nicht klargeworden. 
Sind das Option ROMs wie bei einem Apple ][ oder IBM PC oder was ist der 
Sinn dahinter? Du hast dich in Flipflops,Register und 
Signalbezeichnungen verstrickt, aber vergessen, einem Typen wie mir zu 
erklären, warum und wofür du das überhaupt machst.

Das war z.B. einer der grossen Vorzüge beim IBM PC oder dem o.a. Apple 
][. Ein offenes System, das jeder nachvollziehen konnte, mit Unterlagen, 
und einem einfach zu verstehenden System aus Erweiterungen und der 
Möglichkeit, mal eben selber eine Karte zu stricken und die durch den 
Rechner anzusprechen.
Gut, in den Zeiten von PCI-Express und USB ist das ein wenig schwieriger 
geworden, aber immer noch vollständig dokumentiert und nachvollziehbar.

: Bearbeitet durch User
von Josef G. (bome) Benutzerseite


Lesenswert?

Matthias Sch. schrieb:
> Nächster Punkt: Du redest zwar von irgendwelche Steckkarten und
> Programmen dadrauf, aber mir ist der Sinn des Ganzen nicht klargeworden.
> Sind das Option ROMs wie bei einem Apple ][ oder IBM PC oder was ist der
> Sinn dahinter?
>
> Das war z.B. einer der grossen Vorzüge beim IBM PC oder dem o.a. Apple
> ][. Ein offenes System, das jeder nachvollziehen konnte, mit Unterlagen,
> und einem einfach zu verstehenden System aus Erweiterungen und der
> Möglichkeit, mal eben selber eine Karte zu stricken und die durch den
> Rechner anzusprechen.

Genauso ist auch mein Rechner konzipiert.

Beim AppleII belegte jeder Steckplatz 256 Byte (oder waren es 512).
Die Adressbereiche waren übereinander angeordnet. Hat man bei einer
Karte den Steckplatz gewechselt, haben sich die Adressen geändert.
Mir hat das nicht gefallen. Und die Kommandos an die Karte wurden
mittels PRINT zeichenweise an die Karte gesendet.

Bei meinem System hat jede Karte volle 64KByte zur Verfügung. Die
Namen der Karten-Kommandos werden bereits beim Compilieren durch
Nummern ersetzt. Es gibt sauber definierte Schnittstellen für den
Aufruf der Kommandos und des "Formelinterpreters", so habe ich das
auf der Karte befindliche Programm genannt, welches die oben
genannten Folgen von "Mikrooperationen" ausführt. Auf die Karten
wird über die Steckplatz-Nummer zugegriffen, das erfolgt indirekt
über eine Ersetzungstabelle. Wenn man eine Karte in einen anderen
Steckplatz steckt, muss man nur diese Tabelle ändern.

von Falk B. (falk)


Lesenswert?

@ Josef G. (bome) Benutzerseite

>> Das war z.B. einer der grossen Vorzüge beim IBM PC oder dem o.a. Apple
>> ][. Ein offenes System, das jeder nachvollziehen konnte, mit Unterlagen,
>> und einem einfach zu verstehenden System aus Erweiterungen und der
>> Möglichkeit, mal eben selber eine Karte zu stricken und die durch den
>> Rechner anzusprechen.

>Genauso ist auch mein Rechner konzipiert.

Meinst DU! Nur mit dem "kleinen" Unterschied, dass Apple II und Ur-PC 
locker 35 Jahre her sind, damals ein Novum waren, innerhalb kürzester 
Zeit Massen von Leuten begeisterten und die Erbauer zu reichen Leuten 
gemacht haben. Aber was rede ich hier über Nebensächlichkeiten. 
Facepalm

von Robert L. (lrlr)


Lesenswert?

ich find es ja (wirklich!) beeindruckend, wenn jemand eine CPU (ganzen 
Rechner?) selber entwickelt.. (ich könnte das nicht)

ist eben so, als baute man eine Balliste oder ein Katapult  (das machen 
auch noch viele Leute aus Spaß/Nostalgie, und nicht weil man heute noch 
einen nutzen davon hätte..)


zum Thema (schleife mit Hirneinspringen)

bin ich grundsätzlich der Meinung, dass du dich hier in irgend einem 
(total unwichtigen) Detail verrennst.. ob man das hat, oder nicht ist 
doch egal..

mich würde immer noch interessieren, wie solch eine Schleife 
verschachtelt ausschaut (und zwar in realem code, nicht skizziert...)
kannst da mal an Screenshot machen?

Falls jemand wirklich glaube, der Typ von schleife wäre sinnvoll, könnte 
man seine Zeit doch auch damit verbringen das bei z.b. FreePascal oder 
GCC (in einem Fork) einzubauen.. und herzeigen wie toll man damit 
tägliche Probleme lösen kann..

das mit den Steckkarten errinnert mich an den GameBoy/C64 usw.

warum es wichtig sein sollte, dass man (anhand vom Code) abzählen kann, 
wieviele takte ein bestimmtes programm jetzt genau braucht, kapier ich 
übrigens nicht..


ps. auch interessant ist, dass die Homepage die ausschaut als wäre sie 
mit der Scheinmaschine geschrieben wurde, mit iWeb erstellt wurde ...

von Josef G. (bome) Benutzerseite


Angehängte Dateien:

Lesenswert?

1
*PGM DEMO
2
*CON STRG -??
3
*AUT AA. /00  BB. /00
4
*BEGN
5
*L.JP
6
  1LFEED
7
  *L.JP
8
    1ADDLOC /01
9
    =DECR AA.
10
  *HERE
11
    1PRINTN /08 AA.
12
  *RP.S AA.
13
  1LFEED
14
*HERE
15
  1SETLOC /f0
16
  *L.JP
17
    1PRINTS /02 STRG
18
  *HERE
19
    1PRINTS /00 STRG  
20
    1INPUTN /08 AA.
21
    1INPUTN /0c BB.
22
    1LFEED
23
  *RP.Z BB.
24
  1  oGET AA.  oAND /f8  oSTO BB.
25
*RP.Z BB.
26
*RETN
Robert L. schrieb:
> mich würde immer noch interessieren, wie solch eine Schleife
> verschachtelt ausschaut (und zwar in realem code, nicht skizziert...)
> kannst da mal an Screenshot machen?

Habe also ein Beispiel erstellt, wo sowohl zwischen L.JP und HERE
als auch zwischen HERE und RP.x eine weitere Schleife mit Hinein-
sprung steht. Siehe part1.png und part2.png, darunter nochmal im
Ganzen. run.png zeigt den Ablauf beim Compilieren und Testen.

Das Programm liest zwei Zahlen ein, wobei davor ?? ausgegeben wird.
Die Eingabe wird wiederholt, falls die zweite Zahl Null ist. Bei
den Wiederholungen wird zusätzlich ein zweites ?? ausgegeben.
Wenn anschließend die erste Zahl größer ist als 7, erfolgt Abbruch,
andernfalls wird diese Zahl ausgegeben und in derselben Zeile bis
Null dekrementiert und es geht wieder zur Eingabe.

Das Programm dient ausschließlich dazu, die Verschachtelbarkeit
der Schleife mit Hineinsprung zu demonstrieren. Niemand würde
sonst ein Programm so schreiben.

: Bearbeitet durch User
von Uhu U. (uhu)


Lesenswert?

Eine Hochsprache ist das ja nicht gerade...

Wer programmiert heutzutage noch ernsthaft Assembler? Höchstens Bastler 
und Nostalgiker.

Josef G. schrieb:
> In meiner Sprache gibt es kein GOTO, und die Blockstruktur
> ist streng und kann nicht durchbrochen werden.

Wozu man einem Assembler eine "strenge Blockstruktur" aufbrummen muss, 
erschließt sich mir nicht.

Warum man die "strenge Blockstruktur" anschließend wieder mit so einer 
komischen Konstruktion, wie dem "Hineinsprung" durchlöchern muss, schon 
zweimal nicht.

Das ganze ist doch nur reine Beschäftigungstherapie.


Ich kenne aus den 1970ern noch ein Sprachkonstrukt, das ich seither 
nicht wieder gesehen habe und das ich wirklich interessant finde:

Das Betriebssystem MCP der Borroughs 1700er-Serie wurde in einer Sprache 
namens SDL (System Development Language) programmiert. Das war eine 
echte Hochsprache (ohne Fließkomma-Arithmetik!) mit folgendem 
Schleifenkonstrukt:
1
  do outerloop forever    /* unendliche Schleife! */
2
    ...
3
    ...
4
    do innerloop forever
5
      ...
6
      ...
7
      undo outerloop
8
      ...
9
    end
10
    ...
11
    ...
12
  end

- Die Schleifennamen (hier: outerloop, innerloop) waren optional und
  frei wählbar
- undo entspricht dem break in C
- undo ohne Label beendet die Schleife, in der undo steht
- undo mit Label beendet die gelabelte Schleife

SDL hatte kein goto und mit dem undo hatte man einen Sprung, der 
keine "Sauereien" zuließ und die Schleifenrücksprünge aus geschachtelten 
Schleifen sehr bequem und sicher machte.

: Bearbeitet durch User
von Josef G. (bome) Benutzerseite


Lesenswert?

Uhu Uhuhu schrieb:
> Warum man die "strenge Blockstruktur" anschließend wieder mit so einer
> komischen Konstruktion, wie dem "Hineinsprung" durchlöchern muss,

Die wird nicht durchlöchert.
L.JP .. HERE .. RP.x ist genauso ein Block mit zwei Unterblöcken,
wie dies bei if .. else .. end-else der Fall ist.

von Uhu U. (uhu)


Lesenswert?

Du hast das Zitat um einen wichtigen Teil verstümmelt und den 
eigentlichen Punkt umgangen: Assembler mit "strenger Blockstruktur" sind 
Unsinn.

von (prx) A. K. (prx)


Lesenswert?

Uhu Uhuhu schrieb:
> Wozu man einem Assembler eine "strenge Blockstruktur" aufbrummen muss,
> erschließt sich mir nicht.

Wenn man schon in Assembler programmiert, dann kann das sehr wohl Sinn 
ergeben. Ganz besonders dann, wenn man nichts anderes zur Verfügung hat 
oder Hochsprachen generell ablehnt (haben wir hier ja so einen oder zwei 
im Forum).

> Warum man die "strenge Blockstruktur" anschließend wieder mit so einer
> komischen Konstruktion, wie dem "Hineinsprung" durchlöchern muss, schon
> zweimal nicht.

Ist doch langweilig, immer bloss den gleichen Strukturen von anno Algol 
nachzueifern.

von Josef G. (bome) Benutzerseite


Lesenswert?

In meiner Sprache gibt es den Datentyp "Databox". Es gibt den
Mechanismus des "Ausleihens", wobei Variable, welche zuvor keinen
Wert haben (reine Zeiger sind), innerhalb der Databox ihren Wert
zugewiesen bekommen. Die Werte müssen danach wieder "zurückgegeben"
werden, bevor die Databox nicht mehr existiert, andernfalls würden
die Werte in undefinierten Bereichen des RAM liegen und Schreib-
zugriffe könnten Unheil anrichten. (Das hat Ähnlichkeit mit üblichen
Konstruktionen wie "with record do", wo die Elemente des records
innerhalb dieses Blocks verfügbar sind.) Der Compiler garantiert,
dass das Zurückgeben innerhalb desselben Blocks erfolgt wie das
Ausleihen. Genau zu diesem Zweck wird die Blockstruktur benötigt,
und da darf es auch kein Herausspringen aus Schleifen geben.

von (prx) A. K. (prx)


Lesenswert?

Uhu Uhuhu schrieb:
> Ich kenne aus den 1970ern noch ein Sprachkonstrukt, das ich seither
> nicht wieder gesehen habe und das ich wirklich interessant finde:

PL/I:
1
  A: DO I = 1 TO 10;
2
       DO J = 1 TO 5;
3
         IF X(I,J)=0 THEN
4
           LEAVE A;
5
       END;
6
     END;
oder kürzer:
1
  A: DO I = 1 TO 10;
2
       DO J = 1 TO 5;
3
         IF X(I,J)=0 THEN
4
           LEAVE A;
5
     END A;

: Bearbeitet durch User
von Uhu U. (uhu)


Lesenswert?

A. K. schrieb:
> PL/I:

Das war etwa dieselbe Zeit...

von Yalu X. (yalu) (Moderator)


Lesenswert?

Uhu Uhuhu schrieb:
> A. K. schrieb:
>> PL/I:
>
> Das war etwa dieselbe Zeit...

Beispiele aus jüngerer Zeit:

In Java gibt es ähnlich wie in PL/I labeled Loops:
1
    outerloop:
2
    for(x=0; x<10; x++) {
3
      for(y=0; y<10; y++) {
4
        if(condition(x, y))
5
            break outerloop;
6
      }
7
    }

Ähnlich geht es auch in Javascript, Ada, Perl, Fortran 90 (und neuer),
Go, Swift und sicher noch etlichen weiteren Sprachen.

In PHP gibt es
1
  break n;

wobei n angibt, wieviele der verschachtelten Schleifen verlassen werden
sollen. Dabei entspricht break 1 einem break ohne Argument.

In Python und Rust wurde so ein Konstrukt vorgeschlagen, dann aber
abgewiesen.

Die Hineinspringschleife von Josef ist im Vergleich dazu schon etwas
Besonderes :)

: Bearbeitet durch Moderator
von Unbekannt U. (Gast)


Lesenswert?

Yalu X. schrieb:
> In Java gibt es ähnlich wie in PL/I labeled Loops:

Diese "Wenn Prädikat dann Abbrechen-Befehl"-Konstruktionen kann man 
direkter so schreiben:

1
    found = false;
2
    for(x=0; x<10 && !found; x++)
3
      for(y=0; y<10 && !found; y++)
4
        found = test(x, y);
5
6
    if (found)
7
      use(x, y);

Man sieht sofort in den Schleifenbedingungen dass sie frühzeitig (bei 
erfolgreicher Suche) abgebrochen werden und man brauch das "found" in 
der Regel sowieso später, da man wissen möchte ob die Suche erfolgreich 
war oder nicht.
Die Alternative die Schleifenvariablen 'x' und 'y' nach der Suche erneut 
auf gültige Werte zu testen, ist viel zu fehleranfällig.

Das "use(x, y)" in die Schleife packen und und danach sofort abbrechen, 
ist noch viel unübersichtlicher, da die beiden Schritte "erst mal 
suchen" und "wenn gefunden dann benutzen", ineinander verschachtelt 
werden und somit der Programmfluss schlecht ersichtlich ist.

von Falk B. (falk)


Lesenswert?

@ Unbekannt Unbekannt (unbekannter)

>Diese "Wenn Prädikat dann Abbrechen-Befehl"-Konstruktionen kann man
>direkter so schreiben:

Endlich mal jemand mit Durchblick und klarer Ansage! Diese Diskussion 
ist sowas von hirnrissig! Mental gesunde Menschem müssen und sollten 
sich NICHT mit diese Josefschen Konstrukt beschäftigen, es sein denn, 
ihnen ist an der Nichtaufrechterhaltung ihrer mentalen Gesundheit 
gelegen.

von (prx) A. K. (prx)


Lesenswert?

Unbekannt Unbekannt schrieb:
> Man sieht sofort in den Schleifenbedingungen dass sie frühzeitig (bei
> erfolgreicher Suche) abgebrochen werden und man brauch das "found" in
> der Regel sowieso später, da man wissen möchte ob die Suche erfolgreich
> war oder nicht.

Deshalb ja auch der geliebte wie verhasste C Klassiker:
1
    for(x=0; x<10; x++)
2
      for(y=0; y<10; y++)
3
        if(test(x,y))
4
          goto found;
5
    fail();
6
found:
7
    run(x,y);

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Noch ein kleines Beispiel aus dem Kuriositätenkabinett:

In Fortran sind Unterprogramme mit mehreren Einstiegspunkten möglich.
Das folgende Beispiel zeigt eine Zählfunktion, die entweder aufgerufen
als

  icounter()

dann wird der aktuelle Inhalt der internen Zählvariable icnt
zurückgegeben und diese inkrementiert, oder als

  icounterinit(istart)

dann wird zusätzlich icnt auf einen neuen Startwert gesetzt:
1
      program test
2
        print *, icounter()
3
        print *, icounter()
4
        print *, icounterinit(100)
5
        print *, icounter()
6
        print *, icounter()
7
      end
8
9
      function icounterinit(istart)
10
        data icnt /0/
11
        icnt = istart
12
      entry icounter()
13
        icounter = icnt
14
        icnt = icnt + 1
15
      end

Ausgabe:
1
           0
2
           1
3
         100
4
         101
5
         102

Mit diesem Konstrukt kann man bspw. einen Zufallszahlengenerator
ohne die Verwendung einer globalen Statusvariable realisieren.

von (prx) A. K. (prx)


Lesenswert?

Offenbar mit Ähnlichem im Sinn war in C anfangs das Schlüsselwort 
"entry" reserviert.

: Bearbeitet durch User
von Uhu U. (uhu)


Lesenswert?

Yalu X. schrieb:
> Ähnlich geht es auch in Javascript, Ada, Perl, Fortran 90 (und neuer),
> Go, Swift und sicher noch etlichen weiteren Sprachen.

Aha, dann bin ich also durch jahrzehntelanges C-Programmieren 
verdorben... Ist halt doch eigentlich eine Scheiß-Sprache :-(

> In PHP gibt es
>   break n;
>
> wobei n angibt, wieviele der verschachtelten Schleifen verlassen werden
> sollen. Dabei entspricht break 1 einem break ohne Argument.

Dass die PHP-Fritzen einen Trick finden werden, der die gute Idee wieder 
in einen Mist umwandelt, den man lieber nicht will, war zu erwarten...

Yalu X. schrieb:
> In Fortran sind Unterprogramme mit mehreren Einstiegspunkten möglich.

Soll das jetzt etwa eine Anregung für Josef sein?

von Marten W. (goldmomo) Benutzerseite


Lesenswert?

Auch wenns OT ist, in C# kann man so etwas ähnliches mittels yield 
machen.
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Text;
5
using System.Threading.Tasks;
6
7
namespace ConsoleApplication1
8
{
9
    class Program
10
    {
11
        static void Main(string[] args)
12
        {
13
            foreach(int value in count(10))
14
            {
15
                Console.Write(value + " ");
16
            }
17
18
            Console.ReadKey();
19
        }
20
21
        static IEnumerable<int> count(int count)
22
        {
23
            for (int i = 0; i < count; i++)
24
            {
25
                yield return i;
26
            }
27
        }
28
    }
29
}

Ausgabe:
1
0 1 2 3 4 5 6 7 8 9

von Unbekannt U. (Gast)


Lesenswert?

Marten W. schrieb:
> Auch wenns OT ist, in C# kann man so etwas ähnliches mittels yield
> machen.

Auch wieder nur eine halbherzige Flickschusterei. Es ist erstaunlich, 
wie "schwach" viele der verbreiteten Programmiersprachen entworfen 
wurden. Teils historisch bedingt, teils weil man auf allen Hochzeiten 
tanzen möchte.

Sei's drum. Das "yield"-Konzept ist den mehr als 50 Jahren alten 
"Koroutinen" entliehen:

    http://en.wikipedia.org/wiki/Coroutine

von Karl H. (kbuchegg)


Lesenswert?

Josef G. schrieb:
>
1
> *PGM DEMO
2
> *CON STRG -??
3
> *AUT AA. /00  BB. /00
4
> *BEGN
5
> *L.JP
6
>   1LFEED
7
>   *L.JP
8
>     1ADDLOC /01
9
>     =DECR AA.
10
>   *HERE
11
>     1PRINTN /08 AA.
12
>   *RP.S AA.
13
>   1LFEED
14
> *HERE
15
>   1SETLOC /f0
16
>   *L.JP
17
>     1PRINTS /02 STRG
18
>   *HERE
19
>     1PRINTS /00 STRG
20
>     1INPUTN /08 AA.
21
>     1INPUTN /0c BB.
22
>     1LFEED
23
>   *RP.Z BB.
24
>   1  oGET AA.  oAND /f8  oSTO BB.
25
> *RP.Z BB.
26
> *RETN
27
>

Gratulation.

Ich dachte ich hätte schon vieles gesehen aber so was hab ich auch noch 
nie gesehen. Mit Ausnahme vielleicht von meiner ersten Begegnung mit APL 
ist es mir seit Jahrzehnten nicht mehr passiert, dass ich in angeblichem 
Quelltext nicht das Geringste verstehe. Noch nicht mal ansatzweise
Da sag noch mal einer, C wäre kryptisch.

von (prx) A. K. (prx)


Lesenswert?

Erinnert entfernt an manchen frühen Assemblercode, oder irgendwelche 
Drucker- oder Job-Controls.

Frühe Assembler waren mitunter ähnlich kryptisch:
http://en.wikipedia.org/wiki/COMPASS/Sample_Code

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?


von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Karl Heinz schrieb:

> Gratulation.
>
> Ich dachte ich hätte schon vieles gesehen aber so was hab ich auch noch
> nie gesehen. Mit Ausnahme vielleicht von meiner ersten Begegnung mit APL
> ist es mir seit Jahrzehnten nicht mehr passiert, dass ich in angeblichem
> Quelltext nicht das Geringste verstehe. Noch nicht mal ansatzweise
> Da sag noch mal einer, C wäre kryptisch.

Das ist doch ganz einfach. Josefs Code ist absolut intuitiv und auch für 
den Nicht-Eingeweihten komplett lesbar!

Ich erklärs Dir:

> *PGM DEMO

Wir beginnen ein Programm namens "DEMO". Beachte die Großbuchstaben. 
Kleinbuchstaben sind nicht erlaubt. Warum? Josef benutzt immer noch 
einen 5-Bit-Lochkartenstanzer.

> *CON STRG -??

Einer der einfachsten Befehle: Schreibe auf die Console. Das "-??" ist 
ein geheimer Code für die Ausgabe von:

   HALLO KARL HEINZ, HEUTE IST MITTWOCH, DER 29. OKTOBER,
   WIR HABEN 12:37 UND EINE ZIMMERTEMPERATUR VON 22 GRAD.
   MORGEN WIRD ES REGNEN UND KALT.

   BITTE GIB NUN ZWEI ZAHLEN EIN:

Wohlgemerkt: Nur Großbuchstaben. Daran müsste Josef nochmal arbeiten.

> *AUT AA. /00  BB. /00

AUT steht für AUTOMATISCHE EINGABE VON ZAHLEN. Hier nennt Josef diese 
AA. und BB, beide vorbelegt mit 00. Das "/" vor den Zahlen 00 soll nur 
den geneigten Leser verwirren: Es handelt sich NICHT um eine Division 
durch Null! Merken!

> *BEGN

Wir beginnen endlich - nach der Eingabe von 2 Zahlen - mit der 
Abarbeitung des Programms. Das Kürzel BEGN statt BEGINN ist besonders 
pfiffig. Josef spart damit Vokale, macht das Programm kompakter und für 
NSA-Mitarbeiter schwieriger. Das ist ABSICHT!

> *L.JP

Oh, jetzt kommts richtig heftig: Das L steht für LOOP, das wissen nur 
die wirklich eingeweihten! Aber macht nichts, ich habe dies nach 
nächtelangem  Einsatz von 1024-Bit-Key-Entschlüsselungsroutinen auf 
einer alten Cray im Münchener Museum ganz klar herausgefunden! Und JP 
steht selbstverständlich
JAM POT, achnee JUMP. Wir springen also jetzt mit Lichtgeschwindigkeit 
in eine Schleife..... festhaaaaaaalten!

>   1LFEED

Eine der einfachsten Anweisungen überhaupt. Wörtlich übersetzt heisst 
das

   Mach ein Line Feed

Warum Josef hier FEED komplett ausschreibt, ist mir absolut rätselhaft. 
Er hätte es auch mit Q abkürzen können, um der Programmiersprache noch 
etwas mehr Transparenz zu geben. Denn

    1 LQ

wäre viel viel verständlicher gewesen, oder nicht? Wenn man nun noch die 
Transponierung von L nach I vornimmt, steht da

    1 IQ

welches klar die Intelligenz dieses phänomenalen Programms ausdrücken 
soll.

Aber wir schweifen ab... zurück zum Code:

>   *L.JP

Tja, kennen wir schon: Wir springen in die innere Schleife. Weitere 
Kommentare sind hier überflüssig.

>     1ADDLOC /01

DAAAAAS ist der absolut Knüller! Wir addieren auf die erste Variable 
(wegen der 1 vor ADDLOC, gemeint ist also AA) eine 1.

>     =DECR AA.

Und hier dekrementieren wir wieder AA. Und jetzt das verblüffendste: Der 
Wert von AA ist danach wieder ABSOLUT IDENTISCH mit der eingegebenen 
Zahl!!!!!11111

>   *HERE

Das HERE steht selbstverständlich nicht für HERE, also "hier", sondern 
für "da", also THERE! Hier müsste der Compiler eigentlich mit einem 
Syntax-Error aussteigen. Aber Josef hat vorgesorgt. Bei einem 
Syntax-Error googelt der Compiler automatisch nach der Bedeutung des 
Wortes, um dann den Sinn einfach umzudrehen! Das ist GENIAL!!!! So 
werden Programmierfehler automatisch korrigiert!

>     1PRINTN /08 AA.

Tja, PRINTN ist wirklich ziemlich geschwätzig. PT hätte mir ja besser 
gefallen. Aber was passiert hier? Ganz einfach: Die Zahl AA wird 
gedruckt - und zwas auf die Console. Und Hurra! Das Programm gibt exakt 
die Zahl wieder aus, die der User vorher eingegeben hat! Das ist 
Wahnsinn! Ein Programm, welches die Gedanken des Anwenders lesen (und 
sicher auch verstehen!) kann!

Die /08 sind klar? Nein? Ganz einfach: "Formatiere die Ausgabe 
rechtsbündig auf 8 Stellen.". Wenn Josef linksbündig meint, dann 
schreibt er "08/", wenn er zentrieren will, dann "/08/". Echt pfiffig.

>   *RP.S AA.

Okay, das ist auf den ersten Blick ziemlich verwirrend hier, aber ist 
für den Experten sofort klar: Das ist ein einfacher NOP. Kennt ja jeder. 
Das genialische: Man kann bei Josefs Rechner dem NOP ein Argument 
mitgeben! Jawoll! Es sollen hier also soviele NOPs gemacht werden, wie 
AA als Zahl bedeutet.

>   1LFEED

Mittlerweile ist die Console nicht mehr busy und kann endlich eine neue 
Zeile ausgeben. Ist sinnig, sonst steht der Druckerkopf von Josefs 
Teletype-Terminal noch hinter der ausgegebenen Zahl und versperrt den 
Blick auf diese.

> *HERE

Nochmal: DA! Guck DA! Also THERE!

>   1SETLOC /f0

Oh, jetzt wird Josefs Programm prozessor-spezifisch. Das heißt soviel 
wie:

    LOKALISIERE DEN VERDAMMTEN F0-BUG AUF DIESER CPU!

Damit beugt Josef einem Fehler von INTEL vor, welcher das Programm ohne 
diese Vorsichtsmaßnahme zum Crash bringen könnte. Aber noch ist Josefs 
Rechner nicht auf INTEL-Rechner portiert. GUT SO!

>   *L.JP

Springe in Schleife...

>>     1PRINTS /02 STRG

Jetzt wird nochmal der Begrüßunssting gedruckt, also eigentlich den von 
oben:

   HALLO KARL HEINZ, HEUTE IST MITTWOCH, DER 29. OKTOBER,
   WIR HABEN 12:37 UND EINE ZIMMERTEMPERATUR VON 22 GRAD.
   MORGEN WIRD ES REGNEN UND KALT.

Durch die Formatierung /02 wird daraus aber:

   HA

Hier hat Josef sich geirrt. Es muss sich um einen Tippfehler handeln, 
denn es hätte /03 heißen müssen. Nur dann würde diese Message auch einen 
Sinn ergeben:

   HAL

Ja, es handelt sich um HAL aus "Odyssee 2001"! Das Rätsel ist gelüftet! 
Josef wars!

>   *HERE
>     1PRINTS /00 STRG
>     1INPUTN /08 AA.
>     1INPUTN /0c BB.
>     1LFEED
>   *RP.Z BB.

Diese Befehle habe ich oben schon erklärt, daher überspringe ich das.

>   1  oGET AA.  oAND /f8  oSTO BB.

Das ist wieder ganz intuitiv. frei übersetzt:

   SCHNAPPE DIR AA UND SPEICHERE DAS IN BB

Ja. Jetzt hat der Rechner die Gedanken des Users von AA nach BB kopiert 
und für die Ewigkeit gespeichert...

> *RP.Z BB.

Kennen wir auch schon: Das war der NOP. Bevor wir also gleich das 
Programm beeenden, ärgern wir den Rechner nochmal mit unsinnigen 
Befehlen. Und das gleich BB-mal!

> *RETN

Kennt jeder: RETURN. Fragt sich nur wohin? Aber das werden wir dann in 
der nächsten Stunde erklären.... brzzzz krrrrchs....

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Karl Heinz schrieb:
> Josef G. schrieb:
>>> *PGM DEMO
> jede Menge Zeugs entfernt

>> *RETN
>>
> Gratulation.
Auch von mir beste Wünsche. Ich habe selten so etwas fehlerträchtiges 
und unlesbares gesehen. Trotz Franks ausgezeichneter Erklärung der 
einzelnen Programmteile bin ich jetzt froh, mir keinerlei Emulazionator 
für dieses ulkige Kauderwelsch geladen/kompiliert/eingetreten zu haben.
Vielen Dank, Frank, das du so viel deiner Zeit geopfert hast - 
andererseits schade drum...

Da ist ja selbst TMS320 Assembler eine wahre Wohltat gegen:
1
loop:
2
        sovm        
3
        ; read in and store new input value
4
        ldpk  0
5
        call  AD_read
6
        ldpk    4
7
        sacl    INPUT           ; keep copy of dry input
8
        lac  *+    ; read from buffer
9
        sacl  OUTPUT    ; output data
10
        cmpr  0
11
        bbz  nowrap2,*,AR1  
12
        lrlk  AR2,BUF
13
        rxf
14
nowrap2:
15
        ; do level scaling on  wet and add unchanged input 
16
        lt      OUTPUT    ; 
17
        mpy     WET             ; scale wet signal
18
        apac
19
        addh    INPUT          ; get original input value
20
        sach    TMP
21
        lac     TMP             ; prepare final output for AIC
22
        ldpk    0
23
        sacl    scratch3             ; do output
24
        call  AD_write
25
done:
26
        b       loop

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@Frank M. (ukw) Benutzerseite

YMMD!!!!

Das ist Elektronikcomedy!

von Uhu U. (uhu)


Lesenswert?

Frank M. schrieb:
> Josef benutzt immer noch einen 5-Bit-Lochkartenstanzer.

Sollte er etwa seinem Hex-Code untreu geworden sein?

von Josef G. (bome) Benutzerseite


Lesenswert?

Frank M. schrieb:
> Karl Heinz schrieb:

>> *CON STRG -??
Es wird eine String-Konstante mit Wert "??" vereinbart.

>> *AUT AA. /00  BB. /00
Es werden die 1-Byte-Variablen AA. und BB. vereinbart. AUT steht für
Automatische Installation auf Stack A beim Starten des Programms.

>>     1ADDLOC /01
Erhöht den Positionszeiger für die Ein/Ausgabe.

>>     =DECR AA.
>
> Und hier dekrementieren wir wieder AA. Und jetzt das
> verblüffendste: Der Wert von AA ist danach wieder ABSOLUT
> IDENTISCH mit der eingegebenen Zahl!!!!!11111

Dekrementieren ist richtig, "wieder" ist falsch. Der Wert ist
danach nicht identisch. Aber weil das =DECR beim erstenmal
übersprungen wird, wird zuerst die unveränderte Zahl ausgegeben.

>>   *HERE
>
> Das HERE steht selbstverständlich nicht für HERE, also "hier",
> sondern für "da", also THERE!

Der Unterschied von here und there im Englischen ist mir durchaus
klar. Aber here sieht besser aus als there, und ganz falsch ist es
auch nicht, wenn man es nicht liest als "jump here", was tatsächlich
falsch wäre, sondern als "hier ist das Sprungziel".

>>   *RP.S AA.
>
> Das ist ein einfacher NOP.
Repeat falls AA. "set", also "not zero".

>>   1SETLOC /f0
Setze Positionszeiger.

>> *RP.Z BB.
>
> Kennen wir auch schon: Das war der NOP.
Repeat falls BB. zero.

>> *RETN
>
> Kennt jeder: RETURN. Fragt sich nur wohin?

In diesem Fall in die Kommandozeile. Es wäre aber auch möglich,
das Programm aus einem anderen Programm heraus aufzurufen.

Alle Operationen 1xxxx sind nicht Teil der Sprache selber,
sondern Teil der Software der Test-Steckkarte in Steckplatz 1.
Eigenschaft der Sprache ist es aber, wie diese Operationen
beim Compilieren eingebunden und bei der Programm-Ausführung
aufgerufen werden.

von Uhu U. (uhu)


Lesenswert?

Josef, geh in die Apotheke und kauf dir für 20 Cent Humor...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Uhu Uhuhu schrieb:
> Frank M. schrieb:
>> Josef benutzt immer noch einen 5-Bit-Lochkartenstanzer.
>
> Sollte er etwa seinem Hex-Code untreu geworden sein?

Er hat einen speziellen Lochkartenstanzer dafür:

Er kann eckige und runde Löcher stanzen. Damit vervielfachen sich die 5 
Bits von (2^5 = 32) auf 5 Trits (3^5 Möglichkeiten = 243)!

Und schon hat er Großbuchstaben, Ziffern und Punkte. Das reicht - auch 
für Hex-code. Der Rest ist zukünftigen Erweiterungen vorbehalten ;-)

: Bearbeitet durch Moderator
von Waldemar Z. (waldemar_z39)


Lesenswert?

> Er kann eckige und runde Löcher stanzen. Damit vervielfachen sich die 5
> Bits von (2^5 = 32) auf 5 Trits (3^5 Möglichkeiten = 243)!

Um noch etwas genauer zu werden:
Er kann die Basis über die Anzahl der Ecken einstellen.
Die runden Löcher sind ganz einfach eckige Löcher mit sehr vielen Ecken.
Somit hat er den Quanten-Computer erfunden.
Mit der Differenzial- und der Integralrechnung kann dann noch bestimmt 
werden, wieviele Zyklen das Programm benötigt, um den Programmierer in 
die Klapse einzuliefern, nach dem er es fertiggestellt hat. ;-DDD

von G. C. (_agp_)


Lesenswert?

Frank M. (ukw) schrieb:

>> *AUT AA. /00  BB. /00

> AUT steht für AUTOMATISCHE EINGABE VON ZAHLEN. Hier nennt Josef diese
> AA. und BB, beide vorbelegt mit 00. Das "/" vor den Zahlen 00 soll nur
> den geneigten Leser verwirren: Es handelt sich NICHT um eine Division
> durch Null! Merken!

Ich wollte schon fragen, ob das eine Zeile aus Josef's Fahrzeugschein 
ist. Sah mir ganz danach aus. Aber jetzt wo du das aufgeklärt hast ...

(nicht böse gemeint Josef, bezüglich deiner Codierungen lebst du 
anscheinend wohl in deiner eigenen unzugänglichen Welt ;))

von Klaus W. (mfgkw)


Lesenswert?

g. c. schrieb:
> (nicht böse gemeint Josef, bezüglich deiner Codierungen lebst du
> anscheinend wohl in deiner eigenen unzugänglichen Welt ;))

Ist in C ja auch nicht viel anders, wenn man es genau nimmt.

von Waldemar Z. (waldemar_z39)


Lesenswert?

>Ist in C ja auch nicht viel anders, wenn man es genau nimmt.

Ähmm... Hochsprachen wurden ja wohl ursprünglich entwickelt, um sich die 
Arbeit zu erleichtern und nicht zu erschweren, damit man sich weniger um 
den ganzen Kram auf Bit-Ebene kümmern muss usw. (d.h. im Vordergrund 
steht nur das Problem, das mit möglichst wenig Aufwand gelöst werden 
soll), um die Lesbarkeit und Wiederverwendbarkeit des Codes zu 
verbessern.
Seine kryptischen Konstrukte sind aber schwer durchzublicken.
Das sieht eher nach korruptem Assembler aus. Assembler ist sogar 
einfacher zu lesen...

Achja... Eine anständige Dokumentation ist ja wohl das wichtigste, wenn 
man vom Nutzen überzeugen möchte.
Ansonsten, wieso sollte ich z.B. von C/C++
umsteigen, wenn damit sowieso schon fast alles möglich ist?

Ein Vorteil der Technik ist natürlich, dass solche Programme auf 
beliebigem System ablaufen können (portabilität).
Ein großer Nachteil ist, dass der erzeugte Zwischencode eben nicht nativ 
ist, man für den Ablauf eines solchen Programms also unbedingt ein 
Betriebssystem braucht, welches nur sehr schwer bspw. auf einen 
Mikrocontroller wg. zu kleinen Speichern zu bekommen ist.
Weiterer Nachteil: Ausführungszeit ist größer als bei nativem Code.

von Eric B. (beric)


Lesenswert?

Karl Heinz schrieb:

> In normalem C wäre das ja im Grunde (wenn ich das richtig verstanden
> habe)
>
1
>    xyz;
2
> 
3
>    while( Abbruchbedingung ) {
4
>      abc;
5
>      xyz;
6
>   }
7
>
>
> wobei xyz bzw. abc für irgendwelche nicht triviale Codeteile stehen.
>
> Solange die Codeteile nicht zu komplex sind, könnte man das auch so
> schreiben
>
1
>    for( xyz; Abbruchbedingung; xyz )
2
>      abc;
3
>
> ich finde allerdings die erste Variante mit dem while trotzdem besser.

oder halt
1
while (xyz, bedingung)
2
{
3
   abc;
4
}
falls xyz nicht zu complex ist. Wenn schon, dann könnte man das noch
in einer Funktion stecken, die die Auswertung der Bedingung 
zurückliefert:
1
while (xyz_funktion())
2
{
3
   abc;
4
}

Aber meist reicht deine erste Variante, und ein guter Compiler
wird das schon optimieren.

von Josef G. (bome) Benutzerseite


Lesenswert?

Eric B. schrieb:
> Wenn schon, dann könnte man das noch in einer Funktion
> stecken, die die Auswertung der Bedingung zurückliefert

Ist auch genau das, was ich geschrieben hatte:

Josef G. schrieb:

>> *L.JP          / springt zu *HERE
>>   oper1
>>   oper2
>> *HERE
>>   oper3
>>   oper4        / weist VAR einen Wert zu
>> *RP.Z VAR      / springt zu oper1 falls VAR = zero
>
>> In C würde man hier eine function definieren, welche
>> oper3/4 ausführt und den Rückgabewert VAR erhält.
>> Und man würde eine while-Schleife verwenden, welche
>> oper1/2 ausführt, solange die function Null liefert.

von Karl H. (kbuchegg)


Lesenswert?

Danke Frank!


Josef schrub

> *RP.S AA.
> Repeat falls AA. "set", also "not zero".
> *RP.Z BB.
> Repeat falls BB. zero.


Ja, das ist natürlich intuitiv. S ist das Gegenteil von Z, so wie 'set' 
das Gegenteil von 'zero' ist.

Josef, Josef. Ich denke, es wird dir immer ein unlösbares Rätsel 
bleiben, warum du einfach nicht den Durchbruch schaffst.

von Karl H. (kbuchegg)


Lesenswert?

Nicht das es mich wirklich interessiert.
Aber

manche Zeilen fangen mit einem '*' an, manche mit einer 1, eine ist 
dabei, die mit einem = anfängt.

Hat das irgendwas zu bedeuten, zb das die einen Zeilen nur Montags 
gelten und die anderen nur in Monaten mit 'R'? Oder kann man die erste 
Spalte einer Zeile nach Gutdünken verwenden?

Es sieht ja fast so aus, als ob alle Zeilen, die irgendwas mit 
Flusskontrolle zu tun haben, mit einem '*' ingeleitet werden, während 
alle 'normalen' Anweisungen mit einer '1' beginnen, mit Ausnahme des '=' 
im DEC. Da wird das = wohl anzeigen, dass das Ergebnis wieder im selben 
Register abgelegt werden soll (was nebenbei bemerkt eigentlich recht 
normal wäre, sonst würde man ja auch einen SUB benutzen).
Aber diese Erklärung scheint mir in Anbetracht der restlichen 
Komplexität als etwas zu banal. Es wäre zwar logisch, denn eigentlich 
braucht diese Sonderzeichen in Wirklichkeit kein Mensch, daher wäre das 
ein gefundenes Fressen für Josef, aber irgendwie auch wieder zu 
naheliegend. Da muss noch mehr dahinter stecken.

: Bearbeitet durch User
von Eric B. (beric)


Lesenswert?

Karl Heinz schrieb:
> Da muss noch mehr dahinter stecken.

http://etherealmind.com/humour-men-vs-women-machine-knobs/

s/Woman/Josef/g

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Karl Heinz schrieb:
> Es sieht ja fast so aus, als ob alle Zeilen, die irgendwas mit
> Flusskontrolle zu tun haben, mit einem '*' ingeleitet werden, während
> alle 'normalen' Anweisungen mit einer '1' beginnen, mit Ausnahme des '='
> im DEC. Da wird das = wohl anzeigen, dass das Ergebnis wieder im selben
> Register abgelegt werden soll (was nebenbei bemerkt eigentlich recht
> normal wäre, sonst würde man ja auch einen SUB benutzen).

Ja, genau so habe ich es mir auch erklärt. Ich weiß - genauso wie Du - 
überhaupt nicht, was diese zusätzliche Redundanz für einen Zweck hat. 
Ich glaube nicht, dass Abweichungen - wie zum Beispiel

   =LFEED

statt

   1LFEED

oder

   =RP.S AA.

statt

   *RP.S AA.

irgendwie einen Sinn ergeben. Diese Zeichen vor jedem Befehl sind 
irgendwie hyperfluid.

Aber vielleicht ist die Erklärung ganz einfach: Wenn schon kryptisch, 
dann richtig!

P.S.
Meine Vermutung: Josefs Parser ist wahrscheinlich ziemlich einfach 
gestrickt. Diese Sonderzeichen unterstützen diesen wohl bei der 
Erkennung.

: Bearbeitet durch Moderator
von Josef G. (bome) Benutzerseite


Lesenswert?

Karl Heinz schrieb:
> Es sieht ja fast so aus, als ob alle Zeilen, die irgendwas mit
> Flusskontrolle zu tun haben, mit einem '*' ingeleitet werden,

Genauso ist es.

> während alle 'normalen' Anweisungen mit einer '1' beginnen,
> mit Ausnahme des '=' im DEC.

Die mit 1 beginnenden Anweisungen werden von der Test-Steckkarte
in Steckplatz 1 ausgeführt. Die mit = beginnenden Anweisungen
sind interner Bestandteil der Sprache.

Josef G. schrieb:
> Alle Operationen 1xxxx sind nicht Teil der Sprache selber,
> sondern Teil der Software der Test-Steckkarte in Steckplatz 1.
> Eigenschaft der Sprache ist es aber, wie diese Operationen
> beim Compilieren eingebunden und bei der Programm-Ausführung
> aufgerufen werden.

von Josef G. (bome) Benutzerseite


Lesenswert?

Frank M. schrieb:
> Meine Vermutung: Josefs Parser ist wahrscheinlich ziemlich einfach
> gestrickt. Diese Sonderzeichen unterstützen diesen wohl bei der
> Erkennung.

Richtig.

Bei den von den Steckkarten ausgeführten Anweisungen kommt als
weiterer Vorteil hinzu, dass Namens-Konflikte vermieden werden.

von Eric B. (beric)


Lesenswert?

Josef G. schrieb:

> Die mit 1 beginnenden Anweisungen werden von der Test-Steckkarte
> in Steckplatz 1 ausgeführt. Die mit = beginnenden Anweisungen
> sind interner Bestandteil der Sprache.

Das heisst, wenn ich de "Test-Steckkarte" in "Steckplatz 2" stecke, muss 
ich mein Programm neu schreiben und compilieren? o_O

von Uhu U. (uhu)


Lesenswert?

Josef G. schrieb:
> Die mit 1 beginnenden Anweisungen werden von der Test-Steckkarte
> in Steckplatz 1 ausgeführt.

D.h.: wenn du deine Steckkarten mischst, läuft das Programm nicht mehr.

Das ist eine echte Innovation, nach der Heere von Informatikern seit 60 
Jahren gesucht haben, aber nie fündig wurden.

von Karl H. (kbuchegg)


Lesenswert?

Josef G. schrieb:
> Frank M. schrieb:
>> Meine Vermutung: Josefs Parser ist wahrscheinlich ziemlich einfach
>> gestrickt. Diese Sonderzeichen unterstützen diesen wohl bei der
>> Erkennung.
>
> Richtig.

Es gibt von Nikolaus Wirth ein kleines Büchlein über Compilerbau. Das 
ist auch für Nicht-Informatiker verständlich. Ich würde dir den Erwerb 
und das Durcharbeiten desselben extremst ans Herz legen.

von Josef G. (bome) Benutzerseite


Lesenswert?

Eric B. schrieb:
> Das heisst, wenn ich de "Test-Steckkarte" in "Steckplatz 2" stecke, muss
> ich mein Programm neu schreiben und compilieren? o_O

Nein.

Josef G. schrieb:
> Auf die Karten
> wird über die Steckplatz-Nummer zugegriffen, das erfolgt indirekt
> über eine Ersetzungstabelle. Wenn man eine Karte in einen anderen
> Steckplatz steckt, muss man nur diese Tabelle ändern.

Ergänzend gibt es ein Kommando zur Vertauschung von
Steckplatz-Nummern in fertig kompilierten Programmen.

von (prx) A. K. (prx)


Lesenswert?

Frank M. schrieb:
> Meine Vermutung: Josefs Parser ist wahrscheinlich ziemlich einfach
> gestrickt.

Yacc gibts seit 1975. ;-)

von Karl H. (kbuchegg)


Lesenswert?

Uhu Uhuhu schrieb:
> Josef G. schrieb:
>> Die mit 1 beginnenden Anweisungen werden von der Test-Steckkarte
>> in Steckplatz 1 ausgeführt.
>
> D.h.: wenn du deine Steckkarten mischst, läuft das Programm nicht mehr.
>
> Das ist eine echte Innovation, nach der Heere von Informatikern seit 60
> Jahren gesucht haben, aber nie fündig wurden.

Allerdings. Das ist mal was Neues.
Normalerweise versucht man ja um jeden Preis, so einen Zustand zu 
vermeiden.

Wie weiter oben schon mal wer geschrieben hat: Wenn schon komplex, dann 
richtig komplex.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

A. K. schrieb:
> Yacc gibts seit 1975. ;-)

Ja, hat mir schon früher immer viel Spaß gemacht, mit yacc einen Parser 
zu bauen. Leider ist yacc aber für User, die weniger bis gar nicht mit 
unixoiden Systemen arbeiten, ziemlich unbekannt.

Mittlerweile bin ich davon aber weg und habe meine eigenen Libs, um 
Sprachen zu entwickeln und diese zu parsen.

von (prx) A. K. (prx)


Angehängte Dateien:

Lesenswert?

Fall jemand denkt, Compiler müssten unbedingt riesige und komplexe 
Gebilde sein: Im Anhang ein einfacher Compiler für Z80 und ein 
Beispielprogramm, Quelle und Resultat. Die Sprache erinnert eher an 
einen strukturierten Assembler, aber das war Absicht und ist hier im 
Thread ja auch nicht anders.

: Bearbeitet durch User
von Josef G. (bome) Benutzerseite


Lesenswert?

Karl Heinz schrieb:
> Normalerweise versucht man ja um jeden Preis, so einen Zustand zu
> vermeiden.

Die Aussage ist ja nach meinem obigen Beitrag wohl hinfällig.
Beitrag "Re: Gibt es eine Programmiersprache mit diesem Schleifentyp?"

von Yalu X. (yalu) (Moderator)


Lesenswert?

Frank M. schrieb:
> Ja, hat mir schon früher immer viel Spaß gemacht, mit yacc einen Parser
> zu bauen. […]
>
> Mittlerweile bin ich davon aber weg

Yacc und Bison sind mittlerweile ziemlich aus der Mode gekommen. Um sie
für nichtriviale Dinge benutzen zu können, muss man wissen, wie ein
LALR-Parser-funktioniert und wie er durch den Parsergenerator erzeugt
wird. Nur dann können die Fehlermeldungen richtig gedeutet und die
angezeigten Konflikte in ihrer Relevanz bewertet werden.

Wenn jemand aber so viel Wissen in sich vereint, ist es für ihn ein
Leichtes, einen Parser von Hand zu schreiben (ggf. unter Zuhilfenahme
einer entsprechenden Bibliothek). Das mag zwar etwas mehr Tipparbeit
bedeuten als wenn ein Generator zum Einsatz kommt. Da ein Compiler aber
nicht nur aus dem Parser besteht, sondern der Parser nur einen kleinen
Teil des Ganzen ausmacht, fällt dieser Mehraufwand praktisch überhaupt
nicht ins Gewicht und wird durch die größere Flexibilität, die man mit
einem handgeschrieben Parser hat, mehr als wett gemacht.

von (prx) A. K. (prx)


Lesenswert?

Yalu X. schrieb:
> Da ein Compiler aber
> nicht nur aus dem Parser besteht, sondern der Parser nur einen kleinen
> Teil des Ganzen ausmacht,

Mein vorhin gezeigter Compiler besteht praktisch nur aus dem Parser. ;-)
Der Code kommt direkt aus dem Parser raus, keine Zwischendarstellung. 
Mehr als dieses eine File gibts nicht, das ist der ganze Compiler.

Sicher, für ernsthafte und grosse Compiler ist das nicht unbedingt der 
beste Weg. Aber für einfache kleine Dinge ist das ungemein praktisch. So 
hatte ich auch mal einen Dekoder für Intel/Microsoft-Objektfiles gebaut, 
und einen Encoder in Yacc dazu, der den Output des Dekoders wieder zu 
einem Objektfile zusammen baute. Um solche Files in Textform einfach 
modifizieren zu können.

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

A. K. schrieb:
> Mein vorhin gezeigter Compiler besteht praktisch nur aus dem Parser. ;-)

und

> Aber für einfache kleine Dinge ist das ungemein praktisch.

Zweimal Zustimmung :)

Für die kleinen Dinge, wo auch die Übersetzungsgeschwindigkeit nicht die
große Rolle spielt, kann man sich auch mal Pyparsing anschauen:

  http://pyparsing.wikispaces.com/

Wenn man es ernsthaft benutzen möchte, sollte man aber das auf der
Webseite angepriesene Buch kaufen. Die Online-Dokumentation ist eher
als ergänzende Referenz dazu zu sehen.

Edit:

Nein, man muss es nicht kaufen (ist auch gar nicht so leicht irgendwo zu
bekommen). Hier kann man es online lesen oder herunterladen:

  http://it-ebooks.info/book/245/

: Bearbeitet durch Moderator
von Karl H. (kbuchegg)


Lesenswert?

Yalu X. schrieb:

> Yacc und Bison sind mittlerweile ziemlich aus der Mode gekommen. Um sie
> für nichtriviale Dinge benutzen zu können, muss man wissen, wie ein
> LALR-Parser-funktioniert und wie er durch den Parsergenerator erzeugt
> wird. Nur dann können die Fehlermeldungen richtig gedeutet und die
> angezeigten Konflikte in ihrer Relevanz bewertet werden.

Was ich an Yacc nie mochte, ist genau dieser LALR Parser. Ich hatte 
damit immer Schwierigkeiten in der Grammatik-Definition. Ok, das mag 
auch an meiner Ausbildung liegen, in der wir im Compilerbau uns nur auf 
LL(1) Parser konzentriert haben. Von daher war ich es gewohnt, bereits 
die Grammatik auf LL(1) Verhalten zu trimmen, was ich ehrlich gesagt nie 
als Nachteil empfand.
Gerade mit Yacc hatte ich bei den wenigen Versuchen auch immer das 
Problem, dass ich die Statemachine als sehr schwierig zu debuggen 
empfand. Etwas, das mir bei einem rekursiven Abstieg überhaupt keine 
Probleme machte.
Von daher wurde dann der COCO zu meinem Lieblings Parser Generator. Auch 
wenn es den meines Wissens auch als tabellenbasierenden Parser gibt, 
bevorzuge ich trotzdem die Variante, die einen rekursiven Abstieg 
erzeugt. Im Debuggen ist das meiner Meinung nach immer noch unschlagbar 
einfach, wenn man sich wieder mal in der Grammatik einen Hund 
reingehauen hat.

> nicht ins Gewicht und wird durch die größere Flexibilität, die man mit
> einem handgeschrieben Parser hat, mehr als wett gemacht.

Da ich sowieso auch per Hand einen rekursiven Abstieg schreiben würde, 
lass ich mir diese Arbeit gerne von einem Generator abnehmen :-)
Der macht dann nicht die vielen kleinen Fehlerchen, die ich selbst bei 
sorgfältigstem Arbeiten einbauen würde (wieder mal ein nextSym Aufruf 
versemmelt, so was kann einem den ganzen Tag versauen :-)

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Karl Heinz schrieb:
> Ok, das mag
> auch an meiner Ausbildung liegen, in der wir im Compilerbau uns nur auf
> LL(1) Parser konzentriert haben.

Das ist ja auch die verkehrte Reihenfolge ;-). Ich hatte mich dank 
entsprechendem Bedarf zuerst mit Compiler und Yacc beschäftigt. Die 
Vorlesung "Compilerbau" folgte später.

PS: Das war in den 80ern. Da war die Auswahl solcher Werkzeuge noch 
etwas kleiner als heute. Auch der PLZ Compiler entstand damals, wie man 
unschwer am K&R Code erkennen kann. Es liegt in der Natur der Sache, 
dass über die Jahrzehnte bessere Werkzeuge entstehen.

: Bearbeitet durch User
von Josef G. (bome) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Noch etwas zum Thema Schleifenoptimierung: Der GCC dreht alle Schleifen
> – egal, ob for, while, do-while oder endlos mit break – so hin, dass die
> Abbruchbedingung am Ende liegt. Man muss sich darum als Programmierer
> also keine Gedanken machen.

Jede while-Schleife ist also in Wahrheit eine Schleife mit Hineinsprung.
Dies wird lediglich vor dem Programmierer verborgen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Josef G. schrieb:
> Jede while-Schleife ist also in Wahrheit eine Schleife mit Hineinsprung.

Nein. "Hinein" im Sinne von "Nicht an den Anfang" wird in eine 
while-Schleife nicht.

von Falk B. (falk)


Lesenswert?

@Josef G. (bome) Benutzerseite

>Jede while-Schleife ist also in Wahrheit eine Schleife mit Hineinsprung.
>Dies wird lediglich vor dem Programmierer verborgen.

Nö. Es wird nur vor dem Schleifeneintritt die Laufbedingung geprüft.

Deine Diskussion ist eine Endlosschleife ohne Heraussprung, komplementär 
zu deiner erfundenen Schleife mit Hineinsprung.

von Andreas P. (andip)


Lesenswert?

Yalu X. schrieb:
> Noch etwas zum Thema Schleifenoptimierung: Der GCC dreht alle Schleifen
> – egal, ob for, while, do-while oder endlos mit break – so hin, dass die
> Abbruchbedingung am Ende liegt. Man muss sich darum als Programmierer
> also keine Gedanken machen.

Rein Interessehalber: Das habe ich jetzt schon mehrfach gelesen. 
Andererseits hat einer meiner Profs behauptet, es würde einen 
Unterschied machen (dass der möglicherweise auf dem Stand der 80er 
stehen geblieben ist, schließe ich ausdrücklich nicht aus).
Hat jemand eine vertrauenswürdige Quelle oder sogar ein Schnipsel 
Beispielcode mit zugehörigem Auszug aus der Ausgabe des Compilers, 
wodurch das bestätigt wird?

Leider bin ich mit Google nicht fündig geworden und konnte auch selbst 
kein aussagekräfgiges Beispiel herbeizaubern. Letzteres liegt aber 
wahrscheinlich daran, dass meine Assembler-Kenntinsse auf dem Stand "ich 
weiß was es ist" sind...

Dass es in der Praxis zu 99,99% irrelevant ist, ist mir auch klar. Aber 
besagter Prof hat dazu auch eine Prüfungsfrage gestellt und ist voll 
davon überzeugt, deswegen interessier es mich eben doch ;-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Andreas P. schrieb:
> Hat jemand eine vertrauenswürdige Quelle oder sogar ein Schnipsel
> Beispielcode mit zugehörigem Auszug aus der Ausgabe des Compilers,
> wodurch das bestätigt wird?

Kannst du nicht einfach selbst ein Stück Code compilieren?

Nimm doch eine einfache Kopierschleife:
1
void
2
memorycopy(char *dst, const char *src, unsigned int i)
3
{
4
   for (unsigned j = 0; j < i; j++) {
5
      *dst++ = *src++;
6
   }
7
}

Compiliert auf dem Host (amd64) mit -Os gibt das:
1
        .file   "copy.c"
2
        .text
3
        .globl  memorycopy
4
        .type   memorycopy, @function
5
memorycopy:
6
.LFB0:
7
        .cfi_startproc
8
        xorl    %eax, %eax
9
.L2:
10
        cmpl    %eax, %edx
11
        jbe     .L5
12
        movb    (%rsi,%rax), %cl
13
        movb    %cl, (%rdi,%rax)
14
        incq    %rax
15
        jmp     .L2
16
.L5:
17
        ret
18
        .cfi_endproc
19
.LFE0:
20
        .size   memorycopy, .-memorycopy
21
        .ident  "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
22
        .section        .note.GNU-stack,"",@progbits

Der Schleifentest befindet sich hier am Anfang der Schleife, beim
Erreichen des Schleifenendes wird zu .L5 rausgesprungen, am Ende
der Schleife wird zum Test nach .L2 zurückgesprungen.

Gleicher Code mit dem AVR-GCC compiliert:
1
        .file   "copy.c"
2
__SP_H__ = 0x3e
3
__SP_L__ = 0x3d
4
__SREG__ = 0x3f
5
__tmp_reg__ = 0
6
__zero_reg__ = 1
7
        .text
8
.global memorycopy
9
        .type   memorycopy, @function
10
memorycopy:
11
/* prologue: function */
12
/* frame size = 0 */
13
/* stack size = 0 */
14
.L__stack_usage = 0
15
        mov r30,r22
16
        mov r31,r23
17
        add r20,r24
18
        adc r21,r25
19
        rjmp .L2
20
.L3:
21
        ld r18,Z+
22
        mov r26,r24
23
        mov r27,r25
24
        st X+,r18
25
        mov r24,r26
26
        mov r25,r27
27
.L2:
28
        cp r24,r20
29
        cpc r25,r21
30
        brne .L3
31
/* epilogue start */
32
        ret
33
        .size   memorycopy, .-memorycopy
34
        .ident  "GCC: (GNU) 4.7.2"

Hier wird zuerst (bedingungslos) zum Schleifentest am Ende der Schleife
nach .L2 gesprungen, bei negativem Test dann zurück zum Anfang nach .L3.

Bleibt sich völlig gleich, was der Compiler genau draus macht.

von Andreas P. (andip)


Lesenswert?

Jörg Wunsch schrieb:
> Kannst du nicht einfach selbst ein Stück Code compilieren?

Erst mal danke für deine Antwort! Das heißt, das ganze ist absolut vom 
Compiler abhängig und eine Aussage von wegen "das eine ist besser" ist 
scheinbar sinnlos, ohne die Toolchain und deren Einstellung sehr genau 
zu kennen (und anzugeben)...

Das Problem, das ich habe ist folgendes:
Aus diesem Code mit for()
1
int main(void)
2
{
3
  int b=0;
4
    for (int i=1; i<10; i*2)
5
    {
6
      asm volatile ("nop");
7
    b++;
8
    }
9
}

macht Atmel Studio folgendes:
1
000000c4 <main>:
2
int main(void)
3
{
4
  int b=0;
5
    for (int i=1; i<10; i*2)
6
    {
7
      asm volatile ("nop");
8
  c4:  00 00         nop
9
  c6:  fe cf         rjmp  .-4        ; 0xc4 <main>

und aus dem Beispiel mit while() hier:
1
int main(void)
2
{
3
  int b=0;
4
  int i=1;
5
  while(i<10)
6
  {
7
    i=i*2;
8
    asm volatile ("nop");
9
    b++;
10
  }
11
}

wird das hier:
1
000000c4 <main>:
2
3
4
#include <avr/io.h>
5
6
int main(void)
7
{
8
  c4:  84 e0         ldi  r24, 0x04  ; 4
9
  c6:  90 e0         ldi  r25, 0x00  ; 0
10
  int b=0;
11
  int i=1;
12
  while(i<10)
13
  {
14
    i=i*2;
15
    asm volatile ("nop");
16
  c8:  00 00         nop
17
  ca:  01 97         sbiw  r24, 0x01  ; 1
18
19
int main(void)
20
{
21
  int b=0;
22
  int i=1;
23
  while(i<10)
24
  cc:  00 97         sbiw  r24, 0x00  ; 0
25
  ce:  e1 f7         brne  .-8        ; 0xc8 <main+0x4>
26
  {
27
    i=i*2;
28
    asm volatile ("nop");
29
    b++;
30
  }
31
  d0:  80 e0         ldi  r24, 0x00  ; 0
32
  d2:  90 e0         ldi  r25, 0x00  ; 0
33
  d4:  08 95         ret

Also für meine (in Assembler ungeübten) Augen ein komplett anderer und 
vor Allem deutlich umfangreierer Code...also macht es scheinbar doch 
einen Unterschied?
Oder spielt mir hier die Optimierung des Compilers einen Streich?
Insbesondere verwirrt mich die doppelte main-Schleife beim Beispiel mit 
while() (und nein, mir ist nicht beim kopieren ein Fehler unterlaufen 
;-) ) Beide Beispiele sind mit absolut gleichen Einstellungen 
gleichzeitig kompiliert worden.

von Josef G. (bome) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Hier wird zuerst (bedingungslos) zum Schleifentest am Ende der Schleife
> nach .L2 gesprungen, bei negativem Test dann zurück zum Anfang nach .L3.

Das bestätigt meine Aussage:

Josef G. schrieb:
> Jede while-Schleife ist also in Wahrheit eine Schleife mit Hineinsprung.
> Dies wird lediglich vor dem Programmierer verborgen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Andreas P. schrieb:

> Also für meine (in Assembler ungeübten) Augen ein komplett anderer und
> vor Allem deutlich umfangreierer Code.

Klar, wenn der Quellcode was anderes tut … Hast du dir mal die
Warnungen angesehen?  Da sollte drin stehen:
1
foo.c: In function ‘main’:
2
foo.c:4:5: warning: statement with no effect [-Wunused-value]

Dein „b * 2“ in der for-Schleife ist das, was er damit meint: das
ist eine sinnlose Operation.

Vermutlich meintest du entweder „b *= 2“ oder „b = b * 2“.

Josef G. schrieb:
> Das bestätigt meine Aussage:

Aber nur, weil du dein selektives Wahrnehmungsfilter eingeschaltet
hast.  Ansonsten wäre dir aufgefallen, dass der völlig gleiche
Sourcecode selbst vom nahezu gleichen Compiler (GCC 4.7 vs. 4.8) nur
für eine andere Zielarchitektur halt genau andersherum compiliert
wird: erst der Test, dann die Schleife.

Aus Sicht der Programmiersprache ist dein Konstrukt also absolut
überflüssig, da er nichts anderes als die normale while-Schleife
darstellt, die man halt verschieden in Maschinencode umsetzen kann.

Auch eine dritte Variante ist noch drin, wenn man nämlich auf
maximale Geschwindigkeit optimieren lässt.  Dann wird der Test auf
vorzeitigen Schleifenabbruch vorgezogen und ein zweiter Test am
Ende der Schleife eingebaut.  Hier das Beispiel mit dem AVR-GCC:
1
        .file   "copy.c"
2
__SP_H__ = 0x3e
3
__SP_L__ = 0x3d
4
__SREG__ = 0x3f
5
__tmp_reg__ = 0
6
__zero_reg__ = 1
7
        .text
8
.global memorycopy
9
        .type   memorycopy, @function
10
memorycopy:
11
/* prologue: function */
12
/* frame size = 0 */
13
/* stack size = 0 */
14
.L__stack_usage = 0
15
        mov r30,r24
16
        mov r31,r25
17
        cp r20,__zero_reg__
18
        cpc r21,__zero_reg__
19
        breq .L1
20
        mov r26,r22
21
        mov r27,r23
22
        add r20,r24
23
        adc r21,r25
24
.L3:
25
        ld r24,X+
26
        st Z+,r24
27
        cp r30,r20
28
        cpc r31,r21
29
        brne .L3
30
.L1:
31
        ret
32
        .size   memorycopy, .-memorycopy
33
        .ident  "GCC: (GNU) 4.7.2"

: Bearbeitet durch Moderator
von Andreas P. (andip)


Lesenswert?

Jörg Wunsch schrieb:
>> Also für meine (in Assembler ungeübten) Augen ein komplett anderer und
>> vor Allem deutlich umfangreierer Code.
>
> Klar, wenn der Quellcode was anderes tut … Hast du dir mal die
> Warnungen angesehen?  Da sollte drin stehen:
> foo.c: In function ‘main’:
> foo.c:4:5: warning: statement with no effect [-Wunused-value]
>
> Dein „b * 2“ in der for-Schleife ist das, was er damit meint: das
> ist eine sinnlose Operation.
>
> Vermutlich meintest du entweder „b *= 2“ oder „b = b * 2“.

Kopf --> Tisch
Du hast ja so was von recht (obwohl du mit b das i meinst).
Sorry, mein Fehler! Wenns keine Probleme zwischen Tastatur und Stuhl 
gibt, kommt tatsächlich genau der gleiche Asm-Code raus ;-)
Übrigens auch wenn man es über do-while, for-break und while-break 
realisiert.

Danke für deine Hilfe und vy 73!

von (prx) A. K. (prx)


Lesenswert?

Andreas P. schrieb:
> (dass der möglicherweise auf dem Stand der 80er
> stehen geblieben ist, schließe ich ausdrücklich nicht aus).

Diesen Trick hatte man schon in der 80ern drauf. Weils eine der 
einfachsten Übungen ist. Komplexer wird es eher heute wieder, weil das 
Verhalten der Prozessoren und deren Sprünge viel komplexer geworden ist.

: Bearbeitet durch User
von Josef G. (bome) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Aus Sicht der Programmiersprache ist dein Konstrukt also absolut
> überflüssig, da er nichts anderes als die normale while-Schleife
> darstellt, die man halt verschieden in Maschinencode umsetzen kann.

Das Konstrukt wäre überflüssig, wenn die Sprache zusätzlich
while-Schleifen bietet. Es ist jedoch nicht überflüssig, wenn
es keine while-Schleifen gibt und diese durch eben dieses
Konstrukt ersetzt werden.

Und gegenüber while-Schleifen hat das Konstrukt den Vorteil,
dass man bereits im Quelltext unmittelbar den erzeugten Code
vor sich sieht und keine Optimierung erforderlich ist.

Ausserdem hat es den Vorteil, dass die Ermittlung der
Abbruchbedingung beliebig kompliziert sein kann. Es muss
lediglich die Zielmarke *HERE des Hineinsprungs entsprechend
weit genug vor dem bedingten Rückwärtssprung liegen.

Bei der while-Schleife müsste man in so einem Fall die
Ermittlung der Abbruchbedingung in eine function packen,
deren Rückgabewert dann abgefragt wird. Oder man muss
eine Endlosschleife mit bedingtem break verwenden,
was der Philosophie der while-Schleife zuwiderläuft.

von (prx) A. K. (prx)


Lesenswert?

Jörg Wunsch schrieb:
> Der Schleifentest befindet sich hier am Anfang der Schleife, beim
> Erreichen des Schleifenendes wird zu .L5 rausgesprungen, am Ende
> der Schleife wird zum Test nach .L2 zurückgesprungen.

Wobei das am -Os hängt. Bei -O1 gibts eine dritte Version:
  if (condition) do ... while (condition)
Also keine eingesprungene Schleife, sondern eine vermiedene Schleife.

        testl   %edx, %edx
        je      .L1
        movl    $0, %eax
.L3:
        movzbl  (%rsi,%rax), %ecx
        movb    %cl, (%rdi,%rax)
        addq    $1, %rax
        cmpl    %eax, %edx
        ja      .L3
.L1:

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Josef G. schrieb:

> Das Konstrukt wäre überflüssig, wenn die Sprache zusätzlich
> while-Schleifen bietet. Es ist jedoch nicht überflüssig, wenn
> es keine while-Schleifen gibt und diese durch eben dieses
> Konstrukt ersetzt werden.

OK.

> Und gegenüber while-Schleifen hat das Konstrukt den Vorteil,
> dass man bereits im Quelltext unmittelbar den erzeugten Code
> vor sich sieht und keine Optimierung erforderlich ist.

Das ist kein Vorteil, sondern deutet darauf hin, dass du eher eine
Art „Hochsprach-Assembler“ im Blick hast denn einen vernünftigen
Compiler.  Letzterer sollte immer sinnvoll optimieren können,
und siehe oben, ob nun der Schleifentest am Anfang oder am Ende
oder auf beiden Seiten erfolgt, kann von Fall zu Fall unterschiedlich
optimiert werden.

Aus Sicht des Programmierers wäre es mir wichtig, dass die
Programmiersprache sich einigermaßen so verhält wie die bereits
existierenden Sprachen (POLA - principle of least astonishment).

> Ausserdem hat es den Vorteil, dass die Ermittlung der
> Abbruchbedingung beliebig kompliziert sein kann.

Inwiefern sollte das bei existierenden while-Schleifen nicht der
Fall sein?

Aber lassen wir das: keiner außer dir versteht deine etwas verworren
anmutenden Gedankengänge, während Millionen von Programmierern es
bislang geschafft haben, mit klassischen while-Schleifen ohne
große Diskussionen ihr Ziel zu erreichen.

A. K. schrieb:
> Wobei das am -Os hängt. Bei -O1 gibts eine dritte Version:

Ja, das ist die, die er auch bie -O3 dann noch nimmt.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Josef G. schrieb:
> Und gegenüber while-Schleifen hat das Konstrukt den Vorteil,
> dass man bereits im Quelltext unmittelbar den erzeugten Code
> vor sich sieht und keine Optimierung erforderlich ist.

Du verkaufst also einen Mangel (Sprache bietet keine while-Schleife) als 
einen Vorteil? Das erinnert mich an Versicherungsvertreter.

Eine höhere Programmiersprache bietet eine Abstraktionsebene an. Genau 
das ist der Sinn einer höheren Programmiersprache. Dem Programmierer 
kann es im allgemeinen vollkommen wurscht sein, wie der Compiler das 
umsetzt. Hauptsache, er macht es korrekt und effizient.

Und jetzt lassen wir uns nochmal Deinen Satz auf der Zunge zergehen:

> Und gegenüber while-Schleifen hat das Konstrukt den Vorteil,
> dass man bereits im Quelltext unmittelbar den erzeugten Code
> vor sich sieht und keine Optimierung erforderlich ist.

Der einzige Programmierer, der "unmittelbar den erzeugten Code vor sich 
sieht", ist ein Assembler-Programmierer. Deine "Sprache" bietet also 
keine Abstraktionsebene an. Und das soll ein "Vorteil" sein?

Oder noch besser im Umkehrschluss:

Alle Sprachen, die dem Programmierer Dein "Konstrukt" nicht zur 
Verfügung stellen, stellen einen Rückschritt dar?

: Bearbeitet durch Moderator
von (prx) A. K. (prx)


Lesenswert?

Josefs Version der eingesprungenen Schleife:
   while condition
      statement2
   entry:
      statement1
   end while

Äquivalente Version in vielen Programmiersprachen:
   while true
      statement1
      if condition false
          exit while
      statement2
   end while

Wie der Compiler das in Code umsetzt ist sowieso seine Sache, d.h. aus 
dem Quellcode der zweiten Version kann ein an die erste Version 
erinnernder Maschinencode werden, oder es kann streckenweise conditional 
execution genutzt werden.

Die zweiten Version hat den Vorzug, dass nicht einen Block rein, sondern 
aus ihm raus gesprungen wird. Das ist an vielen Stellen angenehmer, 
beispielsweise bei Variablen lokal zum Block (*) und bei exception 
handling.

Optisch vermeidet man in der zweiten den Spaghetticode-Eindruck der 
ersten Version, deren Statements anfangs in umgekehrter Reihenfolge 
ausgeführt werden. Ein Compiler würde in der heute üblichen 
Datenflussanalyse die erste Version deshalb ohnehin intern umdrehen 
müssen.

*: Mit lokaler Variable, wird das dann so geschrieben:
   while condition
      statement2(i) // was ist i? Kenn ich nicht!
   entry:
      declare i as integer = 1
      i = 2
   end while
oder so:
   while condition
      declare i as integer = 1 // wird i hier initialisiert?
      statement2(i) // Aufruf ist mit i=2 oder i=1?
   entry: // wird i hier initialisiert?
      i = 2
   end while
oder wie?

Eingesprungene Blöcke sind Mist. Die C Syntax von switch statements ist 
es auch.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ A. K. (prx)

>Eingesprungene Blöcke sind Mist.

Na dann vielleicht eingesprungene Böcke?

http://upload.wikimedia.org/wikipedia/commons/b/b7/Saut_de_gazelle_Springbok.jpg


> Die C Syntax von switch statements ist es auch.

Warum? Das ist doch sonnenklar, oder?

von (prx) A. K. (prx)


Lesenswert?

Falk Brunner schrieb:
> Na dann vielleicht eingesprungene Böcke?

Die sind zwar kein Mist, aber machen Mist.

von Josef G. (bome) Benutzerseite


Lesenswert?

A. K. schrieb:
> beispielsweise bei Variablen lokal zum Block (*)
Gibt es in meiner Sprache nicht.
Gegf. müsste die Variablen-Vereinbarung nach *HERE erfolgen.

> Spaghetticode-Eindruck
Wenn die Schleife mit Hineinsprung auf dich wie Spaghetticode
wirkt, ist das rein subjektiv und nur eine Frage der Gewöhnung.
Tatsächlich hat es mit Spaghetticode nichts zu tun.

Josef G. schrieb:
>> Warum man die "strenge Blockstruktur" anschließend wieder mit so einer
>> komischen Konstruktion, wie dem "Hineinsprung" durchlöchern muss,
>
> Die wird nicht durchlöchert.
> L.JP .. HERE .. RP.x ist genauso ein Block mit zwei Unterblöcken,
> wie dies bei if .. else .. end-else der Fall ist.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Josef G. schrieb:
> Wenn die Schleife mit Hineinsprung auf dich wie Spaghetticode
> wirkt, ist das rein subjektiv und nur eine Frage der Gewöhnung.

Totschlagargument: kann man immer behaupten.  „Für mich sieht das
alles schön aus, muss also dein Problem sein.“

Wie ich schon schrieb: mach' deine Sprache, wenn du sie unbedingt so
brauchst.  Alles andere scheint dich ja nur dann zu interessieren,
wenn es irgendwie deiner Argumentation hilfreich ist, also als
externe Selbstbestätigung.

von Klaus W. (mfgkw)


Lesenswert?

Jörg Wunsch schrieb:
> Aus Sicht des Programmierers wäre es mir wichtig, dass die
> Programmiersprache sich einigermaßen so verhält wie die bereits
> existierenden Sprachen (POLA - principle of least astonishment).

naja, es gibt auch Programmierer, die wünschen sich POFUC (Principle Of 
FUrthest from C).

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Klaus Wachtler schrieb:
> POFUC

Die können doch BASCOM nehmen. :-)  Oder FORTRAN …

von Josef G. (bome) Benutzerseite


Lesenswert?

A. K. schrieb:
> Josefs Version der eingesprungenen Schleife:
>    while condition
>       statement2
>    entry:
>       statement1
>    end while

Abgesehenen davon, dass die Schlüsselworte bei mir anders sind:
Die Verwirrung entsteht durch die von dir gewählte Bezeichnung
statement2 statement1. Ich würde es so schreiben:

1
*L.JP
2
  statement1
3
*HERE
4
  statement2
5
RP.c

In der Schleife wird jeweils statement1 & statement2 ausgeführt,
zuletzt statement2. Nur beim ersten Durchlauf wird statement1
übersprungen.

Wenn man diese Vorstellung verinnerlicht hat, wirkt alles
ganz natürlich. Wie schon geschrieben: reine Gewöhnungssache.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Josef G. schrieb:
> Wenn man diese Vorstellung verinnerlicht hat, wirkt alles
> ganz natürlich.

Gewiss.

von Josef G. (bome) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
>> Ausserdem hat es den Vorteil, dass die Ermittlung der
>> Abbruchbedingung beliebig kompliziert sein kann.
>
> Inwiefern sollte das bei existierenden while-Schleifen
> nicht der Fall sein?

Es ist jedenfalls nicht so einfach wie
bei der Schleife mit Hineinsprung.

von (prx) A. K. (prx)


Lesenswert?

Josef G. schrieb:
> Es ist jedenfalls nicht so einfach wie
> bei der Schleife mit Hineinsprung.

Kann ich nicht nachvollziehen. Ich kann zwischen den beiden oben 
gezeigten Varianten keinen Unterschied erkennen, was die Komplexität der 
Abbruchbedingung angeht.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Josef G. schrieb:
> Wenn man diese Vorstellung verinnerlicht hat, wirkt alles
> ganz natürlich. Wie schon geschrieben: reine Gewöhnungssache.

Ich fand es auch mal völlig natürlich, das bei -1+2 am Ende -3 
rauskommt, und 1/3 zu 3 wird. Ersteres finde ich auch heute noch 
logischer und konsequenter als den ganzen Zirkus mit der operator 
precedence.

: Bearbeitet durch User
von Josef G. (bome) Benutzerseite


Lesenswert?

A. K. schrieb:
> Kann ich nicht nachvollziehen.

Josef G. schrieb:
> Ausserdem hat es den Vorteil, dass die Ermittlung der
> Abbruchbedingung beliebig kompliziert sein kann. Es muss
> lediglich die Zielmarke *HERE des Hineinsprungs entsprechend
> weit genug vor dem bedingten Rückwärtssprung liegen.
>
> Bei der while-Schleife müsste man in so einem Fall die
> Ermittlung der Abbruchbedingung in eine function packen,
> deren Rückgabewert dann abgefragt wird. Oder man muss
> eine Endlosschleife mit bedingtem break verwenden,
> was der Philosophie der while-Schleife zuwiderläuft.

von (prx) A. K. (prx)


Lesenswert?

Ich bezog mich die zu deiner Methode äquivalente Version in 
Beitrag "Re: Gibt es eine Programmiersprache mit diesem Schleifentyp?".

von Josef G. (bome) Benutzerseite


Lesenswert?

A. K. schrieb:
> Ich bezog mich die zu deiner Methode äquivalente Version in
> Beitrag "Re: Gibt es eine Programmiersprache mit diesem Schleifentyp?".

A. K. schrieb:
> Äquivalente Version in vielen Programmiersprachen:
>    while true
>       statement1
>       if condition false
>           exit while
>       statement2
>    end while

Ich vermute, gemeint war das:
>    while true
>       statement1
>       if condition=false exit
>       statement2
>    end while
also eine Endlosschleife mit bedingtem break.

Da gilt meine Aussage
> eine Endlosschleife mit bedingtem break verwenden,
> was der Philosophie der while-Schleife zuwiderläuft.

Ist sicher kein starkes Argument, aber immerhin, es ist ein Argument.

Bei einfacher Abbruchbedingung schreibt man

while(??){...}

Wenn die Ermittlung der Abbruchbedingung
eine lange Befehlsfolge beinhaltet, schreibt man

while(1){Befehlsfolge; if(??) break; ...}

Man hat also zwei verschiedene Strukturen,
je nach Komplexität der Abbruchbedingung.

Bei der Schleife mit Hineinsprung hat man beide Male dieselbe
Struktur, nur die Marke *HERE steht unterschiedlich weit
vom bedingen Rückwärtssprung entfernt.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Josef G. schrieb:
> Wenn die Ermittlung der Abbruchbedingung
> eine lange Befehlsfolge beinhaltet, schreibt man
>
> while(1){Befehlsfolge; if(??) break; ...}

Warum denn das?

Alles, was du im "if" schreiben kannst, kannst du auch im "while"
als Bedingung schreiben.

Klar kann es aus Gründen der Übersichtlichkeit Sinn haben, dass man
für die Bedingung eine (inline-)Funktion schreibt, aber ansonsten
kann man gerade in C beliebig komplexe Ausdrücke als Steuerung von
"if" oder "while" konstruieren.

Du legst dir tausendundein Argument zurecht für einen Konstrukt, den
nur du haben willst, und den du nun unbedingt allen anderen als
Vorteil deines aufgebohrten Assemblers verkaufen willst.

Aufgebohrte Assembler gab es auch schon vor 40 Jahren, PL/M zum
Bleistift.  Sie haben sich nicht wirklich durchgesetzt.

von Josef G. (bome) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
>> Und gegenüber while-Schleifen hat das Konstrukt den Vorteil,
>> dass man bereits im Quelltext unmittelbar den erzeugten Code
>> vor sich sieht und keine Optimierung erforderlich ist.
>
> Das ist kein Vorteil, sondern deutet darauf hin, dass du eher eine

Es hat sogar einen praktischen Vorteil: Ein Programmierer,
der sich das Compilat anschauen will um es zu überprüfen,
findet sich schneller zurecht.

von Josef G. (bome) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Alles, was du im "if" schreiben kannst, kannst du auch im "while"
> als Bedingung schreiben.

So etwas? while(Befehlsfolge; ??){...}

Wusste ich nicht, dass das geht.

von Falk B. (falk)


Lesenswert?

@ Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite

>Wie ich schon schrieb: mach' deine Sprache, wenn du sie unbedingt so
>brauchst.  Alles andere scheint dich ja nur dann zu interessieren,
>wenn es irgendwie deiner Argumentation hilfreich ist, also als
>externe Selbstbestätigung.

Genau. Darum sind wir HIER und JETZT Zeuge der Geburt einer neuen 
Sprache.

https://www.youtube.com/watch?v=XrzRH2I5Mpo

E (wie Ego), created by Josef G.

(Über G. dürfen hier und jetzt pupertäre Witzchen gemacht werden ;-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Josef G. schrieb:
> Wusste ich nicht, dass das geht.

Du kennst C nicht, insbesondere den Komma-Operator.

Jetzt verrätst du mir aber, warum man so einen Kram unbedingt
vor der ersten Iteration der Schleife ernsthaft braucht.  In allen
anderen Fällen kann man ja deine „Befehlsfolge“ problemlos ans Ende
der Schleife schreiben, ohne dass sie beim ersten Mal mit abgearbeitet
werden muss.

Josef G. schrieb:
> Es hat sogar einen praktischen Vorteil: Ein Programmierer,
> der sich das Compilat anschauen will um es zu überprüfen,
> findet sich schneller zurecht.

Nur, weil dein Compiler zu blöd ist zum optimieren.

Bei einem optimierenden Compiler erkennt man völlig unabhängig von
solchen Schleifenkonstrukten im Maschinencode niemals mehr 1:1 den
Quellcode.

Aus dem Alter, in dem man das Compilat „überprüfen“ muss, sind wir
sowieso schon lange raus.

: Bearbeitet durch Moderator
von Falk B. (falk)


Lesenswert?

Ist das Compilat gar desolat, weiß meistens nur der Josef Rat.

;-)

von Josef G. (bome) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Josef G. schrieb:
>> Wenn die Ermittlung der Abbruchbedingung
>> eine lange Befehlsfolge beinhaltet, schreibt man
>>
>> while(1){Befehlsfolge; if(??) break; ...}
>
> Warum denn das?
> ... kannst du auch im "while" als Bedingung schreiben.

Jörg Wunsch schrieb:
> Du kennst C nicht, insbesondere den Komma-Operator.

Wenn aber "Befehlsfolge" keine einfache Folge ist,
sondern selber Verzweigungen/Schleifen beinhaltet?

Sogar wenn es ginge, das in den runden Klammern der Struktur
1
while(..., ..., ??){...}
unterzubringen, würde man das sicher nicht so machen, sondern
1
while(1){"Befehlsfolge"; if(??) break; ...}
verwenden. Und dann gilt mein Argument wieder:

Josef G. schrieb:
> Bei einfacher Abbruchbedingung schreibt man
> while(??){...}
>
> Wenn die Ermittlung der Abbruchbedingung
> eine lange Befehlsfolge beinhaltet, schreibt man
> while(1){Befehlsfolge; if(??) break; ...}
>
> Man hat also zwei verschiedene Strukturen,
> je nach Komplexität der Abbruchbedingung.
>
> Bei der Schleife mit Hineinsprung hat man beide Male dieselbe
> Struktur, nur die Marke *HERE steht unterschiedlich weit
> vom bedingen Rückwärtssprung entfernt.

von Josef G. (bome) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Nur, weil dein Compiler zu blöd ist zum optimieren.

Dafür läuft er aber auch auf einem 8bit-Rechner
und benötigt nicht die Ressourcen eines PC.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Josef G. schrieb:
> Dafür läuft er aber auch auf einem 8bit-Rechner
> und benötigt nicht die Ressourcen eines PC.

Das ist sicherlich reizvoll. Gewesen. Vor dreißig Jahren. Auch wenn das 
Programmieren von 8-Bit-Systemen nach wie vor sinn- und reizvoll ist, 
das auf 8-Bit-Systemen zu tun ist Masochismus. Brauchbare 
Texteditoren, brauchbare Ein- und Ausgabesysteme, Dateisysteme, die auch 
Dateinamen verarbeiten können (statt auf wenige Zeichen Länge 
beschränkte Kürzel) ... all das sind Gründe, die Programmiererei auf 
einem etwas zeitgenössischeren System zu veranstalten.

Ich habe auch noch meinen ersten selbst zusammengelöteten 8-Bit-Rechner 
herumstehen, der wird demnächst mal abgestaubt und zum 30. seiner 
Inbetriebnahme auch mal wieder eingeschaltet, eine Zeitlang bewundert 
und dann wieder ausgeschaltet. Obwohl der unter anderem einen 
Pascal-Compiler im ROM hat, und so ziemlich den schicksten aller 
8-Bit-Prozessoren verwendet (6809).

von Karl H. (kbuchegg)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Josef G. schrieb:
>> Dafür läuft er aber auch auf einem 8bit-Rechner
>> und benötigt nicht die Ressourcen eines PC.
>
> Das ist sicherlich reizvoll. Gewesen. Vor dreißig Jahren.

Abgesehen davon.
Auch vor 30 Jahren gab es schon C-Compiler die problemlos und sauber auf 
den damaligen 8 Bit Rechnern liefen.

Nur weil heutige IDE Megabyteweise Dinge mitbringen, bedeutet das ja 
nicht, dass das immer so sein muss. Ein C Compiler ist kein besonders 
umfangreiches Programm. Der gcc hat es natürlich schwerer, weil er so 
gebaut ist, dass er von den kleinsten bis zu den größten Maschinen mit 
unterschiedlichen Architekturen klar kommen muss. D.h. alles muss sehr 
allgemein gehalten sein.

> Sogar wenn es ginge, das in den runden Klammern der Struktur
>
> while(..., ..., ??){...}
> unterzubringen, würde man das sicher nicht so machen, sondern
>
> while(1){"Befehlsfolge"; if(??) break; ...}
> verwenden. Und dann gilt mein Argument wieder:

Klar. Man kann natürlich immer damit argumentieren, dass die gröbsten 
Schweinereien in einer Sprache nicht so einfach möglich sind. Die 
Erfahrung zeigt aber, dass irgendwer immer einen Weg findet :-)

Um das klar zu sagen: Wenn du das willst, dann hast du die ganze 
Entwicklung der strukturierten Programmierung und was man aus den 
letzten 80 Jahren Programmierung gelernt hat, ganz einfach verschlafen. 
Der Trend ging nicht grundlos in die Richtung, dass man derartige 
Schweinereien gezielt abstellen will.
Die Praxis zeigt nämlich auch, dass genau diese Schweinereien es nicht 
sind, mit denen man aus einem Programm Speed herausholt. Ausser 
natürlich in sinnlosen Demos. Aber in realen Programmen sind diese Dinge 
nicht der Bottleneck.

Ich finde die Schleife mit Hineinsprung durchaus interessant. Aber es 
ist jetzt nichts, was ich mir unbedingt zu Weihnachten wünschen würde.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Karl Heinz schrieb:
> Auch vor 30 Jahren gab es schon C-Compiler die problemlos und sauber auf
> den damaligen 8 Bit Rechnern liefen.

Und vor 30 Jahren gab es auch längst 32-Bit 68000 Systeme, die sich weit 
besser als Host für Compiler eigneten.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karl Heinz schrieb:
> Auch vor 30 Jahren gab es schon C-Compiler die problemlos und sauber auf
> den damaligen 8 Bit Rechnern liefen.

Insbesondere gab es schon Turbo-Pascal, welches gar nicht mal so
schlecht optimiert hat und auch keine derartig verrenkten syntaktischen
Konstrukte benötigte, wie Josef sie hier anzetteln will.

Josef G. schrieb:
> Und dann gilt mein Argument wieder:

… für das du bislang immer noch den Anwendungsfall schuldig geblieben
bist.  Du theoretisierst da um irgendwas herum.  Wo zum Geier braucht
man derartig kompliziert gestaltete Abbruchbedingungen, die man dann
auch noch unbedingt vor dem ersten Abarbeiten der Schleife
durchlaufen muss?  Alles andere in deinen komplizierten Abläufen kann
man ja immer noch ganz normal ans Ende der Schleife setzen:
1
  while (!abbruchbedingung) {
2
    tuwas();
3
    komplizierte_vorbereitung_der_abbruchbedingung;
4
  }

Ich würde mal sagen, in den allermeisten Fällen müsste man selbst
bei derzeitigen C-Programmen die Abbruchbedingung noch nichtmal
vor dem ersten Schleifendurchlauf testen, weil von der Umgebung her
klar ist, dass beim Eintritt in die Schleife auf jeden Fall was zu
tun ist.  Es würde dann eine do{}while-Schleife genügen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Insbesondere gab es schon Turbo-Pascal

Und das lief in den ersten Inkarnationen sogar auf 8-Bit-Systemen 
(CP/M).

von (prx) A. K. (prx)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Und das lief in den ersten Inkarnationen sogar auf 8-Bit-Systemen

Und zwar verdammt gut, trotz wenig RAM. Klar, grossartig optimiert hat 
der Compiler nicht, aber gegenüber den vorher üblichen Compilern, wie 
UCSD-Pascal mit interpretierem Bytecode, oder den dicken FORTRAN und 
PL/I Dingern war die Zeit zwischen Quellcodeänderung und Ausführung 
angenehm kurz.

Nur: Muss man das heute auch noch so machen? Schon in der Anfangszeit 
fand professionelle Entwicklung für 8-Bit Systeme unterhalb der CP/M 
Klasse auf Minicomputern statt, bevor die PCs deren Rolle übernahmen.

von Falk B. (falk)


Lesenswert?

@ A. K. (prx)

>Nur: Muss man das heute auch noch so machen? Schon in der Anfangszeit
>fand professionelle Entwicklung für 8-Bit Systeme unterhalb der CP/M
>Klasse auf Minicomputern statt, bevor die PCs deren Rolle übernahmen.

Hat nicht auch Bill Gates so angefangen? Auf dem Rechner der Uni für die 
"Homecomputer" was programmiert. Da gab dann Ärger.

von Falk B. (falk)


Lesenswert?

@Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite

>> Und dann gilt mein Argument wieder:

>… für das du bislang immer noch den Anwendungsfall schuldig geblieben
>bist.  Du theoretisierst da um irgendwas herum.

Jörg, die "kennst" den Josef doch schon seit Jahren. Immer noch nicht 
verstanden, wie es um ihn steht?

Beitrag "Re: wer kann sich noch an den hex-zeichensatz erinnern?"

von Josef G. (bome) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> für das du bislang immer noch den Anwendungsfall schuldig geblieben

Eine Zahl SELECT soll eingelesen werden, wozu mehrere Aktionen nötig
sind (Linefeed, Ausgabe von Benutzer-Info und Eingabe-Maske, ...).
Hat die Zahl einen Wert 0..3, dann soll dadurch eine von vier Aktionen
ausgewählt werden, welche dann auszuführen sind, und es soll eine neue
Zahl SELECT eingelesen werden und so fort. Falls aber SELECT den Wert
4 oder größer hat, soll abgebrochen werden.

Man hat eine Schleife mit Hineinsprung: Nach dem *HERE stehen die
Eingabe der Zahl SELECT und die unterstützenden Aktionen, dann
der Rückwärtssprung falls SELECT nicht größer als 3. Vor dem
*HERE stehen in einer CASE-Struktur die vier Aktionen,
welche durch SELECT ausgewählt werden.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Josef G. schrieb:
> Man hat eine Schleife mit Hineinsprung

Nein. Hat man nicht. Die Schleife kann auch bei Deiner Anforderung ganz 
vorne, also an ihrem Anfang begonnen werden.

In c-artigem Pseudocode
1
do
2
{
3
  Select = Hole_Aktion();
4
5
  switch (Select)
6
  {
7
    case 0 :
8
      machdies();
9
      break;
10
11
    case 1 :
12
      machjenes();
13
      break;
14
15
    case 2 :
16
      machwasanderes();
17
      break;
18
19
    case 3 :
20
      verbraucherechenzeit(); 
21
      break;
22
  }
23
}
24
while (Select < 4);

von (prx) A. K. (prx)


Lesenswert?

Hast du was gegen Funktionen?
1
do zahl = input(); while (action(zahl));
2
3
int action(int zahl)
4
{
5
  switch (zahl) {
6
  case 0: ...
7
  case 1: ...
8
  case 2: ...
9
  case 3: ...
10
  default: return 0;
11
  }
12
  return 1;
13
}

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

A. K. schrieb:
> Hast du was gegen Funktionen?

Soweit ist Josef bzw. seine Programmiersprache noch nicht. Aber frag mal 
in 30 Jahren nach.

von (prx) A. K. (prx)


Lesenswert?

Kennen tut er Funktionen jedenfalls, zumindest in C. Ich weiss bloss 
nicht, was er dagegen hat. Und was ihn insbesondere an Return-Werten 
stört:
Beitrag "Re: Gibt es eine Programmiersprache mit diesem Schleifentyp?"

Und so geht natürlich auch:
1
   while ((zahl = input()) < 4) {
2
      ..
3
   }
was genau dem C-Klassiker der ersten Stunde entspricht:
1
   while ((c = getchar()) != EOF) {
2
      ..
3
   }
OK. Eine Zuweisung mitten in der Bedingung, das gibts wirklich nicht 
in jeder Sprache.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

A. K. schrieb:
> Hast du was gegen Funktionen?

Dass ja seine tolle Erfindung dann doch bloß wieder flüssiger als
Wasser ist. ;-)

von (prx) A. K. (prx)


Lesenswert?

Jörg Wunsch schrieb:
> Dass ja seine tolle Erfindung dann doch bloß wieder flüssiger als
> Wasser ist. ;-)

Nu, das wär doch wirklich was.
Suprafluidität - eine völlig reibungslos funktionierende IT.

von Josef G. (bome) Benutzerseite


Lesenswert?

Josef G. schrieb:
> Es gibt in der Tat eine Eins-zu-Eins-Entsprechung zwischen
> dem Quelltext und dem erzeugten Code. Und dies ermöglicht
> es, durch Addieren von Ausführungszeiten die Dauer von
> Programmteilen zu berechnen. Ob es dafür einmal eine
> ernsthafte Anwendung geben wird, wird man sehen.

Robert L. schrieb:
> warum es wichtig sein sollte, dass man (anhand vom Code) abzählen kann,
> wieviele takte ein bestimmtes programm jetzt genau braucht, kapier ich
> übrigens nicht..

Offenbar gibt es doch Leute, die für so etwas eine Anwendung haben.
Beitrag "Funktion mit gleichbleibender Ausführungszeit"

von Robert L. (lrlr)


Lesenswert?

>die für so etwas eine Anwendung haben.
nein, die GLAUBEN für so etwas eine Anwendung zu haben!

dort wurde (wie so oft) gefragt, wie man eine vermeintliche Lösung für 
ein Problem umsetzten kann

das PROBLEM ansich aber nicht dargelegt: ob es diese "Lösung" also 
überhaupt braucht, oder die beste ist weiß keiner..

von Helmut S. (hels)


Lesenswert?

Geht auch in "C", sogar ohne explizites "goto":

switch (einsprung) while (bedingung) {

    case EINSPRUNG_1:

    case EINSPRUNG_2:

    case EINSPRUNG_3:

    // Tu' irgendwas mit "bedingung"
}

Sage niemandem dass Du das von mir hast!
Fuer soetwas wird man in jedem Review bei lebendigem Leibe verbrannt ;)


Josef G. schrieb:
> In einer von mir kreierten Programmiersprache gibt es die
> "Schleife mit Hineinsprung" anstelle der while-Schleife.
>
> Kennt jemand sonst eine Sprache mit dieser Struktur?
>
> Beitrag "Re: 8bit-Computing mit FPGA"

von Klaus W. (mfgkw)


Lesenswert?

Helmut S. schrieb:
> Sage niemandem dass Du das von mir hast!
> Fuer soetwas wird man in jedem Review bei lebendigem Leibe verbrannt ;)

Ich sage auch niemandem, daß du es von Duff's Device abgeschaut hast :-)
https://en.wikipedia.org/wiki/Duff%27s_device

von Josef G. (bome) Benutzerseite


Lesenswert?

Klaus W. schrieb:
> https://en.wikipedia.org/wiki/Duff%27s_device


Habe jetzt den Wikipedia-Artikel doch noch einigermaßen verstanden.
Es geht darum, bei Zähl-Schleifen die Zahl der Durchläufe und damit
die Zahl der bedingten Rückwärtssprünge, welche Zeit kosten, auf
einen Bruchteil zu reduzieren, indem man den Schleifenkern mehrere
Male (zB. achtmal) untereinander schreibt und den Startwert des zu
dekrementierenden Zählers durch einen Bruchteil (zB. ein Achtel)
des ursprünglichen Wertes ersetzt. Falls der ursprüngliche Wert
nicht durch acht teilbar ist, springt man zu Beginn in die
Schleife zu einer der Kopien des Schleifenkerns.


Zwar nicht auf Hochsprachen-Ebene aber bei Assembler-Programmierung
wird dieses Problem bei meiner CPU auf andere Weise gelöst. Hier
als Beispiel ein Code zur Blockverschiebung (S = Schleifenzähler):
1
S.RP     Setze Schleifenstartadresse auf den GTMX-Befehl
2
GTMX     Lade (X) in den Akku
3
STMY     Speichere Akku in (Y)
4
IX0      Inkrementiere X
5
R.IY     Falls S nicht Null ist:
6
         Dekrementiere S, Inkrementiere Y, Sprung zum Start

Der kombinierte Befehl R.IY dauert nicht länger als ein einfaches
Inkrementieren IY0. Damit entfällt der Anreiz, Schleifendurchläufe
zusammenzufassen durch mehrmaliges Hinschreiben des Schleifenkerns.


Zu diesem und anderen Aspekten der CPU siehe auch
Beitrag "Re: 8bit-Computing mit FPGA"

von Josef G. (bome) Benutzerseite


Lesenswert?

Mit "mehrmaligem Hinschreiben" war diese Lösung gemeint:
1
S.RP
2
GTMX
3
STMY
4
IX0
5
IY0
6
GTMX
7
STMY
8
IX0
9
R.IY

: Bearbeitet durch User
von Lukas T. (tapy)


Lesenswert?

Ohne jetzt den wie üblich wirren Thread durchgelesen zu haben, habe ich 
den Eindruck, dass hier "Repeat [Anweisungen] Until [Bedingung]" 
wiederentdeckt wurde. Bekannt aus bspw. PASCAL.

von Josef G. (bome) Benutzerseite


Lesenswert?

Lukas T. schrieb:
> Ohne jetzt den wie üblich wirren Thread durchgelesen zu haben, habe
> ich den Eindruck, dass hier "Repeat [Anweisungen] Until [Bedingung]"
> wiederentdeckt wurde. Bekannt aus bspw. PASCAL.

Der Eindruck ist falsch.

In dem Thread geht es um die "Schleife mit Hineinsprung",
welche while-Schleifen ersetzt und darüber hinaus mehr kann.

In meinen letzten zwei Beiträgen geht es um etwas anderes:

Bei Zählschleifen, welche bestehen aus dem Schleifenkern und dem
Zählvorgang mit bedingtem Rückwärtssprung, verlängert sich die Dauer
einer Ausführung des Schleifenkerns um die Dauer des Zählvorgangs mit
Rückwärtssprung. Wenn man den Schleifenkern zweimal hinschreibt und
die Zahl der Schleifendurchläufe halbiert, ist pro Ausführung des
Schleifenkerns nur noch die halbe Dauer eines Zählvorgangs mit
Rückwärtssprung anzurechnen, es geht also schneller. Dadurch ergibt
sich für den Programmierer ein Konflikt zwischen Geschwindigkeit
einerseits und Codelänge/Einfachheit andererseits.

Sofern im Schleifenkern ein Adressregister inkrementiert oder
dekrementiert wird, wird bei meiner CPU dieser Konflikt vermieden
durch kombinierte Befehle, welche ein Adressregister inkrementieren
oder dekrementieren und gleichzeitig den Zählvorgang mit bedingtem
Rückwärtssprung ausführen, und welche nicht länger dauern als das
Inkrementieren/Dekrementieren des Adressregisters allein.

von Robert L. (lrlr)


Lesenswert?

>Dadurch ergibt
>sich für den Programmierer ein Konflikt zwischen Geschwindigkeit
>einerseits und Codelänge/Einfachheit andererseits.

eigentlich nicht: es ist ein "Problem" des Compilers...
für den Programmier ist der Code ja der selbe, egal ob der Compiler 
jetzt auf geschwindigkeit oder größe optimiert..
(es steht auch in dem WIKI artikel zu  Duff's Device, dass das aufgrund 
von modernen comilern nicht mehr/kaum notwendig ist..)


ausserdem sind heutige CPU so extrem schnell, dass es in 99,999% der 
Fälle nicht notwendig ist sich über sowas überhaupt gedaken machen zu 
müssen
und in den restlichen 0.0001% wird man zuerstmal eine schnellere CPU 
(und vorallem keine 8bit CPU) verwenden.. und DANN erste anfangen mühsam 
code zu optimieren... (siehe stm32 für ein paar $..)


>und welche nicht länger dauern als das
>Inkrementieren/Dekrementieren des Adressregisters allein.

liegt aber vielleicht daran dass dein "inkremtenieren alleine" zu 
langsam  ist, und nicht dass das kombinierte so schnell ist ;-)

ausserdem: wenn du dir anschaust, welche optimierungen "aktuelle" CPU 
(seit Jahrezehnten) gerade bei bedingten sprüngen machen, ist nicht mal 
sicher, ob mehrmaliges hinschreiben, schneller ist als normale 
schleife...

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Robert L. schrieb:
> ausserdem: wenn du dir anschaust, welche optimierungen "aktuelle" CPU
> (seit Jahrezehnten) gerade bei bedingten sprüngen machen, ist nicht mal
> sicher, ob mehrmaliges hinschreiben, schneller ist als normale
> schleife...

Wer sich dafür interessiert, was in CPUs heute abgeht, der kann man hier 
reinschnuppern: http://www.realworldtech.com/sandy-bridge/

Leider versteckt David Kanter seine sehr guten Analysen mittlerweile im 
unbezahlbaren Microprocessor Report.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

In Matlab hätte ich jahrelang diesen Schleifentyp gern gehabt. Ich hatte 
ein "kleines" Dynamik-FEM-Programm, das ungefähr so aussah:
1
   Preprocessing
2
   Initialization
3
   Step-Postprocess
4
5
   for( ... )
6
       Step-Calculation
7
       Step-Postprocess
8
   end for

Das Problem war, daß Matlab nur call by value beherrscht, und da die 
Übergabe von Matrices > 1GB (sparse) viel zu langsam gewesen wäre, 
mußten die einzelnen Schritte in der Hauptschleife ausgeschrieben 
werden, d.h. die beiden Blocks "Step-Prostprocess" waren 1:1-Textkopien 
des Quelltextes. Sehr lästig.

Da hätte man den Einsprung in eine Schleife gut gebrauchen können. Das 
ist aber eher das gegenteilige Extrem, was Programmgröße und 
Programmiersprache (Hochsprache) angeht.

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Robert L. schrieb:
> wenn du dir anschaust, welche optimierungen "aktuelle" CPU
> (seit Jahrezehnten) gerade bei bedingten sprüngen machen

Zudem werden auch die Compiler immer schlauer und nutzen diese Features
der aktuellen Prozessoren meist besser als man dies durch explizite
Programmierung (sei es in Assembler oder durch neue Sprachkonstrukte wie
der "Josef-G.-Schleife") kann.

Schon vor ca. 20 Jahren war der C-Compiler für den TMS320C30 (DSP von
TI) in der Lage, eine Schleife komplett umzustellen, um damit Features
des Prozessors wie bspw. die Multiply/Accumulate (parallele Addition/
Multiplikation) und Single-Instruction-Repeat (Wiederholung einer
Einzeinstruktion ohne Schleifen-Overhead) nutzen zu können.

Beispiel Skalarprodukt:

So schreibt man den Code üblicherweise hin:

1
double dot(double x[], double y[], int n) {
2
  double sum;
3
  int i;
4
5
  sum = 0.0;
6
  for(i=0; i<n; i++)
7
    sum += x[i] * y[i];
8
9
  return sum;
10
}

Er ist zwar leicht schreib- und lesbar, hat aber den Nachteil, dass die
Addition in der Schleife vom Ergebnis der Multiplikation abhängt,
weswegen diese beiden Operationen nicht parallel ausgeführt werden
können.

Der Compiler erzeugt daraus Code, der äquivalent zu diesem ist:

1
double dotopt(double x[], double y[], int n) {
2
  double sum, prod;
3
  int i;
4
5
  sum = 0.0;
6
  prod = x[0] * y[0];
7
  for(i=1; i<n; i++) {
8
    sum += prod;
9
    prod = x[i] * y[i];
10
  }
11
  sum += prod;
12
13
  return sum;
14
}

Durch die Umstellung der Operationen innerhalb der Schleife können sie
jetzt parallel ausgeführt werden. Die erste Multiplikation und die
letzte Addition der gesamten Berechnung werden außerhalb der Schleife
ausgeführt, weswegen die Schleife statt n nur n-1 Durchläufe hat.

Das alles bastelt der Compiler ohne Zutun des Programmierers so hin mit
dem Ergebnis, dass die Berechnung statt 5n+1 nur n+2 Maschinenzyklen
dauert. Das ist eine Geschwindigkeitssteigerung um den Faktor 5, ohne
dass dafür neuartige Schleifenkonstrukte vonnöten wären.

Und die Compiler sind seither nicht schlechter, sonden noch viel besser
geworden

Josef G. schrieb:
> Wenn man den Schleifenkern zweimal hinschreibt und die Zahl der
> Schleifendurchläufe halbiert, ist pro Ausführung des Schleifenkerns
> nur noch die halbe Dauer eines Zählvorgangs mit Rückwärtssprung
> anzurechnen, es geht also schneller.

Loop-Unrolling wäre im obigen Beispiel sogar kontraproduktiv, da dadurch
ein Schleifen-Overhead entstünde, der vorher nicht vorhanden war. Und
auf Prozessoren, wo es tatsächlich einen Nutzen bringt, überlässt man es
sinnvollerweise meist ebenfalls dem Compiler, so dass man damit nicht
den Quellcode verunstalten muss.



Walter T. schrieb:
>    Preprocessing
>    Initialization
>    Step-Postprocess
>
>    for( ... )
>        Step-Calculation
>        Step-Postprocess
>    end for
>
> Das Problem war, daß Matlab nur call by value beherrscht, und da die
> Übergabe von Matrices > 1GB (sparse) viel zu langsam gewesen wäre,
> mußten die einzelnen Schritte in der Hauptschleife ausgeschrieben
> werden, d.h. die beiden Blocks "Step-Prostprocess" waren 1:1-Textkopien
> des Quelltextes. Sehr lästig.

Matlab hat doch eine Break-Anweisung.Warum also nicht so:
1
    Preprocessing
2
    Initialization
3
 
4
    forever
5
        Step-Postprocess
6
        if <exit condition> then
7
            break
8
        end if
9
        Step-Calculation
10
    end for

von Uhu U. (uhu)


Lesenswert?

A. K. schrieb:
> Leider versteckt David Kanter seine sehr guten Analysen mittlerweile im
> unbezahlbaren Microprocessor Report.

Der wird doch nicht etwa hier bei Joseph abschreiben?

von Walter T. (nicolas)


Lesenswert?

Yalu X. schrieb:
> Matlab hat doch eine Break-Anweisung.Warum also nicht so:

Die klassische Antwort: "Ja, aber." Matlab war damals (ich mache diesen 
Kram leider nicht mehr) extrem viel schneller, wenn es vorher die Anzahl 
der Schleifendurchläufe kannte. Sprich: Eine einfache for-Schleife mit 
konstantem Initialsierungsvektor war deutlich schneller als eine 
while-Schleife oder wenn in der Schleife "break" oder 
"continue"-Anweisungen vorhanden waren.

Einen Tod muß man halt immer sterben.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Walter T. schrieb:
> Yalu X. schrieb:
>> Matlab hat doch eine Break-Anweisung.Warum also nicht so:
>
> Die klassische Antwort: "Ja, aber." Matlab war damals (ich mache diesen
> Kram leider nicht mehr) extrem viel schneller, wenn es vorher die Anzahl
> der Schleifendurchläufe kannte.

Macht sich der Schleifen-Overhead auch dann noch bemerkbar, wenn
innerhalb der Schleife

Walter T. schrieb:
> Matrices > 1GB

verarbeitet werden? So lahm wird doch selbst der Matlab-Intepreter nkaum
sein, oder?

von Walter T. (nicolas)


Lesenswert?

Yalu X. schrieb:
> Macht sich der Schleifen-Overhead auch dann noch bemerkbar, wenn
> innerhalb der Schleife
>
> Walter T. schrieb:
>> Matrices > 1GB
>
> verarbeitet werden? So lahm wird doch selbst der Matlab-Intepreter nkaum
> sein, oder?

So lahm ist der Interpreter gar nicht. Im Vergleich zu 
Fortran-Programmen von mittelmäßig darin begabten Ingenieuren (da 
schließe ich mich ein) ist er sogar ziemlich fix. Ich nehme an, daß er 
einfach deutlich besser parallelisieren kann, wenn er schon vorher die 
Anzahl der Schleifenläufe kennt.

: Bearbeitet durch User
von Gu. F. (mitleser)


Lesenswert?

Oh mein Gott.
Und ich dachte wir hätten den Schmarrn endlich überstanden.

von Josef G. (bome) Benutzerseite


Lesenswert?

Robert L. schrieb:
>>und welche nicht länger dauern als das
>>Inkrementieren/Dekrementieren des Adressregisters allein.
>
> liegt aber vielleicht daran dass dein "inkremtenieren alleine" zu
> langsam  ist, und nicht dass das kombinierte so schnell ist ;-)

Bei meiner CPU dauern alle Operationen 1 oder 2 oder 3 "Vollzyklen",
wobei ein Vollzyklus aus den Halbzyklen tA und tB besteht.

Das Inkrementieren/Dekrementieren eines Adressregisters
dauert 1 Vollzyklus, ebenso die kombinierten Befehle.

Beim Inkrementieren eines Adressregisters wird bei tA das
Adressregister in ein Hilfsregister übertragen, an dessen
Ausgang ein Inkrementiernetz hängt. Bei tB wird der Ausgang
des Inkrementiernetzes in das Adressregister geschrieben.

Gleichzeitig wird bei tA der Programmzähler P auf dem Adressbus
ausgegeben und der nächste OpCode in ein Eingangs-Pufferregister
geladen. Bei tB wird er dann in das für das folgende tA zuständige
OpCode-Register übertragen. Ebenfalls gleichzeitig wird bei tA
der Programmzähler P in ein Hilfsregister übertragen, an dessen
Ausgang ein Inkrementiernetz hängt, bei tB wird das Ergebnis
in den Programmzähler geschrieben.

Bei den kombinierten Befehlen wird, sofern der Schleifenzähler
nicht Null ist, bei tA statt P die Schleifenstartadresse R auf dem
Adressbus ausgegeben zum Einlesen des nächsten OpCodes, und in das
Hilfsregister, an dessen Ausgang das Inkrementiernetz hängt, wird
ebenfalls R statt P übertragen. Das Ergebnis kommt wieder nach P.

Bei den kombinierten Befehlen wird gleichzeitig bei tA der
Schleifenzähler S in ein Hilfsregister übertragen, an dessen
Ausgang ein Dekrementiernetz hängt. Bei tB wird das Ergebnis
in S gespeichert, falls S vorher nicht Null war.

Man sieht, dass wirklich alles parallel ausgeführt wird und
nicht länger dauert als das Inkrementieren des Adressregisters
allein. Das Inkrementieren des Adressregisters wird auch nicht
künstlich verlängert, um gleiche Dauer wie bei den kombinierten
Befehlen zu erreichen.

Würde man das CPU-Konzept grundlegend ändern und die Hilfsregister
einsparen und statt tA/tB nur eine Phase haben, könnte man das auf
alle genannten parallel ablaufenden Vorgänge anwenden, und die
gleiche Dauer von kombinierten Befehlen und einfachem
Inkrementieren würde weiter gelten.

von Robert L. (lrlr)


Lesenswert?

Josef G. schrieb:
> Das Inkrementieren/Dekrementieren eines Adressregisters
> dauert 1 Vollzyklus, ebenso die kombinierten Befehle.

nein...

wenn ich das jetzt richtig verstanden habe, ist dein "kominierter 
Befehl" kein echter "bedingter Sprung" ..

der würde nämlich eine Zieladresse beinhalten..
(im nahen und sehr nahen Umfeld)

http://www.mathemainzel.info/files/x86asmref.html#jne

du hingegen hast hier Arbeit auf 2 Befehle aufgeteilt (S.RP  und  R.IY)
d.h. man muss fairerweise auch die Zeit von beiden addieren..


ist mir aber soweiso unklar, wie man hiermit verschachtelte schleifen 
programmierne kann ..


p.s. schön dass du alle anderen Ausführungen ignoriert hast und nur auf 
das Antwortest was dir lieb ist..

von Josef G. (bome) Benutzerseite


Lesenswert?

Robert L. schrieb:
> du hingegen hast hier Arbeit auf 2 Befehle aufgeteilt (S.RP  und  R.IY)
> d.h. man muss fairerweise auch die Zeit von beiden addieren..

Nein, man muss die Zeiten nicht addieren. Das S.RP steht
ausserhalb der Schleife und wird nur 1-mal ausgeführt.

> ist mir aber soweiso unklar, wie man hiermit verschachtelte schleifen
> programmierne kann ..

Das ist in der Tat nicht möglich. Der schnelle Rückwärtssprung ist
nur für die innerste Schleife gedacht, für äussere Schleifen muss
man bedingte Rückwärtssprünge ( B.xx nn ) mit expliziter Angabe
der Sprungdistanz nn verwenden. Bei dieser äusseren Schleife
ist aber die Dauer des Rückwärtssprungs vernachlässigbar
gegenüber der Gesamtdauer der inneren Schleife.

von Josef G. (bome) Benutzerseite


Lesenswert?

Die schnellen Rückwärtssprünge bei meiner CPU gibt es natürlich auch
ohne Inkrementieren oder Dekrementieren eines Adressregisters.

von Josef G. (bome) Benutzerseite


Lesenswert?

Angeregt durch diesen aktuellen Thread
Beitrag "goto verpönt - was dann nehmen?"
möchte ich hiermit nochmal einen Versuch machen,
für meine Programmiersprache zu werben.

Es gibt in dieser Sprache kein goto, kein break, kein continue,
und in jedem Programm oder Unterprogramm genau 1 return,
nämlich am Ende des Programms oder Unterprogramms.

Die Strukturelemente sind folgende:
1
Bedingte Anweisung:  IF.c  ...  ENDF
2
Verzweigung:         IF.c  ...  ELSE  ...  ENDE
3
Case-Struktur:       CASE /nn  ...  NEXT /nn  ...  LAST
4
Do-while-Schleife:   LOOP  ...  RP.c
5
While-Schleife:      L.JP  ...  HERE  ...  RP.c

c steht hier für die Sprungbedingung, nn steht für eine Zahl
fallend bis 00, NEXT /nn ist entsprechend mehrmals anzugeben.

RP.c steht für wiederhole falls c.
Ebenso wie  IF.c ... ELSE ... ENDE  zählt die
Schleife mit Hineinsprung  L.JP ... HERE ... RP.c  als ein
Block mit zwei Unterblöcken, die strenge Blockstruktur
wird durch den Hineinsprung nicht durchbrochen.

Unterprogramme: Es gibt keine functions mit Rückgabewert,
sondern nur einfache Unterprogramme, bei welchen alle Parameter
gleichberechtigt sind. Es werden ausschließlich Zeiger übergeben.

http://www.mikrocontroller.net/articles/8bit-Computer:_bo8h

von Uhu U. (uhu)


Lesenswert?

Josef G. schrieb:
> Angeregt durch diesen aktuellen Thread
> Beitrag "goto verpönnt - was dann nehmen?"
> möchte ich hiermit nochmal einen Versuch machen,
> für meine Programmiersprache zu werben.

Du willst doch nicht etwa Kurt die Schau stehlen?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Josef G. schrieb:
> Unterprogramme: Es gibt keine functions mit Rückgabewert,
> sondern nur einfache Unterprogramme, bei welchen alle Parameter
> gleichberechtigt sind.

Reiner Masochismus bringt mich dazu, Dich zu fragen, was das sein soll.

von Josef G. (bome) Benutzerseite


Lesenswert?

Rufus Τ. F. schrieb:
> was das sein soll.

Beim Aufrufen werden nach dem Namen des Unterprogramms die Namen
der Parameter aufgelistet. Das Unterprogramm kann die Parameter
lesen und beschreiben, sofern der betreffende Variablentyp das zu-
lässt. Damit kann jeder Parameter auch für die Rückgabe verwendet
werden. Einen speziellen Rückgabe-Parameter gibt es nicht.

von (prx) A. K. (prx)


Lesenswert?

Rufus Τ. F. schrieb:
> Reiner Masochismus bringt mich dazu, Dich zu fragen, was das sein soll.

Vereinfacht den Compiler. Sowohl in der so sehr einfachen Syntax, als 
auch bei der Umsetzung in Code. Verschachtelte Aufrufe kann es damit 
nicht geben, so dass man sich keine andere Ausrede überlegen muss, 
weshalb man sie nicht zulässt. Und dass sein Sinn für Ästhetik deutlich 
anders entwickelt ist, als bei jedem anderen, wissen wir bereits.

: Bearbeitet durch User
von Uhu U. (uhu)


Lesenswert?

Rufus Τ. F. schrieb:
> Reiner Masochismus

Rainer Unsinn ist hier bekannt, aber wer ist Reiner Masochismus?

von Josef G. (bome) Benutzerseite


Lesenswert?

A. K. schrieb:
> Verschachtelte Aufrufe kann es damit nicht geben,

Bin zwar nicht ganz sicher, was damit gemeint ist, aber, nur
damit es keine Missverständnisse gibt: Unterprogramme können
selbstverständlich ihrerseits andere Unterprogramme aufrufen.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Josef G. schrieb:
> Bin zwar nicht ganz sicher, was damit gemeint ist,

Ja, das war etwas undeutlich ausgedrückt. In diesem Fall meine ich einen 
Funktionsaufruf als Argument eines Unterprogrammaufrufs. Also sowas wie
   call foobar (1, sin(0.5))
statt
   temp = sin(0.5)
   call foobar (1, temp)
oder bei dir sinngemäss wohl
   call sin (0,5, temp)
   call foobar (1, temp)
falls du Konstanten als Argumente überhaupt zulässt.

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Josef G. schrieb:
> Beim Aufrufen werden nach dem Namen des Unterprogramms die Namen
> der Parameter aufgelistet. Das Unterprogramm kann die Parameter
> lesen und beschreiben, sofern der betreffende Variablentyp das zu-
> lässt.

Toll. Und was ist daran jetzt besonders, abgesehen davon, daß man beim 
Betrachten des Aufrufs eines "Unterprogrammes" nicht sieht, welche 
Parameter verändert werden können (ohne sich das "Unterprogramm" näher 
anzusehen)?

Praktisch jede andere Programmiersprache kennt das auch - in Pascal 
nennt sich das "call by reference", in C verwendet man Pointer auf die 
Argumente, und in C++ kann man das auch machen, oder die dafür 
vorgesehenen Referenzen verwenden.

Bei C/C++ und der Verwendung von Pointern kann man auch ohne Betrachtung 
der aufgerufenen Funktion (bzw. ihres Prototypen) erkennen, welche der 
Parameter verändert werden könnten und welche nicht - wo kein Pointer 
übergeben wird, kann auch nichts verändert werden.

Oh, und man hat in all diesen Programmiersprachen auch die Möglichkeit, 
einen expliziten Rückgabewert zu verwenden, was z.B. zum Zurückgeben 
von Fehlercodes sinnvoll sein kann.

Bei der "ich schreib' hier mal zehn Parameter hin"-Methode muss man 
jedes mal erneut vereinbaren, welcher davon ein etwaiger Fehlercode sein 
könnte.

Nein, ich vermag keinen einzigen Vorteil zu erkennen.

von (prx) A. K. (prx)


Lesenswert?

Rufus Τ. F. schrieb:
> Praktisch jede andere Programmiersprache kennt das auch

Wie etwa FORTRAN, wo stets call by reference verwendet wird.

von Uhu U. (uhu)


Lesenswert?

Rufus Τ. F. schrieb:
> Nein, ich vermag keinen einzigen Vorteil zu erkennen.

Das ist der Vorteil der Methode!

von (prx) A. K. (prx)


Lesenswert?

Es ist oft genug grad andersrum, d.h. es gibt einen gewisse Neigung, 
mehrere Returnobjekte zuzulassen, nicht nur eines. Entweder, indem man 
Klassenobjekte als Returnwert verwendet (wie in C++), oder indem die 
Sprache ganz offizell mehrere Returnobjekte zulässt (wie etwa Go).

Ein klassisches Beispiel dafür ist eine Funktion, die neben dem 
eigentlichen Returnwert auch noch mitteilen muss, ob sie überhaupt einen 
gültigen Wert produzieren konnte. Damit entsteht ein Paar aus dem Wert 
selbst und einem Error-Flag.

Natürlich kann man das auch per Referenz-Parameter implementieren. 
Leider bewegt man sich damit allzu leicht von übersichtlicherer 
funktionaler Programmierung mit seiteneffektfreien Funktionen weg und 
die Programme werden zudem auch länger.

Hinzu kommt, dass Objekte in Registern weit besser aufgehoben sind als 
im Speicher, was die Rechenleistung angeht. Übergabe von Werten in 
Registern ist daher sehr viel effizienter als die Übergabe von Werten im 
Speicher und deren Speicheradressen in Registern. Das gilt 
gleichermassen für Parameter wie für Returnobjekte.

Es gibt Programmiersprachen, die Parameter in "in", "out" und "inout" 
unterscheiden. Bei "in" und "out" kommt man dem Prinzip nach ganz gut 
ohne Speicheradresse aus und "out" Parameter liessen sich auch als 
Returnobjekte darstellen.

Ob Grunde bewegt man sich mit dem konsequenten Verzicht auf call by 
value also zurück in 50er Jahre, die Zeit der Entstehung von FORTRAN. 
Eine Zeit, in der Register sehr aufwändig und daher selten waren.

: Bearbeitet durch User
von Robert L. (lrlr)


Lesenswert?

>möchte ich hiermit nochmal einen Versuch machen,
>für meine Programmiersprache zu werben.

die nur auf einer 8-bit CPU funktioniert, die es nicht mal gibt..

na viel glück..

von Josef G. (bome) Benutzerseite


Lesenswert?

Rufus Τ. F. schrieb:
> Nein, ich vermag keinen einzigen Vorteil zu erkennen.

Die Anwendung des Prinzips Minimalismus hat immerhin
den Vorteil, dass die Sprache leichter zu erlernen
wäre, wenn es denn jemand versuchen würde.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Da ist nichts minimalistisches. Eine Programmiersprache wie C ist 
minimalistisch, das ist auch einer der Gründe für ihren langanhaltenden 
Erfolg.

von Josef G. (bome) Benutzerseite


Lesenswert?

Rufus Τ. F. schrieb:
> Da ist nichts minimalistisches.
> Eine Programmiersprache wie C ist minimalistisch,

Also diese Antwort versteh ich nun wirklich nicht.
Ausgangspunkt waren meine Aussagen:

Josef G. schrieb:
> Unterprogramme: Es gibt keine functions mit Rückgabewert,
> Es werden ausschließlich Zeiger übergeben.

In meiner Sprache gibt es also nur eine Sorte von Parametern.
In C gibt es mehrere Sorten. Da ist es doch offensichtlich, dass
in dieser Hinsicht meine Sprache minimalistischer ist als C.

von Robert L. (lrlr)


Lesenswert?

nur weil was minimalistisch ist, ist es nicht automatisch einfacher..

Schach Regeln sind sehr einfach.. ist deshalb Schach spielen einfach?



gerade in/out/var/const parameter machen vieles einfacher
gäbs das nicht, müsste man es eben in die doku schreiben..
(nur lesen leider die meisten Compiler die doku nicht, und können somit 
auch nichts überprüfen..)

von Gu. F. (mitleser)


Lesenswert?

Josef G. schrieb:
> Da ist es doch offensichtlich, dass
> in dieser Hinsicht meine Sprache minimalistischer ist als C.

Auf den Nutzen bezogen hast du wohl recht.

von Uhu U. (uhu)


Lesenswert?

Josef, wenn du damit vor 50 Jahren gekommen wärst, hättest du evtl. 
Interesse erregen können. Heute wirst du damit höchstens belächelt...

von (prx) A. K. (prx)


Lesenswert?

Hau noch mindestens 10 Jahre drauf. Vor 50 Jahren gab es FORTRAN, Lisp, 
Algol, APL, COBOL, BASIC, PL/I, BCPL(*), ... Alle lesbarer. ;-)

*: aka "Before C Programming Language". Für B langts noch nicht ganz.

: Bearbeitet durch User
von Uhu U. (uhu)


Lesenswert?

Der Fairness halber sollte man ASM als Vergleich heranziehen - damit 
wurde seinerzeit noch sehr viel gemacht.

Das alles ändert aber nichts an der Lächerlichkeit, ein Projekt wie 
dieses hier heutzutage als Ultima Ratio anzupreisen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.