Polyglottes Programm

aus Wikipedia, der freien Enzyklopädie
Zur Navigation springen Zur Suche springen

Ein polyglottes Programm (polyglott = mehrsprachig) ist ein Computerprogramm, dessen Quelltext in mehr als einer Programmiersprache gültig ist; d. h., es kann vom jeweiligen Interpreter bzw. Compiler jeder der dafür vorgesehenen Sprachen fehlerfrei ausgeführt bzw. übersetzt werden. In der Regel erzeugt es bei der Ausführung in den verschiedenen Sprachen jeweils dieselbe Ausgabe. Ein solches Programm hat keinerlei Nutzen für die Allgemeinheit, seine Erstellung ist lediglich eine anspruchsvolle Übung für den Programmierer.

Während es nahezu unmöglich sein dürfte, einen natürlichsprachigen polyglotten Text zu formulieren, ist die Erstellung eines polyglotten Programms weniger schwierig, als es zunächst den Anschein hat. Bei der Entwicklung polyglotter Programme macht man sich die folgenden Tatsachen bzw. Methoden zunutze:

  • Teile des Codes können in mehreren Programmiersprachen gültig sein, z. B. erzeugt „printf ("...")“ sowohl in Perl als auch in C eine textuelle Ausgabe.
  • Man kann durch Sprungbefehle die in der jeweiligen Sprache ungültigen Teile des Quelltextes überspringen oder die Programmausführung mit exit „rechtzeitig“ vor dem Auftauchen ungültigen Codes terminieren.
  • Eine Programmzeile kann in der einen Programmiersprache ausführbaren Code, in der anderen einen Kommentar darstellen. Beispielsweise ist „# include ...“ in C eine Präprozessoranweisung, in vielen Skriptsprachen – wegen des Zeichens „#“ am Zeilenanfang – eine Kommentarzeile.
  • In manchen Programmiersprachen (z. B. in C mit einer Präprozessoranweisung) kann man Tokens neu definieren oder vorhandene redefinieren und damit ein in einer fremden Programmiersprache gültiges Token auch in der eigenen – u. U. in einer anderen Bedeutung – gültig werden lassen.

Ein einfaches Beispiel

[Bearbeiten | Quelltext bearbeiten]

Das folgende Beispiel ist weit weniger spektakulär als die in den Weblinks referenzierten; es wurde speziell mit dem Ziel der Verständlichkeit auch für den Laien entworfen. Es macht von den ersten drei der oben genannten Techniken Gebrauch.

Quelltext Erläuterung

# include <stdio.h> /*                  
eval "echo 'Hello, world!'; exit";
sub echo { print "@_\n" }; __END__ */
main() { printf ("Hello, world!\n"); }

Der nebenstehende Quelltext ist gültig in C, Perl und vielen Unix-Shells (Bourne Shell, Korn-Shell, Bash, C-Shell, Z-Shell). Das Programm gibt den Text „Hello, world!“ aus.

# include <stdio.h> /*
eval "echo 'Hello, world!'; exit";
sub echo { print "@_\n" }; __END__ */
main() { printf ("Hello, world!\n"); }

C
Der von /* und */ eingeschlossene Text (hier grün eingefärbt) ist in C Kommentar und wird ignoriert. Der Rest ist eine Variante des Hallo-Welt-Programms in C.

# include <stdio.h> /*
eval "echo 'Hello, world!'; exit";
sub echo { print "@_\n" }; __END__ */
main() { printf ("Hello, world!\n"); }

Unix-Shells
Die erste Zeile (grün) ist eine Kommentarzeile und wird ignoriert. Wenn die eval-Anweisung ausgeführt wurde, terminiert das Programm wegen des exit; der Rest (grau) wird vom Interpreter nicht mehr eingelesen und daher auch nicht auf korrekte Syntax geprüft.

# include <stdio.h> /*
eval "echo 'Hello, world!'; exit";
sub echo { print "@_\n" }; __END__ */
main() { printf ("Hello, world!\n"); }

Perl
Die erste Zeile ist Kommentar. Die eval-Anweisung wird erst ausgeführt, nachdem in Zeile 3 die Subroutine echo definiert wurde. Der auf das Schlüsselwort __END__ folgende Rest (grau) wird vom Perl-Interpreter gelesen, aber ignoriert.

Ein komplexeres Beispiel

[Bearbeiten | Quelltext bearbeiten]

Der folgende Quelltext ist gültig in C, PHP und Bash. Es werden alle oben beschriebenen Methoden genutzt, insbesondere ist für die Kompatibilität mit C in etlichen Fällen die Neu- oder Umdefinition von Zeichenfolgen erforderlich. Diese erfolgen in den mit „#define“ beginnenden Zeilen, die für die beiden Skriptsprachen Kommentarzeilen sind.

#define a /*
#<?php
echo "\010Hello, world!\n"// 2> /dev/null > /dev/null \ ;
// 2> /dev/null; x=a;
$x=5 // 2> /dev/null \ ;
if (($x))
// 2> /dev/null; then
return 0;
// 2> /dev/null; fi
#define e ?>
#define b */
#include <stdio.h>
#define main() int main()
#define printf printf(
#define true )
#define function
function main()
{
printf "Hello, world!\n"true/* 2> /dev/null | grep -v true*/;
return 0;
}
#define c /*
main
#*/

MS-DOS und Perl

[Bearbeiten | Quelltext bearbeiten]

Das folgende Programm kann durch den Perl-Interpreter oder als DOS-Batchdatei ausgeführt werden. (Erläuterungen zu jeder Zeile rechts neben dem Quelltext.)

Quelltext DOS Perl
@rem = '
@echo Hello, world!
@goto END
';
print substr "@rem", 7, 13;
__END__
: END
Kommentar
Ausgabe
Sprung ans Ende
wird übersprungen
wird übersprungen
wird übersprungen
Ende Code
Definition des Arrays @rem
Inhalt des Arrays @rem
Inhalt des Arrays @rem
Ende der Definition von @rem
Ausgabe Teilstring aus @rem
Ende Code
wird ignoriert

DOS-Wrapper für Perl

[Bearbeiten | Quelltext bearbeiten]

In ähnlicher Weise kann eine DOS-Batchdatei für den Aufruf eines Perl-Programms erstellt werden: Die DOS-Batchdatei enthält den Perl-Code und führt sich selbst (in Zeile 10) mit dem Perl-Interpreter aus. Es bedarf allerdings einigen Aufwandes, die Kommandozeilen-Argumente einzusammeln und an Perl zu übergeben:

@rem = ' ---------- BEGIN DOS ------------------
    @echo off
    set PROG=%0.bat
    : ARG LOOP
        if "%1" == "" goto EXEC
        set ARGS=%ARGS% %1
        shift
        goto ARG LOOP
    : EXEC
    perl %PROG% %ARGS%
    goto END
';
# ================ BEGIN PERL ==================

print "Perl here with these arguments: @ARGV\n";

__END__ # ========= END PERL ===================
: END
set PROG=
set ARGS=
:: ---------------- END DOS --------------------

Weitere Beispiele für nutzlose, aber lehrreiche Programme:

(Alle hier angegebenen Quellen sind in englischer Sprache.)