Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht Das deutsche QBasic- und FreeBASIC-Forum
Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
 
FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen  RegistrierenRegistrieren
ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin
Zur Begleitseite des Forums / Chat / Impressum
Aktueller Forenpartner:

Programm, das eigenen Quellcode ausgibt

 
Neues Thema eröffnen   Neue Antwort erstellen    Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht -> Allgemeine Fragen zu FreeBASIC.
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
nemored



Anmeldungsdatum: 22.02.2007
Beiträge: 4702
Wohnort: ~/

BeitragVerfasst am: 11.01.2013, 21:50    Titel: Programm, das eigenen Quellcode ausgibt Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden
Roland Chastain



Anmeldungsdatum: 05.12.2011
Beiträge: 194
Wohnort: Frankreich

BeitragVerfasst am: 12.01.2013, 10:00    Titel: Antworten mit Zitat

Nicht besser, aber kürzer vielleicht ? lächeln

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
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
MOD
Fleißiger Referenzredakteur


Anmeldungsdatum: 10.09.2007
Beiträge: 1003

BeitragVerfasst am: 12.01.2013, 12:32    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden
Roland Chastain



Anmeldungsdatum: 05.12.2011
Beiträge: 194
Wohnort: Frankreich

BeitragVerfasst am: 12.01.2013, 12:57    Titel: Antworten mit Zitat

verlegen

Danke für die Erklärung.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
nemored



Anmeldungsdatum: 22.02.2007
Beiträge: 4702
Wohnort: ~/

BeitragVerfasst am: 12.01.2013, 14:14    Titel: Antworten mit Zitat

Ja, Roland, das war auch mein allererster Ansatz - aber leider nicht erlaubt. traurig

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. grinsen


edit: hey, die Variante mit dem Präprozessor ist ja genial! geschockt
_________________
Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
volta



Anmeldungsdatum: 04.05.2005
Beiträge: 1876
Wohnort: D59192

BeitragVerfasst am: 30.01.2013, 20:23    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
RockTheSchock



Anmeldungsdatum: 04.04.2007
Beiträge: 138

BeitragVerfasst am: 31.01.2013, 12:10    Titel: Quellcode in exe einbinden Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden
volta



Anmeldungsdatum: 04.05.2005
Beiträge: 1876
Wohnort: D59192

BeitragVerfasst am: 31.01.2013, 12:52    Titel: Antworten mit Zitat

Hi RockTheSchock,
schönes Beispiel was FB und AS zusammen können lächeln
_________________
Warnung an Choleriker:
Dieser Beitrag kann Spuren von Ironie & Sarkasmus enthalten.
Zu Risiken & Nebenwirkungen fragen Sie Ihren Therapeuten oder Psychiater.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
nemored



Anmeldungsdatum: 22.02.2007
Beiträge: 4702
Wohnort: ~/

BeitragVerfasst am: 31.01.2013, 14:41    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden
RockTheSchock



Anmeldungsdatum: 04.04.2007
Beiträge: 138

BeitragVerfasst am: 31.01.2013, 15:17    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden
volta



Anmeldungsdatum: 04.05.2005
Beiträge: 1876
Wohnort: D59192

BeitragVerfasst am: 31.01.2013, 16:05    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
nemored



Anmeldungsdatum: 22.02.2007
Beiträge: 4702
Wohnort: ~/

BeitragVerfasst am: 31.01.2013, 17:13    Titel: Antworten mit Zitat

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. happy

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
Benutzer-Profile anzeigen Private Nachricht senden
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht -> Allgemeine Fragen zu FreeBASIC. Alle Zeiten sind GMT + 1 Stunde
Seite 1 von 1

 
Gehe zu:  
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.

 Impressum :: Datenschutz