Cha*_*azu 2 c++ common-lisp ecl
我正在努力将Embeddable Common Lisp嵌入到库中,我一直在编写实用程序函数来将ECL转换cl_object为各种C/C++类型 - 例如将cl_object表示字符串转换为std :: string.
我的问题是这个 - 为什么我没能在ECL中检索包含符号名称的字符串?
我无法使用以下函数ecl_symbol_to_string,它应该使用ECL符号并返回带有它名称的std :: string:
string ecl_symbol_to_string(cl_object sym) {
return ecl_string_to_string(sym->symbol.name);
}
string ecl_string_to_string(cl_object echar) {
string res("");
int j = echar->string.dim; //get dimension
ecl_character* selv = echar->string.self; //get pointer
//do simple pointer addition
for(int i=0;i<j;i++){
res += (*(selv+i));
}
return res;
};
Run Code Online (Sandbox Code Playgroud)
请注意,ecl_string_to_string适用于lisp字符串.
一个简单的单元测试说明了失败:
TEST_CASE( "ecl_symbol_to_string returns a string for symbol",
"[ecl_string_to_string]" ) {
LispRuntime *rt = new LispRuntime("()");
std::string eval_script;
cl_object eval_result;
std::string subject_result;
eval_script = "'mysymbol";
eval_result = rt->evaluate(eval_script);
REQUIRE( ECL_SYMBOLP(eval_result) );
subject_result = ecl_symbol_to_string(eval_result);
REQUIRE ( ECL_STRINGP(cl_symbol_name(eval_result)) );
std::cout << subject_result.c_str() << std::endl;
REQUIRE( subject_result.compare("mysymbol") == 0 );
delete rt;
}
Run Code Online (Sandbox Code Playgroud)
此测试用例打印出来MM用于调用cout.我也试过比较"失败"的"MYSYMBOL"和"M".
LispRuntime :: eval_script只是转换和评估表单:
cl_object LispRuntime::evaluate(std::string &code) {
cl_object form = c_string_to_object(code.c_str());
cl_object result = cl_eval(form);
return result;
}
Run Code Online (Sandbox Code Playgroud)
我在本地编译了ECL版本16.1.3并启用了C++选项,调试符号和所有其他设置都是默认的.非常感谢任何帮助.
我相信这是一个unicode /非unicode混淆:ECL在object.h中定义了两种字符串类型.一个是ecl_base_string,成员self最终typedef到a unsigned char*,另一个是ecl_string成员self通常(根据编译时参数,我认为)typedef到a int*.你正在访问它ecl_string.
如果你追踪你的工作,ecl_make_symbol发现它最终调用make_constant_base_string返回基本字符串的函数.因此,您ecl_string_to_string通过错误的类型访问它.
我怀疑最简单的解决方案是将类型检查/转换构建为ecl_string_to_string:
string ecl_string_to_string(cl_object echar) {
switch (ecl_t_of(echar)) {
#ifdef ECL_UNICODE
case t_string:
if (!ecl_fits_in_base_string(echar)) {
echar = cl_copy_seq(echar);
} else {
echar = si_copy_to_simple_base_string(echar);
}
break;
#endif
case t_base_string:
// OK
break;
default:
// PRINT SOME ERROR
return string(); // or raise an exception
}
string res("");
int j = echar->base_string.dim; //get dimension
ecl_base_char* selv = echar->base_string.self; //get pointer
//do simple pointer addition
for(int i=0;i<j;i++){
res += (*(selv+i));
}
return res;
};
Run Code Online (Sandbox Code Playgroud)
我添加的额外代码是从ECL函数中大量复制的cl_make_symbol.我决定转换为ecl_base_string而不是ecl_string因为C++字符串无论如何都不会接受unicode字符.如果你有充分的理由,你可以反过来做.