age++;10歳……じゃなくて、0x10歳 (16歳) になりました。
演算子順位構文解析法と下向き構文解析法を使い、前に書いたパーサーを実装し直す。
字句解析器を書き直し、識別子に対応させる。
最適化と逆ポーランド記法への変換の実装。
何となくC言語の仕様書を読んでいたら、無理矢理ポインタ演算を使って実現しようとしていた機能を見つけた。
良く調べてみたら、 C99 で追加された仕様らしい。
特別な場合として、二つ以上の名前付きメンバは、不完全配列型をもってもよい。これをフレキシブル配列メンバ (flexible array member) と呼ぶ。二つの例外を除いて、フレキシブル配列メンバは無視される。一つ目は、構造体の大きさは、フレキシブル配列メンバを未規定の長さの配列に置き換えて、それ以外は元のままとした構造体の最後のメンバのオフセットに等しいとする。二つ目は、
.( 又は->) 演算子がフレキシブル配列メンバをもつ構造体 ( 又はその構造体へのポインタ ) を左オペランドとしてもち、かつ右オペランドがそのメンバであるとき、その動作は、構造体の大きさが現在アクセスされているオブジェクトの大きさより大きくならないという条件のもとで、そのメンバが同じ要素型を持つ最大の大きさの配列で置き換えられた場合と同じとする。このとき、たとえ置き換えられた配列のオフセットがそのメンバのオフセットと異なるとしても、そのメンバのオフセットは変更しない。置き換えられた配列が要素をもたないとき、それはただ一つの要素をもつのと同じ規則で動作する。しかし、その要素にアクセスした場合、又はその要素を一つ超えたポインタを生成した場合、その動作は未定義とする。
a<b == b<c と書くと、 b が a,c のうち一方と比べて大きく、一方と比べて小さい場合に真値を返す事が出来る。多分最短だとは思うけど、意味的にはちょっと如何かと思う。
アルゴリズムの問題で、多少順番が入れ替わっても処理出来てしまうようですが、一応動いています。以下は (1+2*3.1)+(1.1*4-2)*(3*(5.3-3)) と入力した時の結果。
lex:
Operator : (
Operator : (
Integer : 1
Operator : +
Integer : 2
Operator : *
Decimal : 3.100000
Operator : )
Operator : +
Operator : (
Decimal : 1.100000
Operator : *
Integer : 4
Operator : -
Integer : 2
Operator : )
Operator : *
Operator : (
Integer : 3
Operator : *
Operator : (
Decimal : 5.300000
Operator : -
Integer : 3
Operator : )
Operator : )
Operator : )
parse:
+
+
1
*
2
3.100000
*
-
*
1.100000
4
2
*
3
-
5.300000
3
#define ディレクティブの罠以下のような #define ディレクティブの使い方はバグの原因になる上、原因が分かり難い。
#include <stdio.h>
#define add(a,b) a+b
int main(void)
{
printf("%d\n",add(1,2)*3);
return 0;
}
これを回避する為には、以下のようにする。
#include <stdio.h>
#define add(a,b) (a+b)
int main(void)
{
printf("%d\n",add(1,2)*3);
return 0;
}
また、以下のような場合もバグの原因になる。
#include <stdio.h>
#define mul(a,b) (a*b)
int main(void)
{
printf("%d\n",mul(1+2,3));
return 0;
}
これを回避する為には、以下のようにする。
#include <stdio.h>
#define mul(a,b) ((a)*(b))
int main(void)
{
printf("%d\n",mul(1+2,3));
return 0;
}
LibStack が完成したので、ドキュメントを書く。
ハッシュ関数のアルゴリズムについて調べる。(LibAssocList の高速化に使う。 )
http://monsho.hp.infoseek.co.jp/compile/compile02.html での単項演算子の扱いがおかしいように見える。因みに、サンプルプログラムは正しく動作してくれない。
単項演算子が出現した場合は、開き括弧と同様、優先度に関係無くスタックに積み、比較時の優先度を他の演算子よりも上げておけば良いのではないだろうか。
因みに、コンパイラの構成と最適化の p.13 にも殆ど同じ内容の事が書かれている。
逆ポーランド記法に変換しても色々手を加えるのが面倒になるだけなので、ツリーへの変換方法を書いてくれると嬉しいかも。
LibAssocList に修正を加え、新しいバージョンとして公開する。
LibQueryString とかいうのを作ったので、幾つかの修正を加えた上でドキュメントを書き、公開する。
LibStack を作る。 (中置記法からツリーへの変換に必要。非常に小規模なライブラリなので、単体で公開するとは限らない。)
開発リソースの都合により、1ヶ月以上前に作った物は放置します。
中置記法からツリーへの変換。
連続したメモリ領域上でツリーデータを表現する方法を考える。 (一つ一つのノードに別々のメモリ領域を割り当てるとメモリ効率が悪くなってしまう。優先度低。)