わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

レポート課題(文脈自由文法をCで)

学生の皆さんは,明日から試験ですね.良い点数*1を取れるよう,しっかり勉強することを,期待したいと思います.
私も担当の科目が一つありますが,14回授業時の「おさらい問題」を作る際に,「試験問題」の案も作っていまして,もう少し具体的に書くと,学生のみなさんに答えを考えてもらいたい「問い」を,授業内容から洗い出して,紛らわしさはあるけれど知ってほしいものを「おさらい問題」に,問いと答えの形で,きちんと理解してほしいものを「試験問題」に,仕分けています.なのであとは,整形するだけです.
本日は,学生さんにとっては冬休みの宿題で,自分にとっても一応2週間前に終わらせた,レポート課題について,書いておくことにします.
例年,冬休みの宿題として,150行程度のコードを打ち込んでもらっています.
小問も与えています.最初はデバッグ問題で,資料通りに打ち込んでコンパイルするとエラーが出るので取り除いてくださいというものです.
あとは,何をするプログラムなのか簡潔に書けだとか,一つだけ関数の前にコメントを書いていないものがあって適切なコメントを書けだとか(要は,何をする関数なのか簡潔に書けという問題です),重要な処理でのメモリ状態を答えよとか,等価書き換えとかをやっています.
昨年度と同じく,最後は「自分で問題を設定し,それに答えなさい」にしています.
問題形式だけでなく,コードの特徴も,前年度のものと相当似ています.ポインタ・関数・構造体を組み合わせています.関数の一つは,再帰呼び出しをします.調査課題も入れました.
今年度はどんな題材にしたのかというと,文脈自由文法です.それも,コンパイラが行う構文解析のほうではなく,生成に着目しました.S→aSb,S→εという2つの規則があれば,開始記号Sから,ab, aabb, aaabbb, ...と,aとbの字数が同じになる文字列が生成できて*2,これは正規文法では無理ってやつです.
ここでS→aSbという規則は{'S', "aSb"}という構造体の値で,S→εなら{'S', ""}と表現することで,規則の集合を構造体の配列で表現できます.あとは条件に合う規則をforループで探し,適用し(書き換え)ます.上限になれば書き換えを打ち切り,それまでに,英大文字(変数)がなくなったらそれを出力します.
プログラミングを離れて考えると,こうなります…変数(非終端記号)と変数でない文字(終端記号)からなる0個以上の系列(語)について,語をノード,1回の規則の適用による語の関係をリンクとすると,有向グラフを作ることができます.さらに,ある語(通常は,開始記号となる非終端記号)を指定すれば,そこから到達可能なノードが導出可能な語と対応し,その中でも終端記号のみからなるものが,Sから生成される語となります.それを求めるのは,木の探索問題に帰着されます.
文脈自由文法の概念自体は,1年後期に,システムソフトウェアという科目で簡単に教わっているはずで,昨年度はこの科目のはじめ3回を担当したのですが,まあ文脈自由文法を知ってても知らなくても,何をするプログラムなのかがきちんと書けていればいいかなと,問うてみると,うまく表現している答案がいくつか出てきました*3
それで,答案から良いもの,他の学生にも見てもらう価値のあるものを抜き出して,「別解」としました.もちろん別解にも善し悪しがあります.たとえば

  char str[10] = 'S';

デバッグしなさいという問題に対して,用意した答えは

  char str[10] = "S";

ですが,

  char str[10] = {'S'};

としても問題ないわけで,これは解答例と同じくらいとします.もう一つ,等価書き換え問題で

  some_type array1[] = {/* 6個の要素 */};
  some_type array2[] = {/* 7個の要素 */};
  some_type *array[] = {array1, array2};

というコードに対して,arrayはポインタと配列が混在してややこしいので2次元配列に書き換えなさいという問題を出しました.array1, array2は消滅してもいいと,但し書きをつけました.期待した答えは

  some_type array[2][7] = {{/* 6個の要素 */}, {/* 7個の要素 */}};

でしたが,

  some_type array[][7] = {{/* 6個の要素 */}, {/* 7個の要素 */}};

はいいでしょう.ですが,

  some_type array[2][10] = {{/* 6個の要素 */}, {/* 7個の要素 */}};

は10が謎ですし,

  some_type array[6][7] = {{/* 6個の要素 */}, {/* 7個の要素 */}};

を目にした瞬間は,2次元配列を理解していないぞこれと思ったものの,ともあれ動作には支障ないわけで,減点はできません.それにしても,何らかの差別化を図りたかったのでした.
そんなこんなと解答を整理した結果,解答例よりも良いものには「◎」,同程度のものには「○」を,別解の頭につけて提示することにしました.
何をするプログラムなのかの問いは,「◎」の文ばかりを載せました.自分で問題を立てて答えるものは,問題のみを並べて解答は挙げないことにし,約半数を「◎」,残りを「○」としました.
別解のほか,誤答の中でも,学生に周知したいものがありました.「変数を書き換える」だとか(文字列を書き換える,または,変数を〜に置き換える,としないといけません),「規則を適応する」だとか「規則を適合する」だとか(いずれも「適用」です),「再帰する」だとか,問題文に「出典」と書いているのに「出展」だとか「出店」だとか.しかしこういうのは,挙げれば挙げるほど自己嫌悪ですねえ.
時間的制約と採点の公平性から,正答には点数を与え,誤答には点数を与えられないのですが,それと別に,各学生の意見を集約すると,一人では思いつかない面白い書き方,考え方が得られる,というのが,このレポート課題を実施するにあたってのひそかな楽しみです.そして学生さんにも,その一端を知ってほしいと願って,解答例と解説をリリースしているのでした.

過去に書いたもの:

*1:和歌山弁で「ええ値(ね),するね」と言ったら,「良い値段」じゃなくて「高い」という意味です.

*2:厳密さを欠きますが,ご容赦ください.

*3:ちなみに「文脈自由文法」と書いている答案はひとっつもありませんでした.授業内容を変えられたのかな….