洗練された構文チェッカーを作成する


8

同じ言語のプログラムの構文をチェックできるプログラムを作成します。たとえば、Pythonで実行すると、Python構文がチェックされます。プログラムは標準入力でプログラムを受け取り、その構文が正しいかどうかを確認します。正しければ、標準出力に「true」だけを出力します。そうでない場合は、標準出力に「false」のみを出力します。

ただし、プログラムは1つのインスタンスで正しくない必要があります。独自のソースコードを入力した場合、標準出力に「false」が出力されます。これはコードゴルフなので、最短のプログラムが勝ちます!

注:これは厳密にはクインではありませんが、クインのルールに従う必要があります。つまり、ファイルシステムなどからソースコードにアクセスすることはできません。

注:構文エラーのために実行できなかったプログラムは、実行可能である必要があるため、この課題を解決することはできません。


1
標準および/またはサードパーティのライブラリを使用できますか?(具体的には、使用中の言語で動作するレクサー/パーサーを使用するため)
Martin Ender

されてtry:exec(raw_input())...許可されていますか?
user80551 2014

@ user80551永遠にループする構文的に正しい入力では機能しません。また、セキュリティ上のわずかなリスクもあります。
マーティンエンダー2014

それはクインのタグを持っているべきではないのですか?
Sylwester 2014

1
@ m.buettner raw_input()を新しい関数にインデントして実行し、関数が実際に呼び出されないようにするとどうなるでしょうか。ところで彼は一体誰がコードゴルフのセキュリティリスクについて気にしていますか?
user80551 2014

回答:


9

Ruby 2.0、65 76 164 キャラクター

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

これは、Rubyの組み込み構文チェッカー(ruby -c)を使用して入力の構文をチェックします。つまり、コードは評価されません。

基本的な使用例:

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

説明

このソリューションは、(以前は)標準のRuby quineに基づいていました。

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

%p書式指定子のためであるarg.inspectと比較することができる、unevalとき:evalによって返された文字列をINGのarg.inspect、あなたは(通常は)再び元の値を取得しますが。したがって、qそれ自体を引数として使用して文字列をフォーマットすると、文字列の%p内部は引用符で囲まれた文字列自体に置き換えられます(つまり、のようなものになります"q=\"q=%p;puts q%%q\";puts q%q")。

このタイプのクインを一般化すると、次のような結果になります。

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

ただし、このアプローチには大きな欠点が1つあります(少なくともでは):すべてのコードを複製する必要があります。幸いにも、evalこれを回避するために使用できます。

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

ここで何が起こるかは、evalに渡されたコードが呼び出されるr 前に 内部保存さevalれることです。その結果、evalステートメントの完全なソースコードをで取得できます'eval r=%p'%revaldコード内でこれを行い、最上位レベルが1つのevalステートメントのみで構成されていることを確認すると、渡された追加のコードevalはすでに内に格納されているため、その式は実際にプログラムの完全なソースコードを提供しますr

補足:このアプローチでは、実際にルビークインを26文字で書くことができます。 eval r="puts'eval r=%p'%r"

ここで、このソリューションでは、内部で実行される追加のコードevalは4つのステートメントで構成されています。

gets p

まず、STDINからすべての入力を読み取り、暗黙的にに保存し$_ます。

$<.pos=0

次に、STDINを巻き戻して、次のステップで開始するサブプロセスで入力を再び使用できるようにします。

`ruby -c 2>&0`

これにより、Rubyは組み込みの構文チェックモードで起動し、stdinからソースコードを読み取ります。供給されたスクリプト(ファイル名またはSTDIN)のシンタックスがOKであれば、印刷Syntax OK(親プロセスによって取得される)、そのstdoutにするが、構文エラーの場合、エラーの記載を印刷さstderrの -う見えるようにするため、2>&0代わりにnirvana()にリダイレクトします。

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

その後、サブプロセスの終了コードを確認$?します。構文に問題がなければ0になります。最後に、先ほど読んだ入力($_)を独自のソースコード(前に説明したように、で取得できる)と比較します'eval r=%p'%r

編集:@histocratのおかげで14文字が節約されました!


私は、あなたの答えが、これまで本当にルールに従っている唯一のものであると信じています。
PyRulez 14

1
非常に素晴らしい!私はあなたが交換することができると思う.write <<、と>>1<1==0
ヒストクラート2014

はぁ@histocrat、何とかに関する部分逃した==Process::Statusドキュメントを。どうもありがとう!
Ventero、2014

6

Rebol-69または7475 すべてのルールに完全に準拠

@rgchrisのおかげで新しい作業バージョン!インタープリターがロードおよび解析されたコードを保持しているため、最初のコードが「ソースにアクセスしない」要件に失敗したかどうかは不明です。コードは、システムオブジェクト(system/options/do-arg)のcmd行パラメーターとして渡され、それ自体を認識します。

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

これはすべてのルールに従います。

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

使用例:

最初に有効な整数を出力し、2番目に無効な整数を出力します。

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 

完全準拠バージョン:

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

説明:

最初のバージョン

これは、Rebols組み込みload関数を使用してstdinからコードを解析およびロードしますが、実行はしません。

tryブロックは、構文エラーをキャッチし、error?機能がシンプルなブール値にエラーを変換します。

i = system/options/do-arg、stdinからの入力(に割り当てられているi)をdo-arg引数に渡されたコードと比較します(こっそりとはいえ、ゴルフ:)

anyブロック内の-thingが(たとえば、を返す)と評価されたtrue場合に返される優れた関数です。anytrueany [ false false true ]true

not次に、ブール値を反転して正しい答えをprobe返し、戻り値の内容を表示します。

完全準拠バージョン

これを順番に見ていきましょう...

b次のブロック[]に単語を割り当てます。

do関数を使用doして、bブロック内の方言を解釈します。

内部bブロック...

istdin(input)の内容を参照するように単語を設定します。

今、if私たちは、join文字列が「Bの操作を行います。」にmold「EDブロックbと、それは同じではありません(<>)STDIN入力にiし、我々がしようとload入力i

結果があればblock、我々は持っているload「正しくそう私たちが受け取ることになる渡されたデータを編none失敗したからif

結果がブロックの場合にtrueを返すprin結果を表示するために使用しますblock?prinとは対照的にを使用するとprint、出力後にキャリッジリターンが表示されません(また、別の文字が節約されます)。


私はあなたがそれで36文字までそれを剃ることができると思いますprint not error? try[load/all input]
draegtun '

それは構文をチェックします...しかし問題はそれがそれ自身のコードで偽を返すことを規定しています。オフハンド、ゴルフではない...c:[c: compose/only [c: (c)]print not error? try[if c = load/all input[1 / 0]]]
HostileForkはSEを信頼してはいけないと言ってい

無効なコードについて少し見逃しました。これはどう? (prin none? attempt[load/all input] halt) 1a 無効な整数は構文評価に失敗しますが、停止すると通常の操作でエラーが停止します
johnk

「コードをチェックサムしないで自分のコードの検証に失敗し、自分のコードが表示された場合にfalseを返す方法はまだ考えられません。」checksum/secureあなたのプログラム ができて、比較の目的でソース自体の中にハッシュを含めることができるなら、私は私のサイバー犯罪シンジケートにあなたのサービスを参加させたいと思います。それがなければ、機能する私のコードから始めます。:-)
HostileForkがdont信頼SEと言う

1
ああ!RebMu at 49:do B[pb bl? iu a jn "do B" ml b [try [ld/all a]]]
rgchris 2014

2

JavaScript- 86 82

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

ブラウザのJavascriptコンソールに貼り付けてテストします。
説明:

// 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
}()

注: @ m.buettnerは、プログラムがのtrueようなネイキッドreturnステートメントに対して戻るという点を示しましたreturn 0;。JavaScriptは、実際に実行されるまで(if (0) { return 0; }構文エラーをスローしないようなコードを意味する)、不正なreturnステートメントの構文エラーをスローしないため、JavascriptでJavaScriptパーサーを作成する以外に、これを修正する方法はないと思います。 。たとえば、次のコードを考えます。

while (1) {}
return 0;

コードが実行されると、ループが原因でハングします。コードが実行されない場合、不正なreturnステートメントに対してエラーはスローされません。したがって、これはJavaScriptがこの課題に対応できるほど優れています。これで問題が十分に解決されないと思われる場合は、Javascriptを失格にしてください。


2
これで、指定したときに構文エラーが報告されなくなりreturn 0ます。
マーティンエンダー2014

うーん、いい人@ m.buettner
アブラハム

2

Haskell-222バイト

これは真のパーサーを使用することに注意してください。eval動的言語の類似の関数には依存しません。

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")

このソリューションは特にきれいではありませんが、機能します。


それ自体は失敗しますか?
PyRulez 14

します。if take ...入力は、プログラムの最初の部分で、文字列リテラルと一致するかどうかを確認するために命令チェック。
gxtaillon 2014

2

これはルールに従うと思います:

JS(✖╭╮✖)

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

正しい場合、コードが評価されます。

矢印の表記を見て、これ以上短くできないかどうかを確認する必要があります。

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

数回失敗した後、元に戻します-新しいバージョン!

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

そして、私は戻ってきました!

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

そして、私は行ってしまった!残念ながらevalの性質と@scragar(@scragarに気を付けて!)のおかげで、このアプローチは機能しません(throw new SyntaxErrorこのメソッドをティックする有効なJSコードを見ると)-そのため、作成することは不可能です構文チェッカー(少なくともevalまたはそのバリエーションを使用)

(*コメントをご覧ください!)


入力が無限ループであると仮定しますか?使用をお勧めしますeval("x=function(){"+t+"}");
DankMemes 2014

1
@ZoveGames }//またはのような入力で壊れる可能性があります};{
Ventero 2014

これは関数ではなくプログラムである必要があるため、これがルールに従って有効かどうかはわかりません(私は思う)
Abraham

@ZoveGames良い点!ブラウザのスクリプト処理が開始されるはずですが(ループカウンタ/タイムアウト)、「システム」をハングさせるスクリプトを書くのは簡単です。OPがこれに関するルールを指定するまで、変更を待ちます。
14

1
@eithedog申し訳ありませんが、言語で混乱しました。Javascriptベースのスロー可能オブジェクトは実際には呼び出されますがError、呼び出されませんExceptionthrow new Error('')不正な動作を引き起こします。
スクレイガー2014

1

パイソン(95)

c=raw_input()
try:compile('"'if sum(map(ord,c))==7860 else c,'n','exec');print 1
except:print 0

これは1行の入力でしか機能しませんか?
Ian D. Scott 14

2
動作しません:c=u'#\u1e91'理由ord('#') + ord(u'\u1e91') == 7860
ThinkChaos

代わりにハッシュを試してください。
PyRulez 14

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

「ハッシュ」(s、ɐɔıʇǝɥʇuʎsの恥知らずなコピー)を保持するために必要なコメント。php -l / lintを使用してエラーをチェックします。

$ 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

0

C 174

説明-Wallは、コンパイル中にシステムエラーを生成する必要がありました。構文エラーはありませんreturn 0;。Windowsコンソールでstdinを介して入力するには、貼り付け後にCtrl-Zを入力してEnterキーを押します。

ゴルフ

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");}

未ゴルフ:

#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");
}

0

T-SQL-110

かなりシンプルで、しばらくここでチャレンジしてみたいと思っていましたが、ようやくやってみました。これは空想的なコードではありませんが、それでも楽しみました。

「ゴルフ」バージョン。

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

より適切にフォーマットされたバージョン。

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

BEGIN CATCH 
    PRINT'FALSE'
END CATCH

それはかなり自明です、それは結果を返すのではなくクエリを解析するだけにするSET NOEXECを使用します。残りは主に、何を印刷する必要があるかを判断するために使用するtry / catchです。

編集:私はこれが技術的にそれ自体失敗することを付け加えるべきでした。動的SQLを使用するため、入力内の単一引用符はすべて二重にする必要があります '->' '

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.