简体   繁体   English

在C ++中将ECL符号名称获取为字符串

[英]Getting ECL symbol name as string in C++

I'm working on embedding Embeddable Common Lisp into a library and I've been writing utility functions to convert ECL's cl_object to various C/C++ types - eg to convert a cl_object representing a string to a std::string. 我正在将Embeddable Common Lisp嵌入到库中,并且我一直在编写实用程序函数以将ECL的cl_object转换为各种C / C ++类型-例如,将表示字符串的cl_object转换为std :: string。

My question is this - why am I failing to retrieve a string containing the name of a symbol in ECL? 我的问题是-为什么我无法在ECL中检索包含符号名称的字符串?

I'm having trouble getting the following function ecl_symbol_to_string to work, which should take an ECL symbol and return a std::string with it's name: 我在使以下函数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;
};

Note that ecl_string_to_string works for lisp strings. 请注意, ecl_string_to_string适用于ecl_string_to_string字符串。

A simple unit test illustrates the failure: 一个简单的单元测试说明了失败:

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;

}

This test case prints out MM for the call to cout. 该测试用例打印出MM ,以调用cout。 I have also tried comparing to "MYSYMBOL", which fails, and "M" which passes. 我还尝试过比较失败的“ MYSYMBOL”和通过的“ M”。

LispRuntime::eval_script simply converts and evaluates the form: 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;
}

I compiled ECL version 16.1.3 locally with the C++ option enabled, with debugging symbols and with all other settings default. 我在本地启用了C ++选项,调试符号和所有其他默认设置的情况下编译了ECL 16.1.3版。 Any assistance is greatly appreciated. 非常感谢您的协助。

I believe this is a unicode/non-unicode mix-up: ECL defines two string types in object.h . 我相信这是Unicode /非Unicode的混合体:ECL在object.h中定义了两种字符串类型。 One is ecl_base_string , where the member self ultimately typedefs to an unsigned char* and the other is ecl_string where the member self usually (depending on compile time arguments, I think) typedefs to a int* . 一个是ecl_base_string ,其中成员self最终将typedef定义为一个unsigned char* ,另一个是ecl_string ,其中成员self通常将ecl_string定义为一个int* (取决于编译时参数)。 You're accessing it as an ecl_string . 您正在作为ecl_string访问它。

If you trace through the workings of ecl_make_symbol you find it ends up calling the function make_constant_base_string which returns a base string. 如果跟踪ecl_make_symbol的工作原理,您会发现它最终调用了函数make_constant_base_string ,该函数返回一个基本字符串。 Thus your ecl_string_to_string accesses it through the wrong type. 因此,您的ecl_string_to_string通过错误的类型进行访问。

I suspect the easiest solution is to build a type-check/conversion into 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;
};

The extra code I've added was heavily copied from the ECL function cl_make_symbol . 我添加的额外代码是从ECL函数cl_make_symbol大量复制的。 I decided to convert to ecl_base_string rather than ecl_string since the C++ string won't accept unicode characters anyway. 我决定转换为ecl_base_string而不是ecl_string因为C ++字符串无论如何都不接受unicode字符。 You could probably do it the other way round if you had good reason to. 如果您有充分的理由,则可以采取另一种方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM