Überprüfen Sie das Brainfuck-Programm


17

Noch ein Brainfuck-Parsing-Problem, aber diesmal ... anders.

Sie arbeiten in der Firma Infinite Monkeys Incorporated, die Brainfuck-Programme herstellt, um verschiedene interessante Probleme zu lösen (nicht weniger aus Versehen - schließlich erstellt die Firma zufällige Programme). Es scheint jedoch, dass Ihre schnellen Turing-Maschinen, die nur Brainfuck ausführen, ein kleines und teures Problem mit Syntaxfehlern haben - machen Sie eins, und der Computer explodiert. Es ist wahrscheinlich ein Designfehler, aber niemand hatte sich die Mühe gemacht, herauszufinden, warum es passiert.

Da Turing-Maschinen (besonders schnelle) teuer sind (schließlich haben sie unendlich viel RAM, was Kosten verursacht), ist es besser, sicherzustellen, dass das Programm keine Syntaxfehler aufweist, bevor Sie den Code ausführen. In Ihrem Unternehmen wird viel Code ausgeführt, sodass die manuelle Überprüfung nicht funktioniert. Schreiben Sie ein Programm, das den STDIN for Brainfuck-Code liest und mit einem anderen Exit-Status als 0 (Fehler) beendet, wenn das Programm einen Syntaxfehler aufweist (z. B. ]ein Syntaxfehler, da keine Übereinstimmung vorliegt [). Beenden Sie mit dem auf 0 gesetzten Beendigungsstatus, wenn das Programm vollständig in Ordnung ist.

Vergewissern Sie sich, dass Ihr Programm die Fehler korrekt erkennt []. Sie möchten doch nicht, dass ein anderer Computer explodiert, oder? Oh, und stellen Sie sicher, dass es so kurz wie möglich ist - Ihr Chef bezahlt für kurze Programme (weil er denkt, dass sie schnell sind oder so). Oh, und Sie müssen keinen Code in Brainfuck eingeben (das können Sie auch nicht, da Brainfuck keine Exit-Codes unterstützt) - Ihr Code wird auf einem normalen Computer ausgeführt.

Wie Sie sehen, müssen Sie überprüfen, ob das Brainfuck-Programm "gültig" ist (mit []Symbolen gepaart ). Beachten Sie, dass Brainfuck-Programme andere Zeichen als []enthalten können. Verweigern Sie das Programm daher nicht, nur weil es andere Befehle enthält. Kleinster Code gewinnt, aber wahrscheinlich interessieren Sie sich sowieso mehr für Upvotes.


1
Was ist mit Sprachen, bei denen kein Prozess-Exit-Code festgelegt werden kann?
Kendall Frey

1
@KendallFrey: Einfach, benutze etwas anderes. Oder binden Sie in GolfScript Ruby-Code ein. Vielleicht blockiert dies einige esoterische Programmiersprachen, aber gut ...
Konrad Borowski

1
Ist es in Ordnung, den Fehlercode bei einem Fehler auf einen anderen Wert als 1 zu setzen (sofern dies natürlich nicht 0 ist)?
Marinus

@marinus: Ich weiß nicht warum du das willst, aber ich denke es ist in Ordnung.
Konrad Borowski

@GlitchMr: da kann ich dann GCD(a,b)statt verwenden 0 != a || b.
Marinus

Antworten:


6

GolfScript, 18 Zeichen

.{[]`?)},~](`91?./

Dieser Code wird erfolgreich mit dem Exit-Code 0 ausgeführt (und gibt einen Teil des Mülls nach stdout aus), wenn die eckigen Klammern in der Eingabe ausgeglichen sind. Wenn dies nicht der Fall ist, schlägt der Vorgang mit einem Exit-Code ungleich Null fehl und es wird eine Fehlermeldung an stderr ausgegeben, z.

(eval):2:in `/': divided by 0 (ZeroDivisionError)

oder

(eval):1:in `initialize': undefined method `ginspect' for nil:NilClass (NoMethodError)

Da die Herausforderung nichts über die Ausgabe an stdout / stderr aussagte, schätze ich, dass dies qualifiziert. In jedem Fall können Sie diese jederzeit an umleiten /dev/null.

Erläuterung:

Der Code entfernt {[]`?)},alles außer eckigen Klammern von der Eingabe und ~wertet das Ergebnis als GolfScript-Code aus. Der schwierige Teil ist, dass unausgeglichene Klammern in GolfScript vollkommen legal sind (und in der Tat enthält mein Code eine!), Also brauchen wir eine andere Möglichkeit, um den Code zum Absturz zu bringen.

Der Trick, den ich verwende, besteht darin, eine Kopie der Eingabe am unteren Rand des Stapels zu belassen, den gesamten Stapel in einem Array zusammenzufassen (unter Verwendung des Unsymmetrischen ]) und das erste Element auszuschalten. An diesem Punkt können drei Dinge passieren:

  • Wenn die Eingabe nicht geschlossen wurde [und versucht wird, ein Element aus einem leeren Array herauszuschieben, stürzt der Interpreter ab (was in diesem Fall genau das ist, was wir wollen!)
  • Wenn die Klammern in der Eingabe ausgeglichen waren, ist das verschobene Element die ursprüngliche Eingabezeichenfolge.
  • Andernfalls (wenn der Eingang ungeöffnet ]oder nicht geschlossen war [) handelt es sich um ein Array.

Mein ursprünglicher Eintrag mit 14 Zeichen verglich dann den verschobenen Wert mit einer Zeichenfolge, die abstürzen würde, wenn es sich um ein verschachteltes Array handeln würde. Leider hat sich herausgestellt, dass das Vergleichen eines flachen (oder insbesondere leeren) Arrays mit einer Zeichenfolge auch in GolfScript zulässig ist, sodass ich den Kurs ändern musste.

Stattdessen verwendet meine aktuelle Übermittlung eine sehr brachiale Methode, um Arrays von Strings zu unterscheiden: Sie entfernt sie und versucht, das erste Vorkommen von [(ASCII-Code 91) zu finden, das genau dann null ist, wenn das nicht ausgewertete nicht vorhanden ist Variable war ein Array. Wenn dies der Fall ist, löst das Teilen der Null mit sich selbst den gewünschten Absturz aus.

Ps. Zwei weitere 18-Zeichen-Lösungen sind:

.{[]`?)},{.}%~](n<

und

.{[]`?)},~]([n]+n<

Leider habe ich noch keinen kürzeren Weg gefunden, um das "Problem mit leeren Arrays" zu lösen.


ist das ausgeglichen ?: ][(dh scheitert es in Ihrem Programm?)
Justin

@ Quincunx: Es schlägt fehl, wie es sollte.
Ilmari Karonen

Es stellte sich jedoch heraus, dass es akzeptierte [[]; Ich habe es jetzt behoben, zum Preis von 4 Zeichen, und es besteht jetzt alle meine Tests.
Ilmari Karonen

Wenn ich Sie richtig verstehe, hatten Sie eine 14-Zeichen-Lösung, die nur dann zwischen einer Zeichenfolge und einem Array unterscheidet, wenn das Array leer ist. 1+verwandelt ein leeres Array in ein nicht leeres Array, ein nicht leeres Array in ein nicht leeres Array und eine Zeichenfolge in eine Zeichenfolge.
Peter Taylor

@ PeterTaylor: Ja, das war es .{[]`?)},~](n<. Ich habe es mit deinem versucht 1+, aber es scheint, dass das Array etwas anderes als eine Zahl enthalten muss (vermutlich, damit der Interpreter abstürzt, wenn er versucht, ein Zeichen rekursiv mit einem Array / einer Zeichenfolge zu vergleichen). Das Verwenden von n+funktioniert auch nicht, da es das Array zu einer Zeichenfolge zwingt. [n]+ funktioniert , bringt mich aber immer noch auf 18 Zeichen.
Ilmari Karonen

17

Brainfuck 76 Bytes

>>+[<+++++++++[->---------<]+>-[--[[-]<->]<[<[->-]>[<+]<]>]<[-<+>]+>,]<<[<+]

Dies geht verloren, wenn eckige Klammern unsymmetrisch sind und der bf-Interpreter / -Compiler ausfällt. Einige von ihnen haben Exit-Codes, die dies widerspiegeln.

erfordert eof = 0, umschließende Werte und endliche Anzahl von Zellen

In Ubuntu können Sie den Interpreter bf( sudo apt-get install bf) verwenden

% echo '[[[]' | bf -n bf_matching.bf
Error: Out of range! Youwanted to '<' below the first cell.
To solve, add some '>'s at the beginning, for example.
an error occured
% echo $? 
5
% bf -n bf_matching.bf < bf_matching.bf
% echo $?
0

5
Mir gefällt, wie du Brainfuck benutzt hast, obwohl die Frage besagt, dass das unmöglich war.
Riking

Oh wow. Ich bin ehrlich überrascht. Ich nahm an, dass es unmöglich war, aber es ist nicht möglich.
Konrad Borowski

1
@ Xfix: Brainfuck ist komplett, so dass es alles tun kann (angesichts der I / O-Einschränkungen.)
Marinus

2
@marinus Vollständigkeit bedeutet nur, dass alle Berechnungen durchgeführt werden können. BrainfuckTuring ist ohne E / A abgeschlossen, da Sie ein Programm ausführen können, das alle Berechnungen berechnet und das Ergebnis anzeigt, indem Sie den Arbeitsspeicher nach dem Ausführen überprüfen. BF ohne I / O würde das Interesse der Leute verringern, da es schwierig wäre, Versorgungsunternehmen zu bauen. ZB hätte ich meinen Lisp-Dolmetscher nie machen können .
Sylwester

14

Befunge 98 - 26 31 20 19 Zeichen

~:']-!\'[-!-+:0`j#q

Wurde einige massive Bedingungen los. Jetzt arbeitet das Programm wie folgt:

~:   read an input char and duplicate it

']-! push a 1 if the char is the ] char, 0 otherwise

\    swap the comparison value for the duplicated input char

'[-! push a 1 if the char is the [ char, 0 otherwise

-    subtract the two comparison values. If the second one is 1, the first is 0, 
     so the result is -1. Else if the second one is 0, the first is 1 and the result is
     1. Else, the first and the second are both 0 and the result is 0

+    Add the number to the counter (which is 0 if there is none already)

:0`  test if the counter is positive (that'd mean an invalid program). Pushes a 1 if 
     positive, 0 otherwise.

j#q  if the counter is positive, then this jumps to the q. Otherwise, it skips the q 
     and continues to the ~ at the beginning of the line. If there are no more chars in
     the input, then the IP will be sent back to the q. 

qBeendet das Programm und zeigt den obersten Wert als Fehlerwert an. Der Fehlerwert ist -1 1, wenn zu viele vorhanden sind ], 0, wenn sie ausgeglichen sind, und positiv negativ, wenn zu viele vorhanden sind [. Wenn die Zahl positiv oder negativ ist, werden so viele Absolutwerte dieser Zahl ]benötigt, um das Programm auszugleichen.

Bearbeiten: Inkrementieren und Dekrementieren umgeschaltet. [dient zum Inkrementieren des Zählers und ]zum Dekrementieren des Zählers . Durch Umschalten spare ich 1 Zeichen, da ich für die Ausgangsbedingung nur prüfen muss, ob der Zähler positiv und nicht negativ ist.


Alte Version

~:'[-!j;\1+\#;']-!j;1-#;:0\`j#q

Dieser Code funktioniert wie folgt:

~    read one char of input
:    duplicate it
'[-! push 1 if the character is [, 0 otherwise
j    jump that number of characters
;    skip until next ;
\1+\ increment counter

similarily for ].

#q when end of input is reached, ~ reflects the IP back. q ends the program with the error value on the stack.

Edit: erkannte, dass diese akzeptierten Eingaben wie ][, jetzt endet es, wenn die Zählung negativ wird, mit

:0\`j


@JoKing das ist ziemlich nett, den Abstand zwischen [und ]zu nutzen, um den Vergleich mit beiden zu machen.
Justin

6

J ( 38 35)

exit({:+.<./)+/\+/1 _1*'[]'=/1!:1[3

Erläuterung:

  • 1!:1[3: lese stdin
  • '[]'=/: Erstellt eine Matrix, in der die erste Zeile eine Bitmaske des [s in der Eingabe und die zweite Zeile das ]s ist.
  • 1 _1*: multipliziere die erste mit 1 und die zweite mit -1.
  • +/: Summiere die Spalten der Matrix und erhalte Delta-Einrückung pro Zeichen
  • +/\: Erstelle eine laufende Summe von diesen und gib jedem Charakter die Einrückungsstufe
  • ({:+.<./): Gibt die GCD des letzten Elements ( {:) und des kleinsten Elements ( <./) zurück. Wenn alle Klammern übereinstimmen, sollten beide übereinstimmen, 0damit dies zurückkehrt 0. Wenn die Klammern nicht übereinstimmen, wird ein Wert ungleich Null zurückgegeben.
  • exit: Stellen Sie den Ausgangswert auf diesen Wert ein und beenden Sie den Vorgang.

Schöne Panne ...
Chris Cashwell

6

Rubin (64)

exit $<.read.tr('^[]','').tap{|x|0while x.gsub!('[]','')}.empty?

vorher (68) war es:

exit ARGF.read.tr('^[]','').tap{|x| 0 while x.gsub!('[]','')}.empty?

Eine andere äquivalente Lösung verwendet

exit $<.read.tr('^[]','').tap{|x|0while x.gsub!('[]','')}.size>0

Kann nicht sizealleine verwendet werden, da dies zu falschen Negativen (!!!) führen würde, wenn die Gesamtzahl der unsymmetrischen Klammern ein Vielfaches von 256 ist


Das ist Codegolf. Ich bin sicher, Sie können hier einige Leerzeichen entfernen. Ruby ist etwas whitespace-sensitiv, ignoriert es aber in vielen Fällen. Zunächst benötigen Sie kein Leerzeichen in der Nähe des =Operators.
Konrad Borowski

bessere Version (etwas inspiriert von der sed + tr-Lösung). Ich bin mir nicht sicher, ob ich noch viel besser werden kann. Zumindest hat es nur 4 Leerzeichen!
umgeschrieben

1
Und doch kann ich zwei davon entfernen.
Konrad Borowski

2
Ich denke die Räume um die 0Dose gehen.
Marinus

toller Weltraumtrick, danke!
umgeschrieben

5

Perl, 30 Zeichen

Ihr grundlegender rekursiver Perl-Regex zur Rettung:

perl -0ne 'exit!/^(([^][]|\[(?1)\])*)$/'

Für diejenigen, die mit den hier verwendeten Befehlszeilenargumenten nicht vertraut sind: -0Ermöglicht das Festlegen des Zeilenendezeichens für die Zwecke der Dateieingabe; Wird -0kein Argument verwendet, wird das Zeilenendezeichen auf EOF gesetzt. -nLiest die Eingabe (in diesem Fall die gesamte Datei) automatisch $_vorher ein.

Wenn der reguläre Ausdruck übereinstimmt, wird ein wahrer Wert zurückgegeben, der für den Exit-Code auf 0 negiert wird. Andernfalls ergibt der falsche Rückgabewert einen Exit-Code von 1.


Ich schätze, ich muss meine Antwort besser Golf spielen, um diese 30-Zeichen-Lösung zu schlagen.
Justin

Dort. Meine Lösung ist jetzt viel kürzer als vorher. Gute Lösung. +1
Justin

4

bash (tr + sed) - 42

[ -z `tr -Cd []|sed ":a;s/\[\]//g;t a"` ]

Wenn Ihnen Fehlermeldungen nichts ausmachen, können Sie das letzte Leerzeichen zwischen `und entfernen ], um Länge 41 zu erhalten.


Sofern ich nichts vermisse, haben Sie nutzlosen Gebrauch von catund $()( "[]"kann auch als geschrieben werden []). Ich habe diese Antwort akzeptiert, aber bis ich Verbesserungen in der Länge sehe, werde ich das nicht befürworten, da es zwar kurz ist, aber für die Bash viel kürzer sein könnte.
Konrad Borowski

Nun, eigentlich kenne ich mich mit Shell-Skripten nicht so gut aus. Ich bin nicht in der Lage, die meiste Arbeit daraus zu machen. Ich habe durch $()Backticks ersetzt und das gemacht "[]"-> []du hast vorgeschlagen.
Shiona


1
Ich hätte es mit einem Schwert versuchen können, aber ich habe mich geirrt.
Shiona

3

Perl (56 Zeichen)

$/=0;$r=qr/[^][]*(\[(??{$r})\])*[^][]*/;<>=~m/^$r$/||die

Die naheliegende Perl-Lösung: ein rekursiver regulärer Ausdruck. Leider ist es ein ziemlich ausführliches Konstrukt.


3

Haskell (143)

import System.Exit
f=exitFailure
v c []|c==0=exitSuccess|True=f
v c (s:t)|c<0=f|s=='['=v(c+1)t|s==']'=v(c-1)t|True=v c t
main=getContents>>=v 0

zu jgon: Die Verwendung von 2 Wachen scheint dichter zu sein als wenn-dann-sonst. Ich glaube auch nicht, dass deine prüft, ob die Klammern in der richtigen Reihenfolge sind ("] [" passt)


oh wow, habe diesen Kommentar erst gesehen, als es heute darauf hingewiesen wurde. Mein Code wurde korrigiert, aber die Wachen scheinen dichter zu sein (+1).
Jgon

3

C, 73 64 Zeichen

Dank Vorschlägen von breadbox (obwohl dies wahrscheinlich Little-Endian erfordert, um zu arbeiten):

i;main(c){while(read(0,&c,1)*(i+1))i+=(c==91)-(c==93);return i;}

Wie es funktioniert:

  • implicit int global iwird auf 0 initialisiert
  • cwird zu einem impliziten int, das wird argc(initialisiert auf 1, aber es ist uns egal, solange die höheren Bits nicht gesetzt sind)
  • read(0,&c,1)Liest ein einzelnes Zeichen in das niedrige Byte von c (bei Little-Endian-Architekturen) und gibt bei EOF 0 zurück. i+1 != 0es sei denn, das ausgeglichene Klammer-Zitat geht auf -1; Das Multiplizieren funktioniert als (sicherer) Boolescher Wert UND das kostet ein Zeichen weniger als&&
  • c==91ergibt 1 für '['und c==93ergibt 1 für ']'. (Möglicherweise gibt es einen kleinen Trick, aber mir fällt nichts ein.)
  • return iWird mit dem Statuscode 0 beendet, wenn er ausgeglichen ist, und mit einem Wert ungleich Null, wenn dies nicht der Fall ist. Das Zurückgeben von -1 verstößt technisch gegen POSIX, aber das interessiert eigentlich niemanden.

Vorherige Version:

main(i){char c;i=0;while(read(0,&c,1)*(i+1))i+=(c==91)-(c==93);return i;}

Wenn Sie getchar()anstelle von read verwenden, wird der Code gekürzt und Sie können (implizit) intanstelle von charfür Ihre Variable verwenden. Denken Sie auch daran, dass Globals automatisch auf Null initialisiert werden.
Brotkasten

Danke, ich habe getchar () vergessen. Ich bin mir jedoch nicht sicher, wie das globale Init hilft - das Definieren eines globalen Int. I benötigt mehr Zeichen als das Verwenden des impliziten Argc.
Flauschige

1
Globale können auch implizit sein. Außerhalb einer Funktion c;definiert ein globales int.
Brotkasten

In der Zwischenzeit macht getchar (c) es nicht kürzer, zumindest unter Verwendung dieses Ansatzes, da es auf irgendeine Weise auf> = 0 getestet werden muss und ein implizites int für c, das an read () übergeben wird, nicht garantiert wird Arbeit wegen Endianness.
Flauschige

Was ist ][? Ich bin sicher, es ist nicht ausgeglichen. Müssen Sie nicht mindestens einmal nachverfolgen, ob es negativ wird?
vsz

2

Lua, 56

os.exit(("["..io.read"*a".."]"):match"^%b[]$"and 0 or 1)

"^%b[]$"Was ist das? Können Sie erklären? Das ist doch kein Regex?
Cruncher

@ Cruncher: Ist es nicht. Es ist das Lua-Muster, nicht Regex (Lua-Muster ähneln Regexen, sind es aber nicht). In diesem Fall stimmt es mit dem Anfang von string ( ^), der ausgeglichenen Menge von [und ]mit irgendetwas dazwischen ( %b[]) und dem Ende von string ( $) überein .
Konrad Borowski

1

GTB , 55

0→O:0→X[`I@I="[":X+1→X@I="]":X-1→X@X<0:1→O@!!Ig;e]l;e~O

Vermisst []

Verwenden Sie, 0um anzuhalten.


1

MATHEMATICA, 88 Zeichen

s = "[ [ my crazy code ] [ don't explode please! [] [ :)Ahh) ]  [] []]]";

r=StringReplace;
StringLength@FixedPoint[r[#,"[]"-> ""]&,r[s,Except@Characters["[]"]-> ""]]

Mit der Funktion s name like RegularExpression StringLengthkann ich mit Mathematica niemals Text Code Golf Kontext gewinnen! :)
Murta

Ich weiß, was du meinst :) ToCharacterCodeist viel länger als ordauch ... PS: Was ist mit einem Exit-Code?
Ajasja

Length[StringCases[s,"["|"]"]//.{x___,"[","]",y___}:>{x,y}]
Alephalpha

1

Rubin, 59 58

Sucht nach öffnender und schließender Klammer, zählt [als 1 und ]als -1 und wird beendet, wenn die Anzahl unter 0 fällt.

b=0
$<.read.scan(/\]|\[/){exit 1if(b+=92-$&.ord)<0}
exit b

1
Upvoted und um ein Zeichen gekürzt (ich habe das Leerzeichen danach entfernt, exit 1falls Sie danach fragen).
Konrad Borowski

1

Hassium , 104 Bytes

func main(){l=0;r=0;b=input();foreach (c in b){if(c=="[")l++;if(c=="]")r++;}if(!(r==l))exit(1);exit(0);}

Voll ausgebaut (Anmerkung im Online - Interpreter funktioniert nicht als Eingang () deaktiviert ist) hier


1

Turing Machine Code, 286 276 Bytes

Auch hier verwende ich die hier definierte Regeltabellensyntax.

0 * * l 1
1 _ ! r Q
5 _ _ r 5
5 * * * W
W [ ! l E
W ] ! l T
W _ _ l I
W * ! r *
E ! ! l *
E * * * R
R _ [ r O
R * * l *
T ! ! l *
T * * * Y
Y _ _ r U
Y * * l *
U [ _ r O
U ! ! * halt-err
I ! ! l *
I _ _ r halt
I * * l halt-err
O ! ! r Q
O _ _ l I
O * * r *
Q ! ! r *
Q * * * W

Beendet in state halt, um die Eingabe zu akzeptieren und halt-errabzulehnen.


halt-errkann kürzer sein, wie halt*zum Beispiel.
Erik der Outgolfer

1

Pyth, 25 Bytes

Ilzv::z"[^[\]]"k"]\[""],[

Probieren Sie es online!

Python 3 Übersetzung:
import re
z=input()
if len(z):
 print(eval(re.sub("]\[","],[",re.sub("[^[\]]","",z))))

1

Haskell ( 167 , 159)

Habe das hauptsächlich zum Spaß gemacht, wenn jemand Vorschläge hat, wie man es kürzer macht, würde ich mich freuen, wenn ich sie höre :)

import System.Exit
p x y b|b=x|True=y
main=getContents>>=(return.all (>=0).scanl (\v->p (v-1) (v+1).(==']')) 0.filter (`elem`"[]"))>>=p exitSuccess exitFailure

Bearbeiten: Es wurde ein Problem behoben, auf das ich in den Kommentaren hingewiesen wurde (11 Byte hinzugefügt).

Bearbeiten 2: Zusatzfunktion zum Testen von Prädikaten mit von user13350 inspirierten Guards erstellt, wobei 8 Bytes entfernt wurden.



@ user202729 Das ist ein hervorragender Punkt, der super unvorsichtig war. Ich bin mir ziemlich sicher, dass es jetzt behoben ist.
Jgon

1

Stax , 14 11 Zeichen

╬Äτ↔EªÉs «Ü

Führen Sie es aus und debuggen Sie es

Gutschrift auf @recursive für -3 Bytes.

ASCII-Äquivalent:

.[]Y|&{yz|egp!

Entfernen Sie alle Zeichen außer []und dann, []bis sich die Zeichenfolge nicht mehr ändert. Rückgabe, 1wenn die letzte Zeichenfolge leer ist.


1
Nett. Mit können Sie .[]|&die Zeichen filtern und dann das Literal für 11
rekursiv am
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.