Tạo một trình kiểm tra cú pháp finky


8

Bạn phải tạo một chương trình có thể kiểm tra cú pháp của các chương trình có cùng ngôn ngữ. Ví dụ, nếu bạn làm điều đó trong python, nó sẽ kiểm tra cú pháp python. Chương trình của bạn sẽ nhận được một chương trình về đầu vào tiêu chuẩn và xác minh xem cú pháp của nó có đúng hay không. Nếu đúng, đầu ra chỉ "đúng" trên đầu ra tiêu chuẩn. Nếu không, đầu ra chỉ "sai" trên đầu ra tiêu chuẩn.

Chương trình của bạn phải không chính xác trong một trường hợp mặc dù. Nếu được cung cấp mã nguồn riêng, nó sẽ chỉ xuất "false" trên đầu ra tiêu chuẩn. Đây là mã golf, vì vậy chương trình chiến thắng ngắn nhất!

Lưu ý: Mặc dù về mặt kỹ thuật, đây không phải là một quy tắc, bạn phải tuân theo các quy tắc về quy tắc, nghĩa là bạn không thể truy cập mã nguồn của mình thông qua hệ thống tệp hoặc bất cứ điều gì.

Lưu ý: Bạn không thể yêu cầu một chương trình không thể chạy do lỗi cú pháp giải quyết thách thức này, vì nó cần phải chạy được.


1
Được phép sử dụng thư viện tiêu chuẩn và / hoặc bên thứ 3? (cụ thể, để sử dụng một trình phân tích / trình phân tích cú pháp hoạt động cho ngôn ngữ của bạn)
Martin Ender

Được try:exec(raw_input())...phép?
dùng80551

@ user80551 Điều đó sẽ không hoạt động cho đầu vào đúng về mặt cú pháp mà lặp đi lặp lại mãi mãi. Đó cũng là một rủi ro bảo mật nhỏ .
Martin Ender

Nó không nên có thẻ quine?
Sylwester

1
@ m.buettner Điều gì xảy ra nếu chúng ta thụt raw_input () vào một hàm mới và thực thi nó để hàm này không bao giờ thực sự được gọi. BTW, người mà anh ta quan tâm về rủi ro bảo mật trong môn đánh gôn?
user80551

Câu trả lời:


9

Ruby 2.0, 65 76 164 nhân vật

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

Điều này sử dụng trình kiểm tra cú pháp tích hợp ( ruby -c) của Ruby để kiểm tra cú pháp của đầu vào, có nghĩa là mã sẽ không được đánh giá.

Ví dụ sử dụng cơ bản:

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

Giải trình

Giải pháp này là (đã) dựa trên tiêu chuẩn Ruby quine:

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

%plà định dạng định dạng cho arg.inspect, có thể được so sánh với uneval: khi evaling chuỗi được trả về bởi arg.inspect, bạn (thường) lấy lại giá trị ban đầu. Do đó, khi định dạng qchuỗi với chính nó làm đối số, %pbên trong chuỗi sẽ được thay thế bằng chính chuỗi được trích dẫn (nghĩa là chúng ta có một cái gì đó giống như "q=\"q=%p;puts q%%q\";puts q%q").

Tổng quát hóa loại quine này dẫn đến một cái gì đó như sau:

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

Cách tiếp cận này có một nhược điểm rất lớn (ít nhất là trong ): Tất cả các mã cần được sao chép. May mắn thay, evalcó thể được sử dụng để có được xung quanh này:

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

Điều xảy ra ở đây là mã được truyền cho eval được lưu trữ bên trong r trước khi eval được gọi. Kết quả là, mã nguồn đầy đủ của evalcâu lệnh có thể được lấy bằng 'eval r=%p'%r. Nếu chúng tôi thực hiện điều này bên trong evalmã d và đảm bảo rằng mức cao nhất của chúng tôi chỉ bao gồm một evalcâu lệnh, thì biểu thức đó thực sự mang lại cho chúng tôi mã nguồn đầy đủ của chương trình của chúng tôi, vì bất kỳ mã bổ sung nào được chuyển đến evalđều được lưu trữ bên trong r.

Lưu ý bên lề: Cách tiếp cận này thực sự cho phép chúng ta viết một quine Ruby trong 26 ký tự: eval r="puts'eval r=%p'%r"

Bây giờ, trong giải pháp này, mã bổ sung được thực thi bên trong evalbao gồm bốn câu lệnh:

gets p

Đầu tiên, chúng tôi đọc tất cả đầu vào từ STDIN và ngầm lưu nó vào $_.

$<.pos=0

Sau đó, chúng tôi tua lại STDIN để đầu vào có sẵn một lần nữa cho quy trình con mà chúng tôi bắt đầu trong bước tiếp theo.

`ruby -c 2>&0`

Điều này khởi động Ruby trong chế độ kiểm tra cú pháp tích hợp, đọc mã nguồn từ stdin. Nếu cú ​​pháp của tập lệnh được cung cấp (tên tệp hoặc stdin) là ổn, nó sẽ in Syntax OKra thiết bị xuất chuẩn của nó (được xử lý bởi quá trình cha), nhưng trong trường hợp có lỗi cú pháp, một mô tả về lỗi sẽ được in ra stderr - sẽ được in thay vào đó có thể nhìn thấy, vì vậy chúng tôi chuyển hướng điều đó thành niết bàn ( 2>&0).

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

Sau đó, chúng tôi kiểm tra mã thoát của quy trình con $?, là 0 nếu cú ​​pháp ổn. Cuối cùng, đầu vào mà chúng ta đọc trước đó ( $_) được so sánh với mã nguồn của chính chúng ta (mà như tôi đã mô tả trước đó, có thể thu được bằng 'eval r=%p'%r).

Chỉnh sửa: Đã lưu 14 ký tự nhờ @histocrat!


Tôi tin rằng câu trả lời của bạn là người duy nhất đã thực sự tuân theo các quy tắc cho đến nay.
PyRulez

1
Rất đẹp! Tôi nghĩ bạn có thể thay thế .write bằng <<, và >>1<1với ==0.
lịch sử

@histocrat Huh, bằng cách nào đó đã bỏ lỡ phần về ==các Process::Statustài liệu. Cảm ơn rất nhiều!
Ventero

6

Rebol - 69 hoặc 7475 tuân thủ đầy đủ tất cả các quy tắc

Phiên bản làm việc mới nhờ @rgchris! Không chắc chắn nếu lần đầu tiên không yêu cầu "không truy cập vào nguồn" vì trình thông dịch giữ mã được tải và phân tích cú pháp, nó đã được truyền dưới dạng tham số dòng cmd trong đối tượng hệ thống ( system/options/do-arg) được sử dụng để nhận dạng chính nó.

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

Điều này tuân theo tất cả các quy tắc:

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

Ví dụ sử dụng:

Đầu tiên in một số nguyên hợp lệ, lần thứ hai in một số nguyên không hợp lệ.

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 

Phiên bản hoàn toàn tuân thủ:

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

Giải trình:

Phiên bản đầu tiên

Điều này sử dụng loadchức năng tích hợp Rebols để phân tích và tải mã từ stdin nhưng nó không thực thi nó.

Các trykhối bắt bất kỳ lỗi cú pháp và error?chức năng chuyển đổi lỗi cho một boolean đơn giản.

Việc i = system/options/do-argso sánh đầu vào từ stdin (được gán cho i) với mã được truyền vào do-argđối số (lén lút nhưng rất golf :).

anylà một hàm tuyệt vời trả về trueif any-thing trong khối ước tính true(ví dụ: any [ false false true ]sẽ trả về true).

notsau đó chỉ cần đảo ngược boolean để cho chúng ta câu trả lời đúng và probehiển thị nội dung của giá trị được trả về.

Phiên bản hoàn toàn tuân thủ

Chúng ta hãy trải qua điều này theo thứ tự ...

Gán từ bcho khối [] theo sau.

Sử dụng dochức năng để giải thích dophương ngữ trong bkhối.

Bên trong bkhối ...

Đặt từ iđể chỉ nội dung của stdin ( input).

Bây giờ, ifchúng ta joinchuỗi "do b:" với khối mold'ed bvà nó không bằng ( <>) với đầu vào stdin isau đó chúng ta thử loadvào đầu vào i.

Nếu kết quả là một blockthì chúng ta đã sửa loaddữ liệu được truyền một cách chính xác nếu không chúng ta sẽ nhận được một nonetừ thất bại if.

Sử dụng prinđể hiển thị kết quả block?trả về giá trị true nếu kết quả là một khối. Sử dụng printrái ngược với printviệc không hiển thị lợi nhuận vận chuyển sau đầu ra (và nó tiết kiệm cho chúng ta một char khác).


Tôi nghĩ rằng bạn có thể cạo nó xuống 36 ký tự vớiprint not error? try[load/all input]
Drainegtun

Điều đó kiểm tra cú pháp ... nhưng vấn đề quy định rằng nó trả về sai trên mã của chính nó. Vô dụng, vô dụng ...c:[c: compose/only [c: (c)]print not error? try[if c = load/all input[1 / 0]]]
HostileFork nói không tin tưởng SE

Tôi đã bỏ lỡ một chút về mã không hợp lệ. Còn cái này thì sao? (prin none? attempt[load/all input] halt) 1a Số nguyên không hợp lệ sẽ không đánh giá cú pháp, nhưng việc dừng sẽ dừng một lỗi trong hoạt động bình thường
johnk

"Vẫn không thể đưa ra một cách để không xác thực mã của riêng tôi khi thiếu kiểm tra mã và trả về sai nếu tôi thấy mã của riêng mình." Nếu bạn có thể checksum/securechương trình của bạn và bao gồm hàm băm bên trong nguồn cho mục đích so sánh, thì tôi muốn tranh thủ các dịch vụ của bạn trong tổ chức tội phạm mạng của tôi. Chặn điều đó, bắt đầu từ mã của tôi, hoạt động. :-)
HostileFork nói không tin tưởng SE

1
Ôi! RebMu lúc 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)}()

Dán vào bảng điều khiển Javascript của trình duyệt của bạn để kiểm tra.
Giải trình:

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

Lưu ý: @ m.buettner đưa ra quan điểm rằng chương trình trả về truecho một tuyên bố hoàn trả trần trụi, chẳng hạn như return 0;. Vì Javascript không gây ra lỗi cú pháp cho câu lệnh trả lại bất hợp pháp cho đến khi nó thực sự chạy (có nghĩa là mã như if (0) { return 0; }không ném lỗi cú pháp), tôi không nghĩ có cách nào để khắc phục lỗi viết trình phân tích cú pháp Javascript này trong Javascript . Ví dụ, hãy xem xét mã:

while (1) {}
return 0;

Nếu mã được thực thi, nó sẽ bị treo vì vòng lặp. Nếu mã không được thực thi, sẽ không có lỗi nào được đưa ra cho câu lệnh trả lại bất hợp pháp. Do đó, điều này tốt như Javascript có thể nhận được cho thử thách này. Vui lòng loại bỏ Javascript nếu bạn cảm thấy việc này không hoàn thành đủ thách thức.


2
Bây giờ nó sẽ không báo cáo lỗi cú pháp khi đưa ra return 0.
Martin Ender

Mm, một người tốt @ m.buettner
Áp-ra-ham

2

Haskell - 222 byte

Lưu ý rằng điều này sử dụng một trình phân tích cú pháp thực sự. Nó không phụ thuộc vào evalchức năng như của các ngôn ngữ động.

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

Giải pháp này không đặc biệt đẹp nhưng có tác dụng.


Nó có thất bại cho chính nó?
PyRulez

Nó làm. Các if take ...kiểm tra hướng dẫn để xem nếu đầu vào phù hợp với một literal chuỗi đó là phần đầu tiên của chương trình.
gxtaillon

2

Tôi nghĩ rằng điều này tuân theo các quy tắc:

JS (✖╭╮✖)

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

Mã sẽ được đánh giá nếu nó đúng.

Cần phải xem ký hiệu mũi tên để xem nếu nó không thể rút ngắn hơn nữa.

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

Sau một vài lần thất bại và hoàn nguyên - phiên bản mới!

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

Và tôi đã trở lại!

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

Và tôi đi rồi! Thật không may do bản chất của eval và nhờ @scragar (chết tiệt bạn @scragar!) Cách tiếp cận này sẽ không hiệu quả (xem như throw new SyntaxErrorlà mã JS hợp lệ, đánh dấu phương thức này) - như vậy, tôi nói rằng không thể tạo ra một kiểm tra cú pháp (ít nhất là sử dụng eval hoặc bất kỳ biến thể nào của chúng)

(* xem các bình luận!)


Giả sử đầu vào là một vòng lặp vô hạn? Tôi đề nghị bạn sử dụngeval("x=function(){"+t+"}");
DankMeme

1
@ZoveGames Điều đó có thể bị phá vỡ với đầu vào như }//hoặc };{.
Ventero

Tôi không biết điều này có hợp lệ hay không theo các quy tắc vì nó phải là một chương trình, không phải là một chức năng (tôi nghĩ)
Áp-ra-ham

@ZoveGames Điểm tốt! Mặc dù việc xử lý tập lệnh của trình duyệt sẽ khởi động (bộ đếm vòng lặp / thời gian chờ), nhưng vẫn dễ dàng viết tập lệnh sẽ khiến "hệ thống" bị treo. Tôi sẽ chờ đợi sự thay đổi cho đến khi OP chỉ định quy tắc về việc này.
vẫy

1
@eithedog Xin lỗi, đã nhầm lẫn về ngôn ngữ, Javascripts cơ sở có thể ném được thực sự được gọi Error, không Exception. throw new Error('')gây ra hành vi không đúng.
Scragar

1

Con trăn (95)

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

Không phải nó chỉ hoạt động cho một dòng đầu vào sao?
Ian D. Scott

2
Không hoạt động: c=u'#\u1e91'bởi vìord('#') + ord(u'\u1e91') == 7860
ThinkChaos

Hãy thử một hàm băm thay thế.
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

Nhận xét cần thiết để giữ 'băm' (một bản sao không biết xấu hổ của s, ɐɔıʇǝɥʇuʎs). Sử dụng php -l / lint để kiểm tra lỗi.

$ 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

Giải thích - Sẽ cần thiết để tạo ra lỗi hệ thống trong khi vẫn có thể biên dịch được. Lỗi cú pháp là không return 0;Để nhập thông qua stdin trong bảng điều khiển Windows gõ Ctrl-Z sau khi dán và nhấn enter.

Chơi gôn

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

Ung dung:

#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

Khá đơn giản, tôi đã muốn thử thách ở đây một thời gian, cuối cùng cũng có vòng để thực hiện nó. Đây không phải là mã fanciest, nhưng tôi đã vui vẻ hàng tháng.

Phiên bản 'chơi gôn'.

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

Một phiên bản định dạng tốt hơn.

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

BEGIN CATCH 
    PRINT'FALSE'
END CATCH

Nó khá tự giải thích, nó sử dụng SET NOEXEC để làm cho nó chỉ phân tích truy vấn thay vì trả về bất kỳ kết quả nào. phần còn lại chủ yếu là thử / bắt mà tôi sử dụng để xác định những gì tôi cần in.

EDIT: Tôi nên nói thêm rằng điều này về mặt kỹ thuật sẽ thất bại cho chính nó. bởi vì nó sử dụng SQL động, bất kỳ dấu ngoặc đơn nào trong đầu vào phải được nhân đôi '->' '

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.