8

私は楽しみと練習のためにラムダ計算インタープリターを書いています。ctype句読点を空白として定義するファセットを追加することにより、iostreamsが識別子を適切にトークン化するようにしました。

struct token_ctype : ctype<char> {
 mask t[ table_size ];
 token_ctype()
 : ctype<char>( t ) {
  for ( size_t tx = 0; tx < table_size; ++ tx ) {
   t[tx] = isalnum( tx )? alnum : space;
  }
 }
};

classic_table()おそらくもっときれいでしょうが、それはOS Xでは機能しません!)

そして、識別子をヒットしたときにファセットを交換します。

locale token_loc( in.getloc(), new token_ctype );
…
locale const &oldloc = in.imbue( token_loc );
in.unget() >> token;
in.imbue( oldloc );

Web上には驚くほどラムダ計算コードがほとんどないようです。私がこれまでに見つけたもののほとんどは、Unicode λ文字でいっぱいです。そこで、Unicodeサポートを追加してみようと思いました。

ただし、ctype<wchar_t>とはまったく異なる動作をしctype<char>ます。マスターテーブルはありません。do_isx2 、、、do_scan_isおよびの4つのメソッドがありdo_scan_notます。だから私はこれをしました:

struct token_ctype : ctype< wchar_t > {
 typedef ctype<wchar_t> base;

 bool do_is( mask m, char_type c ) const {
  return base::do_is(m,c)
  || (m&space) && ( base::do_is(punct,c) || c == L'λ' );
 }

 const char_type* do_is
  (const char_type* lo, const char_type* hi, mask* vec) const {
  base::do_is(lo,hi,vec);
  for ( mask *vp = vec; lo != hi; ++ vp, ++ lo ) {
   if ( *vp & punct || *lo == L'λ' ) *vp |= space;
  }
  return hi;
 }

 const char_type *do_scan_is
  (mask m, const char_type* lo, const char_type* hi) const {
  if ( m & space ) m |= punct;
  hi = do_scan_is(m,lo,hi);
  if ( m & space ) hi = find( lo, hi, L'λ' );
  return hi;
 }

 const char_type *do_scan_not
  (mask m, const char_type* lo, const char_type* hi) const {
  if ( m & space ) {
   m |= punct;
   while ( * ( lo = base::do_scan_not(m,lo,hi) ) == L'λ' && lo != hi )
    ++ lo;
   return lo;
  }
  return base::do_scan_not(m,lo,hi);
 }
};

(フラットフォーマットについてお詫びします。プレビューではタブの変換が異なります。)

コードはあまりエレガントではありません。句読点だけが追加の空白であるという概念をより適切に表現しますが、私が持っていれば、それは元の形式では問題ありませんでしたclassic_table

これを行うためのより簡単な方法はありますか?私は本当にそれらすべての過負荷が必要ですか?(ここで示されたテストdo_scan_notは無関係ですが、私はもっと広く考えています。)そもそも私はファセットを悪用していますか?上記も正しいですか?より少ないロジックを実装する方が良いスタイルでしょうか?

4

2 に答える 2

3

(実質的な回答がない1年でしたが、その間にiostreamについて多くのことを学びました…)

カスタムファセットは、文字列抽出演算子を提供するためだけに存在しますin >> tokenuse_facet< ctype< wchar_t > >( in.getloc() ).is( ios::space, c )その演算子は、 「次に使用可能な入力文字cに対して」という観点から定義されます。(§21.3.7.9)ctype::isは単にのスタブであるためctype::do_is、それでdo_is十分と思われます。

それにもかかわらず、GCC標準ライブラリの最近のバージョンは、のoperator>>観点から実装されていscan_isます。キャッチは、仮想ディスパッチおよびすべてdo_scan_isへの一連の呼び出しとして実装されることです。do_isヘッダーファイルはdo_scan_is、ユーザー最適化のフックとして記述されています。

したがって、as-ifルールは、最初のオーバーライドのみを提供する実装を保護しているように見えます。

マスク値を取得する2番目のオーバーライドは、奇妙なものであることに注意してください。マスクをビットごとに非効率的に構築することにより、最初の観点から実装できます。GCCでは、システムコールの観点から実装されており、1文字あたり15回の呼び出しで、マスクをビットごとに非効率的に構築します。これにより、パフォーマンスと互換性の両方が犠牲になるようです。幸いなことに、誰もそれを使用していないようです。


とにかく、これはすべてうまくいきますが、を使用してトークナイザーを作成するstreambuf_iterator<wchar_t>方が簡単で、はるかに拡張可能であり、例外処理が簡素化されます。

于 2011-07-05T06:56:32.507 に答える
2

私見あなたが投稿したコードは大丈夫です。より単純なコードが必要な場合は(おそらく効率を犠牲にして)、他のメソッドを使用していくつかのメソッドを実装できますが、それを実行した方法は問題ありません。

格差は、人々がUNICODEプログラムに数メガバイトのテーブルを持ちたくないという事実に基づいています。

于 2010-03-25T00:22:34.943 に答える