Buat pemeriksa sintaks yang aneh

8

Anda harus membuat program yang dapat memeriksa sintaks program dengan bahasa yang sama. Misalnya, jika Anda melakukannya dengan python, ia memeriksa sintaks python. Program Anda akan menerima program pada input standar, dan memverifikasi apakah sintaksinya benar atau tidak. Jika benar, output hanya "benar" pada output standar. Jika tidak, output hanya "false" pada output standar.

Program Anda harus salah dalam satu contoh. Jika diberi kode sumbernya sendiri, itu hanya akan menampilkan "false" pada output standar. Ini kode golf, jadi program tersingkat menang!

Catatan: Meskipun ini secara teknis bukan quine, Anda harus mengikuti aturan quine, artinya Anda tidak dapat mengakses kode sumber Anda melalui sistem file atau apa pun.

Catatan: Anda tidak dapat mengklaim program yang tidak dapat dijalankan karena kesalahan sintaksis memecahkan tantangan ini, karena itu harus dapat dijalankan.

PyRulez
sumber
1
Apakah menggunakan perpustakaan standar dan / atau pihak ketiga diizinkan? (khusus, untuk menggunakan lexer / parser yang berfungsi untuk bahasa Anda)
Martin Ender
Apakah try:exec(raw_input())...diperbolehkan?
user80551
@ user80551 Itu tidak akan berfungsi untuk input yang benar secara sintaksis yang berulang selamanya. Ini juga sedikit risiko keamanan.
Martin Ender
Bukankah seharusnya memiliki tag quine?
Sylwester
1
@ m.buettner Bagaimana jika kita indent raw_input () ke fungsi baru dan exec sehingga fungsi tersebut tidak pernah benar-benar dipanggil. BTW siapa dia peduli tentang risiko keamanan dalam kode-golf?
user80551

Jawaban:

9

Ruby 2.0, 65 76 164 karakter

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

Ini menggunakan checker sintaks bawaan Ruby ( ruby -c) untuk memeriksa sintaks input, yang berarti kode tidak akan dievaluasi.

Contoh penggunaan dasar:

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

Penjelasan

Solusi ini didasarkan pada standar Ruby quine:

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

%padalah penentu format untuk arg.inspect, yang dapat dibandingkan dengan uneval: ketika evalstring dikembalikan oleh arg.inspect, Anda (biasanya) mendapatkan nilai asli lagi. Jadi, ketika memformat qstring dengan dirinya sendiri sebagai argumen, bagian %pdalam string akan diganti dengan string yang dikutip itu sendiri (yaitu kita mendapatkan sesuatu seperti "q=\"q=%p;puts q%%q\";puts q%q").

Generalisasi jenis quine ini mengarah ke sesuatu seperti berikut:

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

Pendekatan ini memiliki satu kelemahan besar (setidaknya dalam ): Semua kode harus diduplikasi. Untungnya, evalbisa digunakan untuk menyiasati ini:

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

Apa yang terjadi di sini adalah bahwa kode yang dikirimkan ke eval disimpan di dalam r sebelum eval dipanggil. Akibatnya, kode sumber lengkap dari evalpernyataan tersebut dapat diperoleh dengan 'eval r=%p'%r. Jika kita melakukan ini di dalam evalkode d dan memastikan bahwa level teratas dari kita hanya terdiri dari satu evalpernyataan, ekspresi itu benar-benar memberi kita kode sumber penuh dari program kita, karena kode tambahan yang diteruskan ke evalsudah tersimpan di dalamnya r.

Catatan: Pendekatan ini sebenarnya memungkinkan kita untuk menulis Ruby quine dalam 26 karakter: eval r="puts'eval r=%p'%r"

Sekarang, dalam solusi ini kode tambahan yang dijalankan di dalam evalterdiri dari empat pernyataan:

gets p

Pertama, kami membaca semua input dari STDIN dan secara implisit menyimpannya $_.

$<.pos=0

Kemudian, kami memundurkan STDIN sehingga input tersedia lagi untuk subproses yang kami mulai pada langkah berikutnya.

`ruby -c 2>&0`

Ini memulai Ruby dalam mode pemeriksaan sintaks bawaannya, membaca kode sumber dari stdin. Jika sintaks skrip yang disediakan (nama file atau stdin) ok, ia mencetak Syntax OKke stdout (yang ditangkap oleh proses induk), tetapi dalam kasus kesalahan sintaks, deskripsi kesalahan dicetak ke stderr - yang akan menjadi terlihat, jadi kami mengarahkan itu ke nirwana ( 2>&0) sebagai gantinya.

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

Setelah itu, kami memeriksa kode keluar subproses $?, yaitu 0 jika sintaksnya ok. Terakhir, input yang kita baca sebelumnya ( $_) dibandingkan dengan kode sumber kita sendiri (yang, seperti yang saya jelaskan sebelumnya, dapat diperoleh dengan 'eval r=%p'%r).

Sunting: Disimpan 14 karakter berkat @ histokrat!

Ventero
sumber
Saya percaya bahwa jawaban Anda adalah satu-satunya yang benar-benar mengikuti aturan sejauh ini.
PyRulez
1
Sangat bagus! Saya pikir Anda bisa mengganti .write dengan <<, dan >>1<1dengan ==0.
histokrat
@ histokrat Huh, entah bagaimana melewatkan bagian tentang ==dalam Process::Statusdokumen. Terima kasih banyak!
Ventero
6

Rebol - 69 atau 7475 sepenuhnya mematuhi semua aturan

Versi kerja baru berkat @rgchris! Tidak yakin jika yang pertama gagal persyaratan "jangan mengakses sumber" karena penerjemah memegang kode yang dimuat dan diuraikan itu telah diteruskan sebagai parameter garis cmd dalam objek sistem ( system/options/do-arg) yang digunakan untuk mengenali dirinya sendiri.

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

Ini mengikuti semua aturan:

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

Contoh penggunaan:

Pertama mencetak bilangan bulat yang valid, yang kedua mencetak bilangan bulat tidak valid.

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 

Versi yang sepenuhnya sesuai:

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

Penjelasan:

Versi pertama

Ini menggunakan fungsi bawaan Rebols loaduntuk mengurai dan memuat kode dari stdin tetapi tidak menjalankannya.

The tryblok menangkap kesalahan sintaks dan error?fungsi mengkonversi kesalahan ke boolean sederhana.

The i = system/options/do-argmembandingkan masukan dari stdin (ditugaskan untuk i) dengan kode lulus pada do-argargumen (licik tapi sangat golf :).

anyadalah fungsi hebat yang mengembalikan truejika any-hal di blok dievaluasi true(misalnya, any [ false false true ]akan kembali true).

notlalu balikkan boolean untuk memberi kita jawaban yang benar dan probemenampilkan konten nilai yang dikembalikan.

Versi yang sepenuhnya sesuai

Mari kita lalui ini dalam rangka ...

Tetapkan kata bke blok [] yang mengikuti.

Gunakan dofungsi ini untuk menafsirkan dodialek di bblok.

Di dalam bblok ...

Atur kata iuntuk merujuk ke isi stdin ( input).

Sekarang, ifkita joinstring "do b:" ke moldblok 'ed bdan itu tidak sama ( <>) ke input stdin ikemudian kita coba ke loadinput i.

Jika hasilnya adalah blockmaka kami telah loadmengirimkan data yang dikirimkan dengan benar jika tidak kami akan menerima nonedari yang gagal if.

Gunakan prinuntuk menampilkan hasil block?yang mengembalikan true jika hasilnya adalah blok. Menggunakan prinsebagai lawan printtidak menampilkan carriage return setelah output (dan itu menyimpan kita char lain).

Johnk
sumber
Saya pikir Anda dapat mencukurnya hingga 36 karakter denganprint not error? try[load/all input]
draegtun
Itu memeriksa sintaks ... tetapi masalahnya menetapkan bahwa itu mengembalikan false pada kode sendiri. Begitu saja, ungolfed ...c:[c: compose/only [c: (c)]print not error? try[if c = load/all input[1 / 0]]]
HostileFork bilang jangan percaya SE
Saya melewatkan sedikit tentang kode tidak valid. Bagaimana dengan ini? (prin none? attempt[load/all input] halt) 1a Integer yang tidak valid akan gagal evaluasi sintaksis, tetapi penghentian akan menghentikan kesalahan dalam operasi normal
johnk
"Masih tidak dapat menemukan cara untuk gagal memvalidasi kode saya sendiri, kurang dari memeriksa kode dan mengembalikan false jika saya melihat kode saya sendiri." Jika Anda dapat checksum/secureprogram Anda, dan memasukkan hash ke dalam sumber itu sendiri untuk tujuan perbandingan, maka saya ingin mendaftarkan layanan Anda di sindikat kejahatan dunia maya saya. Kecuali itu, mulai dari kode saya, yang berfungsi. :-)
HostileFork bilang jangan percaya SE
1
Doh! RebMu pukul 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)}()

Rekatkan ke konsol Javascript browser Anda untuk menguji.
Penjelasan:

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

Catatan: @ m.buettner mengemukakan poin bahwa program kembali trueuntuk pernyataan pengembalian telanjang, seperti return 0;. Karena Javascript tidak melempar kesalahan sintaksis untuk pernyataan pengembalian ilegal sampai benar-benar berjalan (artinya kode seperti if (0) { return 0; }tidak melempar kesalahan sintaksis), saya tidak berpikir ada cara untuk memperbaiki ini singkat menulis parser Javascript di Javascript . Misalnya, perhatikan kodenya:

while (1) {}
return 0;

Jika kode dieksekusi, itu akan hang karena loop. Jika kode tidak dieksekusi, tidak ada kesalahan akan dilemparkan untuk pernyataan pengembalian ilegal. Oleh karena itu, ini sama baiknya dengan Javascript untuk tantangan ini. Jangan ragu untuk mendiskualifikasi Javascript jika Anda merasa ini tidak cukup memenuhi tantangan.

Abraham
sumber
2
Sekarang tidak akan melaporkan kesalahan sintaks saat memberikannya return 0.
Martin Ender
Mm, bagus @ m.buettner
Abraham
2

Haskell - 222 byte

Perhatikan bahwa ini menggunakan parser sejati. Itu tidak tergantung pada evalfungsi seperti bahasa dinamis.

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

Solusi ini tidak terlalu cantik tetapi tidak berfungsi.

gxtaillon
sumber
Apakah itu gagal untuk dirinya sendiri?
PyRulez
Itu benar. The if take ...instruksi cek untuk melihat apakah input cocok dengan literal string yang yang merupakan bagian pertama dari program ini.
gxtaillon
2

Saya pikir ini mengikuti aturan:

JS (✖╭╮✖)

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

Kode akan dievaluasi jika benar.

Perlu melihat notasi panah untuk melihat apakah itu tidak dapat dipersingkat lagi.

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

Setelah beberapa upaya gagal dan kembali - versi baru!

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

Dan saya kembali!

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

Dan aku pergi! Sayangnya karena sifat eval dan terima kasih kepada @scragar (sialan Anda @scragar!) Pendekatan ini tidak akan berfungsi (melihat seperti throw new SyntaxErrorkode JS yang valid, yang menandai metode ini) - karena itu, saya akan mengatakan tidak mungkin untuk membuat pemeriksa sintaks (paling tidak menggunakan eval atau variasi lainnya)

(* lihat komentar!)

eithed
sumber
Misalkan inputnya adalah infinite loop? Saya sarankan Anda menggunakaneval("x=function(){"+t+"}");
DankMemes
1
@ZoveGames Itu bisa rusak dengan input suka }//atau };{.
Ventero
Saya tidak tahu apakah ini valid atau tidak sesuai dengan aturan karena harus program, bukan fungsi (saya pikir)
Abraham
@ZoveGames Poin bagus! Meskipun penanganan skrip browser harus dimulai (penghitung putaran / batas waktu), masih mudah untuk menulis skrip yang akan menyebabkan "sistem" hang. Saya akan menunggu dengan perubahan sampai OP menentukan aturan tentang ini.
eithed
1
@ eithedog Maaf, bingung pada bahasa, basis Javascripts sebenarnya bisa dipanggil Error, bukan Exception. throw new Error('')menyebabkan perilaku yang salah.
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
sumber
Bukankah itu hanya bekerja untuk satu jalur input?
Ian D. Scott
2
Tidak berfungsi: c=u'#\u1e91'karenaord('#') + ord(u'\u1e91') == 7860
ThinkChaos
Cobalah hash sebagai gantinya.
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

Komentar diperlukan untuk menyimpan 'hash' (salinan s, ɐɔıʇǝɥʇuʎs yang tidak tahu malu). Menggunakan php-l / lint untuk memeriksa kesalahan.

$ 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ý
sumber
0

C 174

Penjelasan -Dinding diperlukan untuk menghasilkan kesalahan sistem sementara masih dapat dikompilasi. Kesalahan sintaksnya adalah no return 0;To enter via stdin di konsol Windows ketik Ctrl-Z setelah menempelkan dan tekan enter.

Golf

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

Tidak Disatukan:

#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
sumber
0

T-SQL - 110

Cukup sederhana, saya sudah lama ingin mencoba tantangan di sini, akhirnya bisa melakukannya. Ini bukan kode yang paling bagus, tapi aku bersenang-senang nontheless.

Versi 'golf'.

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

Versi yang diformat lebih baik.

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

BEGIN CATCH 
    PRINT'FALSE'
END CATCH

Ini cukup jelas, menggunakan SET NOEXEC yang membuatnya hanya mengurai kueri alih-alih mengembalikan hasil apa pun. sisanya sebagian besar adalah try / catch yang saya gunakan untuk menentukan apa yang perlu saya cetak.

EDIT: Saya seharusnya menambahkan bahwa ini secara teknis akan gagal untuk dirinya sendiri. karena menggunakan SQL dinamis setiap kutipan tunggal dalam input harus digandakan '->' '

PenutReaper
sumber