 |
Das deutsche QBasic- und FreeBASIC-Forum Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
nemored

Anmeldungsdatum: 22.02.2007 Beiträge: 4702 Wohnort: ~/
|
Verfasst am: 11.01.2013, 21:50 Titel: Programm, das eigenen Quellcode ausgibt |
|
|
Was in Interpreter-BASIC-Sprachen über den Befehl LIST noch sehr einfach war, ist in einer compilierenden Sprache schon schwieriger. Es geht um ein Programm, das seinen eigenen Quellcode ausgibt. Das Programm darf gezielt so gestaltet sein, das es lediglich die Aufgabe, sich selbst auszugeben, erfüllt. Ich habe mich da mal vor einem Jahr oder so damit beschäftigt, und vor ein paar Tagen aus der Erinnerung heraus rekonstruiert.
Vorneweg: Leere Programme, die entsprechend auch eine leere Ausgabe liefern, sind bei dieser Fragestellung nicht erlaubt. Auch das Auslesen der Quelltextdatei zählt offenbar nicht - aber sonst wäre es auch viel zu leicht.
Der Trick ist, dass der Programminhalt doppelt vorkommt - einmal normal als Code und einmal als Textinhalt. Ich mache das über DATA-Zeilen; ein STRING-Array mit Initialwerten geht vermutlich auch (muss ich mal probieren). Was dabei herausgekommen ist, ist folgendes:
Code: | DIM zeilenzahl AS INTEGER = 11, zeile(zeilenzahl) AS STRING, datastr AS STRING
READ datastr
FOR zeilennr AS INTEGER = 1 TO zeilenzahl
READ zeile(zeilennr)
PRINT zeile(zeilennr)
NEXT
PRINT datastr; CHR(34); datastr; CHR(34)
FOR zeilennr AS INTEGER = 1 TO zeilenzahl
PRINT datastr; CHR(34); zeile(zeilennr); CHR(34)
NEXT
SLEEP
DATA "DATA "
DATA "DIM zeilenzahl AS INTEGER = 11, zeile(zeilenzahl) AS STRING, datastr AS STRING"
DATA "READ datastr"
DATA "FOR zeilennr AS INTEGER = 1 TO zeilenzahl"
DATA " READ zeile(zeilennr)"
DATA " PRINT zeile(zeilennr)"
DATA "NEXT"
DATA "PRINT datastr; CHR(34); datastr; CHR(34)"
DATA "FOR zeilennr AS INTEGER = 1 TO zeilenzahl"
DATA " PRINT datastr, CHR(34); zeile(zeilennr); CHR(34)"
DATA "NEXT"
DATA "SLEEP" |
Kürzer bekomme ich das nur hin, wenn ich alle Befehle in eine Zeile schreibe - dann spare ich mir die beiden Schleifen. Ist natürlich auch nicht mehr ganz so übersichtlich.
Code: | DIM AS STRING d,z:READ d:READ z:PRINT z:PRINT d;CHR(34);d;CHR(34,44,34);z;CHR(34)
DATA "DATA ","DIM AS STRING d,z:READ d:READ z:PRINT z:PRINT d;CHR(34);d;CHR(34,44,34);z;CHR(34)" |
Geht es noch kürzer* / besser? Oder interessanter?
*) abgesehen davon, dass man ? statt PRINT schreiben könnte ... _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
 |
Roland Chastain

Anmeldungsdatum: 05.12.2011 Beiträge: 194 Wohnort: Frankreich
|
Verfasst am: 12.01.2013, 10:00 Titel: |
|
|
Nicht besser, aber kürzer vielleicht ?
Code: | ' Quellcode.bas
' Programm, das eigenen Quellcode ausgibt
dim as string fName = "Quellcode.bas"
dim as integer fNumber = FreeFile
if Open(fName for input as #fNumber) then end -1
do until Eof(fNumber)
dim as string text
Line input #fNumber, text
if Len(text) andAlso (text[0] = Asc("'")) then Color 8 else Color 7
Print text
loop
Close #fNumber
Locate 25, 1, 0
Color 7, 5
Print Dr"&Chr(129)&"cken Sie eine beliebige Taste...";
Sleep : end 0 |
|
|
Nach oben |
|
 |
MOD Fleißiger Referenzredakteur

Anmeldungsdatum: 10.09.2007 Beiträge: 1003
|
Verfasst am: 12.01.2013, 12:32 Titel: |
|
|
Tut mir Leid Roland, aber nemored hat Folgendes geschrieben: | das Auslesen der Quelltextdatei zählt [...] nicht |
Das Ganze nennt sich übrigens Quine. Im englischen Forum gab es vor einiger Zeit auch einen Thread dazu: FB Quine |
|
Nach oben |
|
 |
Roland Chastain

Anmeldungsdatum: 05.12.2011 Beiträge: 194 Wohnort: Frankreich
|
Verfasst am: 12.01.2013, 12:57 Titel: |
|
|
Danke für die Erklärung. |
|
Nach oben |
|
 |
nemored

Anmeldungsdatum: 22.02.2007 Beiträge: 4702 Wohnort: ~/
|
Verfasst am: 12.01.2013, 14:14 Titel: |
|
|
Ja, Roland, das war auch mein allererster Ansatz - aber leider nicht erlaubt.
Eine Stringarray-Version habe ich inzwischen auch:
Code: | DIM AS STRING zeile(0 TO ...) = { _
"DIM AS STRING zeile(0 TO ...) = {", _
"PRINT zeile(0); CHR(32, 95)", _
"FOR zeilennr AS INTEGER = 0 TO UBOUND(zeile)-1", _
" PRINT CHR(32, 32, 34); zeile(zeilennr); CHR(34, 44, 32, 95)", _
"NEXT", _
"PRINT CHR(32, 32, 34); zeile(UBOUND(zeile)); CHR(34, 32, 125)", _
"FOR zeilennr AS INTEGER = 1 TO UBOUND(zeile)", _
" PRINT zeile(zeilennr)", _
"NEXT", _
"SLEEP" }
PRINT zeile(0); CHR(32, 95)
FOR zeilennr AS INTEGER = 0 TO UBOUND(zeile)-1
PRINT CHR(32, 32, 34); zeile(zeilennr); CHR(34, 44, 32, 95)
NEXT
PRINT CHR(32, 32, 34); zeile(UBOUND(zeile)); CHR(34, 32, 125)
FOR zeilennr AS INTEGER = 1 TO UBOUND(zeile)
PRINT zeile(zeilennr)
NEXT
SLEEP |
Muss ich mal mit der im Link vergleichen; ein paar Sachen machen die wohl anders. Ob es mit q=CHR(34) wirklich kürzer wird? Mal sehen.
Mit ASM ist das natürlich gemein. Das würde ich ja nur bedingt zählen lassen.
edit: hey, die Variante mit dem Präprozessor ist ja genial!  _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
 |
volta
Anmeldungsdatum: 04.05.2005 Beiträge: 1876 Wohnort: D59192
|
Verfasst am: 30.01.2013, 20:23 Titel: |
|
|
Hi,
zählt das denn?
Code: | Dim As UByte Ptr StartFile 'Pointer für den Anfang des File
Dim As UInteger LenFile 'Variable für die Länge des File
Asm
.balign 16
jmp START_OF_PROG 'springe zum Label
.balign 4
START_OF_FILE: 'ab hier beginnt die eingebundene Datei
.incbin "./quine.bas" 'Name des Quelltextes
END_OF_FILE: 'hier endet die eingebundene Datei
.balign 16
START_OF_PROG:
lea ebx, START_OF_FILE 'Lade die Adresse des Label START_OF_FILE nach ebx
mov dword Ptr [StartFile], ebx 'Speicher die Adresse im Pointer StartFile
lea eax, END_OF_FILE 'Lade die Adresse des Label END_OF_FILE nach eax
Sub eax, ebx 'berechne eax - ebx = Länge des File
mov dword Ptr [LenFile], eax 'Speicher die Länge des File in der Variablen LenFile
End Asm
For i As Integer = 0 To LenFile-1
Print Chr(StartFile[i]);
Next
Sleep | ich habe den Quälcode als quine.bas angelegt.
Ein anderer Name müsste dann im Quelltext eingetragen werden. _________________ Warnung an Choleriker:
Dieser Beitrag kann Spuren von Ironie & Sarkasmus enthalten.
Zu Risiken & Nebenwirkungen fragen Sie Ihren Therapeuten oder Psychiater. |
|
Nach oben |
|
 |
RockTheSchock
Anmeldungsdatum: 04.04.2007 Beiträge: 138
|
Verfasst am: 31.01.2013, 12:10 Titel: Quellcode in exe einbinden |
|
|
Der ASM Code muss direkt am begin der Datei eingefügt werden, sodass unter lpData nur der eigentliche Quellcode gespeichert wird
.incbin __FILE__,208 Überspringt die ersten 208 bytes, den asm teil
Code: | Dim As ZString Ptr lpData
Asm
jmp binary_end
.balign 16
binary_start:
.incbin __FILE__,208
.asciz "\n"
.balign 16
binary_end:
lea eax, binary_start
mov [lpData], eax
End Asm
'Hier gehts los
Screen 0
Print *lpData
Sleep
|
Quelle:
http://www.freebasic.net/forum/viewtopic.php?f=8&t=7869
Abgewandelt, sodass die Daten als ZString interpretiert werden und der ASM teil übersprungen wird.
Zuletzt bearbeitet von RockTheSchock am 31.01.2013, 13:33, insgesamt 7-mal bearbeitet |
|
Nach oben |
|
 |
volta
Anmeldungsdatum: 04.05.2005 Beiträge: 1876 Wohnort: D59192
|
Verfasst am: 31.01.2013, 12:52 Titel: |
|
|
Hi RockTheSchock,
schönes Beispiel was FB und AS zusammen können  _________________ Warnung an Choleriker:
Dieser Beitrag kann Spuren von Ironie & Sarkasmus enthalten.
Zu Risiken & Nebenwirkungen fragen Sie Ihren Therapeuten oder Psychiater. |
|
Nach oben |
|
 |
nemored

Anmeldungsdatum: 22.02.2007 Beiträge: 4702 Wohnort: ~/
|
Verfasst am: 31.01.2013, 14:41 Titel: |
|
|
Wenn der ASM-Teil übersprungen wird, ist es denn dann überhaupt noch die Ausgabe des gesamten Quelltextes? Bei mir (unter Linux) beginnt die Ausgabe übrigens mit dem "os" aus dem Kommentar "'Hier gehts los" - keine Ahnung, ob das systembedingt ist.
Volta, du könntest auch __FILE__ verwenden, um den Dateinamen herauszufinden. Ich habe gerade getestet, ob ich deinen Code als Include-Datei speichern und in eine SUB LIST() packen kann - funktioniert im Prinzip schon ganz gut, jetzt habe ich aber wieder das Problem, wie ich den Quelldatei-Namen in die SUB hineinbringe (ohne hardcoden). Vielleicht gibt es da ja eine elegante Lösung? _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
 |
RockTheSchock
Anmeldungsdatum: 04.04.2007 Beiträge: 138
|
Verfasst am: 31.01.2013, 15:17 Titel: |
|
|
Zitat: | Wenn der ASM-Teil übersprungen wird, ist es denn dann überhaupt noch die Ausgabe des gesamten Quelltextes?
|
Der ASM Teil ist nicht für die Funktionalität deines Programms verantwortlich. Der Quellcode der Datei wird lediglich in die Exe geschrieben und ein Pointer um darauf zuzugreifen wird dimensioniert und im ASM Teil richtig initialisiert. Allerdings sollte der Zugriff auf den Pointer in einer Sub gekapselt werden die mit ausgegeben wird und mit preprozessoranweisungen abgesichert ist, dass ganze Konstrukt kann man auch in eine bi datei packen und sie in der ersten Zeile des Quellcodes mit #include einbinben
Zitat: | Bei mir (unter Linux) beginnt die Ausgabe übrigens mit dem "os" aus dem Kommentar "'Hier gehts los" - keine Ahnung, ob das systembedingt ist.
|
Das hängt wahrscheinlich damit zusammen dass Linux statt zwei Zeichen nur eins für "newline" verwendet. Dadurch sind es 13 bytes weniger für den ASM Teil. Also 208-16 => 192
-16 wegen des alignments |
|
Nach oben |
|
 |
volta
Anmeldungsdatum: 04.05.2005 Beiträge: 1876 Wohnort: D59192
|
Verfasst am: 31.01.2013, 16:05 Titel: |
|
|
Hi nemored,
leider akzeptiert .incbin nur einen Filenamen, keinen Zeiger auf einen String etc. Bisher kenne ich keinen Trick dies zu umgehen.
@RockTheSchock
Zitat: | Der ASM Code muss direkt am begin der Datei eingefügt werden, sodass unter lpData nur der eigentliche Quellcode gespeichert wird | Es funktioniert auch in eine Sub oder Function, auch am Ende des Quelltext (.incbin "file"[,skip[,count]] nur ohne skip).
Code: | Declare Sub PrintQuelltext ()
Color 14
PrintQuelltext
Sleep
Sub PrintQuelltext ()
Dim As ZString Ptr Quelltext'Pointer für den Anfang des Quelltext
Asm
.balign 16
jmp START_OF_PROG 'springe zum Label
START_OF_FILE: 'ab hier beginnt die eingebundene Datei
.incbin __FILE__ 'Name des Quelltextes
.byte 0 'Abschluss des ZString
START_OF_PROG:
lea ebx, START_OF_FILE'Lade die Adresse des Label START_OF_FILE
mov [Quelltext], ebx 'Speicher die Adresse im Pointer Quelltext
End Asm
Print *Quelltext
End Sub |
_________________ Warnung an Choleriker:
Dieser Beitrag kann Spuren von Ironie & Sarkasmus enthalten.
Zu Risiken & Nebenwirkungen fragen Sie Ihren Therapeuten oder Psychiater. |
|
Nach oben |
|
 |
nemored

Anmeldungsdatum: 22.02.2007 Beiträge: 4702 Wohnort: ~/
|
Verfasst am: 31.01.2013, 17:13 Titel: |
|
|
Zitat: | Der ASM Teil ist nicht für die Funktionalität deines Programms verantwortlich. |
Die Funktion eines Quine ist doch, eine Kopie seines eigenen Quellcodes auszugeben, also würde ich sagen, dass der ASM-Teil bei euch von entscheidender Bedeutung ist.
Zitat: | Zitat: | Bei mir (unter Linux) beginnt die Ausgabe übrigens mit dem "os" aus dem Kommentar "'Hier gehts los" - keine Ahnung, ob das systembedingt ist.
|
Das hängt wahrscheinlich damit zusammen dass Linux statt zwei Zeichen nur eins für "newline" verwendet. Dadurch sind es 13 bytes weniger für den ASM Teil. Also 208-16 => 192
-16 wegen des alignments |
Das ist richtig - wenn ich auf Windows-Zeilenumbrüche umstelle, passt es. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
 |
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
|