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;
};

Обратите внимание, что 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 для вызова кут. Я также попытался сравнить с «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;
}

Я скомпилировал версию 16.1.3 ECL локально с включенной опцией C ++, с символами отладки и другими настройками по умолчанию. Любая помощь очень ценится.

2

Решение

Я считаю, что это смешивание Unicode / не-Unicode: ECL определяет два типа строк в object.h. Один ecl_base_stringгде член self в конечном счете typedefs к unsigned char* а другой ecl_string где член self обычно (в зависимости от аргументов времени компиляции, я думаю) typedefs для 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 ++ в любом случае не будет принимать символы Юникода. Вы могли бы сделать это наоборот, если бы у вас были для этого веские основания.

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]