Но, подозреваю, однажды выяснится, что одним массивом не обойтись и нужно заводить какую-то параллельную структуру данных для хранения чего-нибудь типа списка (или таблицы) встроенных констанкт, функций и операторов - я не хочу тратить драгоценное ОЗУ контроллера для хранения того, что всё равно не меняется (подобные вещи можно и нужно хранить в памяти программ, всегда).
Пока пишу код мелкими кусочками, отлаживая и исследуя его поведение. Вот, например, обобщённые функции получения данных атома по его индексу и копирования атома:
void* data_of(uclptr_t atom) { int type_id = CAR(atom); int type_valid = (type_id <= TYPES_TOTAL); return (void*)((type_valid && (UCL_Types[type_id].data != 0)) ? UCL_Types[type_id].data(atom) : 0); } uclptr_t copy_atom (uclptr_t original) { uclptr_t n = cell_alloc(); if (!IS_NIL(n)) { int type_id; int type_valid = ((CAR(n) = (type_id = CAR(original))) <= TYPES_TOTAL); void *sample_data = (void*)((type_valid && (UCL_Types[type_id].data != 0)) ? UCL_Types[type_id].data(original) : 0); CDR(n) = (type_valid && (UCL_Types[type_id].create != 0)) ? UCL_Types[type_id].create(sample_data) : NIL; TAG(n) = TAG_ATOM; return n; } else { return NIL; }; }
Люблю, знаете ли, такой вот вырвиглазный стиль, делающий из старого доброго Си ужасающую мешанину скобок, точек, амперсандов, звёздочек и прочего мусора, за который почему-то не любят простой и прозрачный синтаксис Лиспа.
Простенькая защита от дурака присутствует. Работает, прикольно. Во второй функции можно было бы вставить вызов data_of, но тогда два раза вычислялось бы значение флага type_valid, а зачем мне такие сложности?