事の発端は、boost::spirit::qi で utf-8 のコードをパースしようとした事から始まった。
最初は、boost::spirit::ascii::space_type を使ってみたんですわ。ところが、どうも ASSERTION に引っかかる。どうやら、マルチバイトセット系は boost::spirit::standard 系を指定しろという話らしいんで、boost::spirit::standard::space_type を使うように切り替えてみたんですわ。mac 上のgcc でコンパイルしてみて通る感じだったんで、まぁ、いいのかな?と思ってました。
ところが、VCのデバッグ環境で、isctype.c Expression: (unsigned)(c + 1) <= 256 とか言うのに引っかかるみたいなんですわ。
もしかして、なんか全然違うところでロケールの設定をしておかないといけないのかな?って、嫌ーな気持ちになりました。とりあえず、この辺でぐぐってみると、目についたのは、この辺の議論
http://boost.2283326.n4.nabble.com/Spirit-Qi-How-do-I-use-UTF-8-encoding-with-Qi-td2683321.html
他には
https://svn.boost.org/trac/boost/ticket/5086
あー、やっぱりかーというような対処方法。
遠い過去の記憶が蘇ってきました。
http://ml.tietew.jp/cppll/cppll/thread_articles/123
やっぱ地雷臭がプンプン・・・。char 型の符号の定義自体が曖昧なんで、気持ち悪さも加速していると思います。
ごちゃごちゃ考えてても目の前の現実には向き合わないといけないので、boost/spirit/home/support/char_encoding/standard.hpp を眺めてみました。
...
struct standard
{
typedef char char_type;
static bool
isascii_(int ch)
{
return 0 == (ch & ~0x7f);
}
static bool
ischar(int ch)
{
// uses all 8 bits
// we have to watch out for sign extensions
return (0 == (ch & ~0xff) || ~0 == (ch | 0xff)) ? true : false;
}
static int
isalnum(int ch)
{
return std::isalnum(ch);
}
static int
isalpha(int ch)
{
return std::isalpha(ch);
}
...
ぬぉおおおお、char 型から、int 型へキャストする時点で、もうオーバーフローしてるやん・・・。入り口が、あちこちに分散・・・。悲惨な状況・・・。UTF-8では、そもそも、8bit目以後ならば、false になる事が確定するので、
if( ch >= 128 ) return false;
してしまう?それとも、地雷臭漂うロケールでも設定してみる?思うんだけど、この辺の is* 系って、そろそろ UTF-8 が標準の考え方でも全然差し支え無いんと違うのかな?
追記: 問題のパーサのコードは、
こちら
更に追記:
どうもやっぱ この standard.hpp の部分
以外で引っかかって
いる用であるいた。ちゃんとデバッガ使って、コールスタック調べる事にしよう…。リリース版で実行すると、特に弊害は無いように見える。
更に追記:vc9 で確認した。以下のような修正を入れるのがベストなのかどうか?
is* 系に対しては、とする。
static int
isalnum(int ch)
{
// return std::isalnum(ch);
return std::isalnum((ch < 0) ? 0 : ch);
}
0 件のコメント:
コメントを投稿