JOI’95 予選 問題6 解答・解説

問題6 正解 (3点 = (1)1点、(2a)(2b)各1点)

      (1)  -33

      (2a) C       expression(expr+1,value)
           Pascal  expression(copy(expr,2,len-2),value)   や
                   expression(copy(expr,2,length(expr)-2),value)
           BASIC   expression(MID$(expr$,2,LEN(expr$)-2),value)

      (2b) C       *value=atoi(expr),   sscanf(expr,"%d",value)    など
           Pascal  val(expr,value,error)
           BASIC   value=VAL(expr$)
    


 この問題では、「数式」をその定義文法に従って構文解析(どのような 文法構造をしているか分析すること)をして値を計算することを、 再帰降下法(recursive descent)と呼ばれる方法によって 行なっている。いわば、非常に簡単なプログラミング言語を定義し、 そのインタプリタを作っているのと同じである。言語の構文(シンタックス) を厳密に定義する方法はいろいろあるが、ここで用いているのは バッカス記法BNF記法)と呼ばれるものである。 このようなものも読み取れることが望ましい。

(1)223---2^2^3 の構文木を図1(省略)に示した。 よって、
  223---2^2^3=[223-[[-[-2]]^[2^3]]=223-(-(-2))^(2^3)=-33
である。

(2)関数 expression, term, factor, primary, constant は 数式の一部分を第1引数に文字列 expr として与えられると、それぞれ 文法要素「数式」「項」「因子」「素子」「定数」の構文に合致しているか どうかの解析を行ない、合致していたならば 第2引数 value(この引数は、自分を呼んだ関数へ値を 返すためのものであるから、「参照呼び出し(アドレス渡し)」にしてある) にその部分数式の値を代入するとともに、関数値として true(真)を返す。
 expression(expr, value) では、expr が「数式」の構文に合致 しているかどうかを、定義式
  <数式>::=<項>|<数式>+<項>|<数式>−<項>
に従って調べる。そのために、文字列 expr を α±β の形に 分解して、部分文字列 α,β に対し expr(α,value1) と expr(β,value2) を 調べ、両方ともtrueだったら数式 α の値 value1 と β の値 value2 を 使って数式 expr の値を value1±value2 に設定する。
同様のことを関数 term, factor, primary, constant でも行なう。 空欄は関数 primary と constant の中にある。
primary(expr, value) は文字列 expr が「素子」の構文
  <素子>::=<定数>|−<素子>|(<数式>)
に合致しているかどうか調べる。まず expr が <定数> かどうか調べ、 そうでなかったら、−<素子> の形をしているかどうか調べる。 そうでなかったら expr は (<数式>) の形をしていなければならない。 この最後の部分を調べるところに空欄(a)はある。(a)には expr の前後の括弧を取り除いた文字列が<数式>かどうかを 判定するための関数呼び出しが入る。
 constant(expr, value) では expr が <定数> であるかどうかを 調べ、そうである場合にはその値を計算する。空欄(b)には、 数字の列 expr を整数値に変換して value に代入する代入文が入る。