2

我正在将 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;
};

请注意,这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;

}

此测试用例会打印出来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;
}

我在本地编译了 ECL 版本 16.1.3,启用了 C++ 选项、调试符号和所有其他默认设置。非常感谢任何帮助。

4

1 回答 1

5

我相信这是 unicode/non-unicode 的混淆:ECL 在object.h中定义了两种字符串类型。一个是ecl_base_string,成员self最终 typedef 到 anunsigned 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;
};

我添加的额外代码大量复制自 ECL 函数cl_make_symbol。我决定转换为,ecl_base_string而不是ecl_string因为 C++ 字符串无论如何都不会接受 unicode 字符。如果你有充分的理由,你可能会反过来做。

于 2017-01-30T11:38:02.593 回答