Machen Sie eine finky Syntaxprüfung

8

Sie müssen ein Programm erstellen, das die Syntax von Programmen derselben Sprache überprüfen kann. Wenn Sie dies beispielsweise in Python tun, wird die Python-Syntax überprüft. Ihr Programm erhält ein Programm bei Standardeingabe und überprüft, ob seine Syntax korrekt ist oder nicht. Wenn es korrekt ist, geben Sie bei der Standardausgabe nur "true" aus. Wenn nicht, geben Sie bei der Standardausgabe nur "false" aus.

Ihr Programm muss jedoch in einem Fall falsch sein. Wenn ein eigener Quellcode eingegeben wird, wird bei der Standardausgabe nur "false" ausgegeben. Dies ist Code Golf, also gewinnt das kürzeste Programm!

Hinweis: Obwohl dies technisch gesehen kein Quine ist, müssen Sie die Quine-Regeln befolgen. Dies bedeutet, dass Sie nicht über das Dateisystem oder was auch immer auf Ihren Quellcode zugreifen können.

Hinweis: Sie können kein Programm beanspruchen, das aufgrund eines Syntaxfehlers nicht ausgeführt werden konnte, um diese Herausforderung zu lösen, da es ausführbar sein muss.

PyRulez
quelle
1
Ist die Verwendung von Standardbibliotheken und / oder Bibliotheken von Drittanbietern zulässig? (speziell, um einen funktionierenden Lexer / Parser für Ihre Sprache zu verwenden)
Martin Ender
Ist try:exec(raw_input())...erlaubt?
user80551
@ user80551 Das funktioniert nicht für syntaktisch korrekte Eingaben, die für immer wiederholt werden. Es ist auch ein leichtes Sicherheitsrisiko.
Martin Ender
Sollte es nicht das Quine-Tag haben?
Sylwester
1
@ m.buettner Was ist, wenn wir raw_input () in eine neue Funktion einrücken und ausführen, damit die Funktion nie aufgerufen wird? Übrigens, wen interessiert er für Sicherheitsrisiken beim Code-Golf?
user80551

Antworten:

9

Ruby 2.0, 65 76 164 Figuren

eval r="gets p;$<.pos=0;`ruby -c 2>&0`;p$?==0&&$_!='eval r=%p'%r"

Dies verwendet Rubys eingebauten Syntaxprüfer ( ruby -c), um die Syntax der Eingabe zu überprüfen, was bedeutet, dass der Code nicht ausgewertet wird.

Grundlegendes Anwendungsbeispiel:

ruby syntax.rb <<< foo
true
ruby syntax.rb <<< "'"
false
ruby syntax.rb < synxtax.rb # assumes the file was saved without trailing newline
false

Erläuterung

Diese Lösung basiert (war) auf dem Standard-Ruby-Quine:

q="q=%p;puts q%%q";puts q%q

%pist der Formatbezeichner für arg.inspect, der verglichen werden kann mit uneval: Wenn evalSie die von zurückgegebene Zeichenfolge eingeben arg.inspect, erhalten Sie (normalerweise) wieder den ursprünglichen Wert. Wenn Sie also die qZeichenfolge mit sich selbst als Argument formatieren , wird das %pInnere der Zeichenfolge durch die angegebene Zeichenfolge selbst ersetzt (dh wir erhalten so etwas wie "q=\"q=%p;puts q%%q\";puts q%q").

Die Verallgemeinerung dieser Art von Quine führt zu folgenden Ergebnissen:

prelude;q="prelude;q=%p;postlude";postlude

Dieser Ansatz hat jedoch einen großen Nachteil (zumindest beim ): Der gesamte Code muss dupliziert werden. Glücklicherweise evalkann verwendet werden, um dies zu umgehen:

eval r="some code;'eval r=%p'%r"

Was hier passiert, ist, dass der an eval übergebene Code darin gespeichert wird, r bevor er eval aufgerufen wird. Infolgedessen kann der vollständige Quellcode der evalAnweisung mit abgerufen werden 'eval r=%p'%r. Wenn wir dies im evald-Code tun und sicherstellen, dass die oberste Ebene von uns nur aus der einen evalAnweisung besteht, gibt uns dieser Ausdruck tatsächlich den vollständigen Quellcode unseres Programms, da jeder zusätzliche Code, der an übergeben evalwird, bereits darin gespeichert ist r.

Randnotiz: Mit diesem Ansatz können wir tatsächlich eine Ruby-Quine in 26 Zeichen schreiben: eval r="puts'eval r=%p'%r"

In dieser Lösung besteht der zusätzliche Code, der darin ausgeführt wird, evalaus vier Anweisungen:

gets p

Zuerst lesen wir alle Eingaben von STDIN und speichern sie implizit in $_.

$<.pos=0

Anschließend spulen wir STDIN zurück, damit die Eingabe für den im nächsten Schritt gestarteten Unterprozess wieder verfügbar ist.

`ruby -c 2>&0`

Dadurch wird Ruby in seinem integrierten Syntaxprüfmodus gestartet und der Quellcode von stdin gelesen. Wenn die Syntax des mitgelieferten Skript (Dateiname oder stdin) OK ist, druckt er Syntax OKin seine stdout (die von der Eltern - Prozess erfasst wird), aber im Falle eines Syntaxfehlers, einer Beschreibung des Fehlers auf gedruckten Stderr - die würden sichtbar sein, also leiten wir das 2>&0stattdessen in nirvana ( ) um.

p$?==0&&$_!='eval r=%p'%r

Anschließend überprüfen wir den Exit-Code des Unterprozesses $?, der 0 ist, wenn die Syntax in Ordnung war. Zuletzt wird die Eingabe, die wir zuvor gelesen haben ( $_), mit unserem eigenen Quellcode verglichen (der, wie ich zuvor beschrieben habe, mit erhalten werden kann 'eval r=%p'%r).

Bearbeiten: 14 Zeichen dank @histocrat gespeichert!

Ventero
quelle
Ich glaube, dass Ihre Antwort die einzige ist, die sich bisher wirklich an die Regeln gehalten hat.
PyRulez
1
Sehr schön! Ich glaube , Sie ersetzen .write mit <<, und >>1<1mit ==0.
Histokrat
@histocrat Huh, irgendwie hat der Teil ==in den Process::StatusDokumenten verpasst . Vielen Dank!
Ventero
6

Rebol - 69 oder 7475 voll konform mit allen Regeln

Neue Arbeitsversionen dank @rgchris! Nicht sicher, ob die erste Anforderung "Nicht auf die Quelle zugreifen" fehlschlägt, da der Interpreter den geladenen und analysierten Code enthält, der als cmd-Zeilenparameter im Systemobjekt ( system/options/do-arg) übergeben wurde, das verwendet wird, um sich selbst zu erkennen.

probe not any[error? i: try[load/all input]i = system/options/do-arg]

Dieser folgt allen Regeln:

do b:[i: input prin block? if i <> join "do b:" mold b [try [load/all i]]]

Anwendungsbeispiel:

Zuerst wird eine gültige Ganzzahl gedruckt, dann wird eine ungültige Ganzzahl gedruckt.

echo "rebol [] print 123" | rebol --do "probe not any[error? i: try[load/all input]i = system/options/do-arg]"
true
echo "rebol [] print 1w3" | rebol --do "probe not any[error? i: try[load/all input]i = system/options/do-arg]"
false
echo "probe not any[error? i: try[load/all input]i = system/options/do-arg]" | rebol --do "probe not any[error? i: try[load/all input]i = system/options/do-arg]"
false 

Vollständig konforme Version:

echo 'rebol [] 123' |r3 --do 'do b:[i: input prin block? if i <> join "do b:" mold b [try [load/all i]]
true
echo 'rebol [] 123a' |r3 --do 'do b:[i: input prin block? if i <> join "do b:" mold b [try [load/all i]]]'
false
echo 'do b:[i: input prin block? if i <> join "do b:" mold b [try [load/all i]]]' |r3 --do 'do b:[i: input prin block? if i <> join "do b:" mold b [try [load/all i]]
false

Erläuterung:

Erste Version

Dies verwendet die in Rebols integrierte loadFunktion, um den Code von stdin zu analysieren und zu laden, führt ihn jedoch nicht aus.

Der tryBlock fängt alle Syntaxfehler ab und die error?Funktion konvertiert den Fehler in einen einfachen Booleschen Wert.

Das i = system/options/do-argvergleicht die Eingabe von stdin (zugewiesen an i) mit dem Code, der an das do-argArgument übergeben wurde (hinterhältig, aber sehr golf :).

anyist eine großartige Funktion, die zurückgibt, truewenn any-thing im Block ausgewertet wird true(zum Beispiel zurückgeben any [ false false true ]würde true).

notInvertiert dann einfach den Booleschen probeWert , um die richtige Antwort zu erhalten, und zeigt den Inhalt des zurückgegebenen Werts an.

Vollständig konforme Version

Lassen Sie uns dies der Reihe nach durchgehen ...

Weisen Sie das Wort bdem folgenden Block [] zu.

Verwenden Sie die doFunktion, um den doDialekt im bBlock zu interpretieren .

Innerhalb des bBlocks ...

Stellen Sie das Wort so ein i, dass es auf den Inhalt von stdin ( input) verweist .

Jetzt setzen ifwir joinden String "do b:" auf den mold'ed-Block bund er ist nicht gleich ( <>) für die stdin-Eingabe, idann versuchen wir loaddie Eingabe i.

Wenn das Ergebnis a ist block, haben wir loaddie übergebenen Daten korrekt bearbeitet, andernfalls würden wir eine nonevon den fehlgeschlagenen erhalten if.

Verwenden Sie prindiese Option , um das Ergebnis anzuzeigen, block?dessen Wert true zurückgibt, wenn das Ergebnis ein Block ist. Wenn Sie prinim Gegensatz zu printverwenden, wird nach der Ausgabe kein Wagenrücklauf angezeigt (und es wird ein weiteres Zeichen gespeichert).

Johnk
quelle
Ich denke, Sie können das bis zu 36 Zeichen mitprint not error? try[load/all input]
draegtun
Das überprüft die Syntax ... aber das Problem sieht vor, dass es im eigenen Code false zurückgibt. Nebenbei, ungolfed ...c:[c: compose/only [c: (c)]print not error? try[if c = load/all input[1 / 0]]]
HostileFork sagt, traue SE
Ich habe das bisschen über ungültigen Code verpasst. Wie wäre es damit? (prin none? attempt[load/all input] halt) 1a Die ungültige Ganzzahl würde die
Syntaxauswertung
"Ich kann immer noch keine Möglichkeit finden, meinen eigenen Code nicht zu validieren, ohne den Code zu überprüfen und false zurückzugeben, wenn ich meinen eigenen Code sehe." Wenn Sie checksum/secureIhr Programm können und den Hash zu Vergleichszwecken in die Quelle selbst aufnehmen, möchte ich Ihre Dienste in mein Cybercrime-Syndikat aufnehmen. Wenn nicht, beginnen Sie mit meinem Code, der funktioniert. :-)
HostileFork sagt, traue SE
1
D'oh! RebMu um 49:do B[pb bl? iu a jn "do B" ml b [try [ld/all a]]]
rgchris
2

Javascript - 86 82

!function $(){b=(a=prompt())=='!'+$+'()';try{Function(a)}catch(e){b=1}alert(!b)}()

Fügen Sie zum Testen in die Javascript-Konsole Ihres Browsers ein.
Erläuterung:

// Declare a function and negate it to call it immediately
// <http://2ality.com/2012/09/javascript-quine.html>
!function $ () { 
  // Concatenating $ with strings accesses the function source
  invalid = (input = prompt()) == '!' + $ + '()';
  try {
    // Use the Function constructor to only catch syntax errors
    Function(input)
  }
  catch (e) {
    invalid = 1
  }
  alert(!invalid)
// Call function immediately
}()

Hinweis: @ m.buettner hat den Punkt angesprochen, dass das Programm truefür eine nackte return-Anweisung zurückgibt , z return 0;. Da Javascript keinen Syntaxfehler für eine unzulässige return-Anweisung auslöst, bis sie tatsächlich ausgeführt wird (was bedeutet, dass Code wie if (0) { return 0; }kein Syntaxfehler auslöst), gibt es meines Erachtens keine Möglichkeit, dieses Problem beim Schreiben eines Javascript-Parsers in Javascript zu beheben . Betrachten Sie zum Beispiel den Code:

while (1) {}
return 0;

Wenn der Code ausgeführt wird, bleibt er aufgrund der Schleife hängen. Wenn der Code nicht ausgeführt wird, wird kein Fehler für die unzulässige return-Anweisung ausgegeben. Daher ist dies so gut wie Javascript für diese Herausforderung bekommen kann. Sie können Javascript jederzeit disqualifizieren, wenn Sie der Meinung sind, dass dies die Herausforderung nicht ausreichend erfüllt.

Abraham
quelle
2
Jetzt wird beim Geben kein Syntaxfehler gemeldet return 0.
Martin Ender
Mm, guter @ m.buettner
Abraham
2

Haskell - 222 Bytes

Beachten Sie, dass hierfür ein echter Parser verwendet wird. Es hängt nicht von evalähnlichen Funktionen dynamischer Sprachen ab.

import Language.Haskell.Parser
main=interact(\s->case parseModule s of ParseOk _->if take 89s=="import Language.Haskell.Parser\nmain=interact(\\s->case parseModule s of ParseOk _->if take"then"False"else"True";_->"False")

Diese Lösung ist nicht besonders hübsch, funktioniert aber.

Gxtaillon
quelle
Scheitert es für sich selbst?
PyRulez
Es tut. Die if take ...Anweisung prüft, ob die Eingabe mit einem Zeichenfolgenliteral übereinstimmt, das der erste Teil des Programms ist.
Gxtaillon
2

Ich denke, das folgt den Regeln:

JS (✖╭╮✖)

function f(s){if(s==f.toString())return false;try{eval(s)}catch(e){return false}return true}

Der Code wird ausgewertet, wenn er korrekt ist.

Schauen Sie sich die Pfeilnotation an, um zu sehen, ob sie nicht mehr gekürzt werden kann.

!function f(){try{s=prompt();return"!"+f+"()"!=s?eval(s):1}catch(e){return 0}}()

Nach ein paar fehlgeschlagenen Versuchen und Zurücksetzen - neue Version!

!function f(){try{s=prompt();"!"+f+"()"!=s?eval(s):o}catch(e){return 1}}()

Und ich bin zurück!

!function f(){try{s=prompt();"!"+f+"()"!=s?eval(s):o}catch(e){return !(e instanceof SyntaxError)}}()

Und ich bin weg! Leider funktioniert dieser Ansatz aufgrund der Art der Bewertung und dank @scragar (verdammt noch mal @scragar!) Nicht (da throw new SyntaxErrores sich um einen gültigen JS-Code handelt, der diese Methode aktiviert ) - als solches würde ich sagen, dass es unmöglich ist, einen zu erstellen Syntaxprüfer (zumindest unter Verwendung von eval oder einer Variation davon)

(* siehe Kommentare!)

eithed
quelle
Angenommen, die Eingabe ist eine Endlosschleife? Ich schlage vor, Sie verwendeneval("x=function(){"+t+"}");
DankMemes
1
@ZoveGames Das kann mit Eingaben wie }//oder gebrochen werden };{.
Ventero
Ich weiß nicht, ob dies gültig ist oder nicht gemäß den Regeln, da es ein Programm sein muss, keine Funktion (glaube ich)
Abraham
@ZoveGames Guter Punkt! Während die Skriptbehandlung des Browsers aktiviert werden sollte (Schleifenzähler / Zeitüberschreitung), ist es immer noch einfach, ein Skript zu schreiben, das dazu führt, dass das "System" hängen bleibt. Ich werde mit der Änderung warten, bis OP die Regel dazu festlegt.
eithed
1
@eithedog Sorry, wurde über Sprachen verwirrt, Javascripts Base Throwable heißt eigentlich Errornicht Exception. throw new Error('')verursacht das falsche Verhalten.
Scragar
1

Python (95)

c=raw_input()
try:compile('"'if sum(map(ord,c))==7860 else c,'n','exec');print 1
except:print 0
ɐɔıʇǝɥʇuʎs
quelle
Funktioniert das nicht nur für eine Eingabezeile?
Ian D. Scott
2
Funktioniert nicht: c=u'#\u1e91'weilord('#') + ord(u'\u1e91') == 7860
ThinkChaos
Versuchen Sie stattdessen einen Hash.
PyRulez
1

PHP - 140

<?exec("echo ".escapeshellarg($argv[1])." | php -l",$A,$o);echo$o|(array_sum(array_map(ord,str_split($argv[1])))==77*150)?"false":"true";//Q

Kommentar erforderlich, um den 'Hash' zu behalten (eine schamlose Kopie von s, ɐɔıʇǝɥʇuʎs). Verwenden Sie php -l / lint, um nach Fehlern zu suchen.

$ php finky_syntax_check.php '<?php echo "good php code"; ?>' 
true
$ php finky_syntax_check.php '<?php echo bad--php.code.; ?>'
false
$ php finky_syntax_check.php '<?exec("echo ".escapeshellarg($argv[1])." | php -l",$A,$o);echo$o|(array_sum(array_map(ord,str_split($argv[1])))==77*150)?"false":"true";//Q'
false
$ php finky_syntax_check.php '<?exec("echo ".escapeshellarg($argv[1])." | php -l",$A,$o);echo$o|(array_sum(array_map(ord,str_split($argv[1])))==77*150)?"false":"true";//D'
true // note that the last character was changed
Aurel Bílý
quelle
0

C 174

Erläuterung - Die Wand muss einen Systemfehler erzeugen, während sie noch kompilierbar ist. Der Syntaxfehler lautet no. return 0;Um nach dem Einfügen über stdin in die Windows-Konsole einzugeben, geben Sie Strg-Z ein und drücken Sie die Eingabetaste.

Golf gespielt

char c[256];int i;int main(){FILE *f=fopen("a.c","w");while(fgets(c,256,stdin)!=NULL){fputs(c,f);}fclose(f);i=system("gcc a.c -o -Wall a.exe");printf("%s",i?"false":"true");}

Ungolfed:

#include <stdio.h>
#include <stdlib.h>
char c[256];int i;
int main()
{
FILE *f=fopen("a.c","w");
while(fgets(c,256,stdin)!=NULL)
{
fputs(c,f);
}
fclose(f);
i=system("gcc a.c -o -Wall a.exe");
printf("%s",i?"false":"true");
}
Bacchusbeale
quelle
0

T-SQL - 110

Ziemlich einfach, ich wollte hier schon eine Weile eine Herausforderung ausprobieren und bin endlich dazu gekommen. Dies ist nicht der schickste Code, aber ich hatte trotzdem Spaß.

Die "Golf" -Version.

BEGIN TRY DECLARE @ VARCHAR(MAX)='SET NOEXEC ON'+'//CODE GOES HERE//'EXEC(@)PRINT'TRUE'END TRY BEGIN CATCH PRINT'FALSE'END CATCH

Eine besser formatierte Version.

BEGIN TRY 
    DECLARE @SQL VARCHAR(MAX)='SET NOEXEC ON'+'//CODE GOES HERE//'
    EXEC(@SQL)
    PRINT'TRUE'
END TRY 

BEGIN CATCH 
    PRINT'FALSE'
END CATCH

Es ist ziemlich selbsterklärend und verwendet SET NOEXEC, wodurch die Abfrage nur analysiert wird, anstatt Ergebnisse zurückzugeben. Der Rest ist meistens der Versuch / Fang, mit dem ich feststelle, was ich drucken muss.

EDIT: Ich hätte hinzufügen sollen, dass dies technisch für sich selbst scheitern wird. Da dynamisches SQL verwendet wird, müssen alle einfachen Anführungszeichen in der Eingabe verdoppelt werden. '->' '

PenutReaper
quelle