完全モジュラーC:グレーディング


8

あなたは、Cプログラミング言語を教えるコンピューターサイエンスの教授です。学生に伝えたい原則の1つはモジュール性です。残念ながら、過去のクラスはメッセージを受信しない傾向があり、プログラム全体を使用して課題を提出していましたmain()。したがって、この学期では、学生を採点するための厳格なモジュール化ガイドラインを発行しました。

Cの文法のサブセットと「整形式」の翻訳単位の規則を以下に定義します。これらの規則に従うコードは、キーワードである識別子が使用されない限り、有効なC89である必要があります。

仕事

Cコードを含むとされる文字列を入力として受け取ります。この文字列には、スペース、改行、および文字のみが含まれていると想定できますabcdefghijklmnopqrstuvwxyz123456789(){},+-*/%;=

コードは、次のルーブリックに従って、学生の課題が受け取るポイント数を出力する必要があります。

  • translation-unit文法により、入力は無効です:0ポイント
  • 入力は文法に従いますが、以下のルールに従って「整形式」ではありません:1ポイント
  • 入力は整形式の翻訳単位ですが、完全にモジュール化されていません:2ポイント
  • 入力は完全にモジュール化された整形式の翻訳単位です:3ポイント

トークンの定義

  • identifier:1つ以上の英小文字のシーケンス。識別子がC89予約語1の場合、結果が予約語を無視していたであろうものの代わりに、オプションで0を返すことができます。予約語の識別子としての使用を検出することに一貫性がある必要はありません。場合によってはフラグを立てて、他のインスタンスに渡すこともできます。

  • integer-literal:1桁以上の数字1から9のシーケンス(文字0が入力に表示されないことが保証されていることを思い出してください)

  • 他の有効なトークンは文法で文字通り定義されています。
  • 文字が空白でない場合に限り、文字はトークンに属している必要があります。
  • 2つの連続した英数字は、同じトークンの一部である必要があります。

EBNF文法

var-expr = identifier
literal-expr = integer-literal
binary-op = "+" | "-" | "*" | "/" | "%"
binary-expr = expr binary-op expr
paren-expr = "(" expr ")"
call-expr = identifier "(" [ expr ( "," expr )* ] ")"
expr = var-expr | literal-expr | binary-expr | paren-expr | call-expr
assign-stmt = var-expr "=" expr ";"
if-stmt = "if" "(" expr ")" assign-stmt
return-stmt = "return" expr ";"
function-body = ( assign-stmt | if-stmt )* return-stmt
argument-list = [ identifier ( "," identifier )* ]
function-definition = identifier "(" argument-list ")" "{" function-body "}"
translation-unit = function-definition*

適切なプログラム要件

  • 2つの関数定義が同じ関数名を持つことはできません。
  • 内の2つの識別子argument-listが同一であってはなりません。
  • 内の識別子は、argument-list関数名と同じであってはなりません(a function-definitionまたはa からcall-expr)。
  • 内の識別子はvar-expr、囲んでいる関数のに含まれている必要がありますargument-list
  • 特定の関数では、すべてcall-exprのとfunction-definition(存在する場合)は引数の数が一致している必要があります。

完全にモジュール式

  • 関数ごとに1つ以下の2項演算子
  • 関数ごとに1つ以下の代入ステートメント
  • 関数ごとに1つ以下の関数呼び出し

例(1行に1つ)

スコア0

}}}}}
return 2;
f() { return -1; }
f() {}
f(x,) { return 1; }
f(x) { return 1 }
f(x) { returnx; }
f(x) { return1; }
f() { g(); return 1;}
f() { if(1) return 5; }
f(x) { if(1) if(1) x = 2; return x; }
f(x, y) { x = y = 2; return x; }

スコア1

f(){ return 1; } f(){ return 1; }
g(x, x) { return 1; }
g(f) { return 1; } f() { return 1; }
f(x) { x = write(); x = write(1); return 1; }
f() { return f(f); }
f() { return 1; } g() { return f(234567); }
f() { return(x); }
f() { j = 7; return 5; }

スコア2

f(x,y,zzzzz) { return x + y + zzzzz; }
f(x,a,b) { if(a) x = foo(); if(b) x = bar(); return x; }
f(j) { return g(h( i() / j, i() ), 1) ; }

スコア3

mod(x, y) { return ((x % y)); }
f() { return f(); }
f(c) { if(c) c = g(c) + 2; return c; }
fib(i){return bb(i,0,1);}aa(i,a,b){return bb(i,b,a+b);}bb(i,a,b){if(i)a=aa(i-1,a,b);return a;}

スコア0または1

h(auto, auto) { return 1; }

スコア0または3

if() { return 1; }

1 予約語リスト:auto break case char const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while


入力文字列は空ですか?(もしそうなら、私はそれが3をスコアするべきだと思います。)
Arnauld

@Arnauldはい、そうです。
feersum

宣言されていない関数の引数の数をチェックするにはどうすればよいですか?「スコア1」の4番目の例は、write引数なしで1回、引数1つで1回呼び出されたため、整形式ではありませんか?
Arnauld、2018

@Arnauldはい、定義されていない関数の各呼び出しに同じ数の引数があることを確認します。
feersum

そうですか。さて、これは現在パーサーと互換性がないので、今のところ私の答えを削除します。後でもう一度試してみるかもしれません。
Arnauld

回答:


3

JavaScript(ES6)、599バイト

T=_=>P=I.shift()
B=v=>I.unshift(P)&&v
J=_=>/^[a-z]+$/.test(T())*7
M=p=>T()==p&&7
C=(n,a)=>n in U?U[n]==a?7:1:(U[n]=a,7)
E=(m,O=n=>E()&(M`,`?O(n+1):P==")"&&C(m,n)))=>(M`(`?E()&M`)`:P==+P?7:J(m=B(P))&(M`(`?++z&&M`)`?C(m,0):O(B(1)):B(A[m]|1)))&(/[+*/%-]/.test(T())?E(++y):B(7))
S=_=>I[0]?M`return`?E()&M`;`&M`}`&C(F,N)&((x|y|z)>1?3:7):(P=="if"?M`(`&E()&M`)`:B(7))&J(++x)&(A[P]|1)&M`=`&E()&M`;`&S():0
G=_=>J(++N)&(A[P]|L[P]&8?1:A[P]=L[P]=7)&(M`,`?G():P==")"&&M`{`&S())
Q=_=>I[N=x=y=z=0]?J(A={})&(L[F=P]?1:L[F]=15)&M`(`&(M`)`?M`{`&S():G(B()))&Q():7
f=c=>Math.log2(Q(U={},L={},I=c.match(/\w+|\S/g)||[])+1)

オンラインでお試しください!(テストケースに付属)

f引数としてコードを受け取る関数を定義します。

(一部)説明

この怪物は本質的に巨大な再帰的なビット単位のANDであり、なんらかの形でこのCサブセットのパーサーとして機能します。スコアとして記憶されている0137ため0123、それぞれおよびとして最終的に変換されlog2(score+1)、いずれかのフェーズでコードの問題が検出されると、7未満のスコアが返され、最終出力からビットの設定が解除され、スコアが低くなります。スコアを除くすべての関数TBスコアを返します。

使用された識別子はで追跡されL、関数の引数はでカウントされUます。現在の関数の引数カウントはNで、名前はにありAます。割り当て、バイナリ演算子とコールがで追跡されxyそしてzそれぞれ。

コードが入力をundefined使い果たした場合でも、トークンの両端からsを喜んで取り出します。一致する唯一の関数undefinedJであり、結局と一致しないため、最終的に再帰が終了して0を返すため、これは問題ありません}。(以外SQその入力の終了の明示的なチェックを持っている。)でも押圧undefinedポッピングがので両端キューにバックは、無害であり、undefined空の配列を飛び出ると同じです。

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