我正在编写lambda演算解释器,以获取乐趣和实践经验。我通过添加ctype
构面(将标点符号定义为空格)来使iostream正确地标记标识符:
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 );
网上似乎很少有lambda演算代码。到目前为止,我发现的大部分内容都是unicode
λ
字符。因此,我想尝试添加Unicode支持。但是
ctype<wchar_t>
的工作原理与ctype<char>
完全不同。没有主表;共有四种方法do_is
x2,do_scan_is
和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
在这里是无关紧要的,但我的思考范围更广。)首先我是在滥用构面吗?以上甚至正确吗?实现更少的逻辑会是更好的样式吗? 最佳答案
(这是一年,没有实质性的回答,与此同时,我已经了解了很多有关iostream的知识……)
定制方面专门用于服务于字符串提取运算符in >> token
。该运算符是根据use_facet< ctype< wchar_t > >( in.getloc() ).is( ios::space, c )
“针对下一个可用的输入字符c”定义的。 (第21.3.7.9节)ctype::is
只是ctype::do_is
的 stub ,因此do_is
似乎就足够了。
尽管如此,最新版本的GCC标准库确实根据operator>>
实现了scan_is
。要注意的是,然后将do_scan_is
实现为对do_is
,虚拟调度等的所有调用。头文件将do_scan_is
描述为用户优化的钩子(Hook)。
因此,似乎该规则包含了仅提供第一个替代的实现。
请注意,第二个替代值(用于检索掩码值)是一个奇怪的值。可以首先通过低效率地逐步构建掩码来实现它。在GCC中,它是根据系统调用来实现的,没有效率地逐位构建掩码,每个字符15个调用。这似乎牺牲了性能和兼容性。幸运的是,似乎没有人使用它。
无论如何,这一切都很好,但是使用streambuf_iterator<wchar_t>
编写 token 生成器更容易,可扩展得多,并且简化了异常处理。