Да на SICP.
Я выполнил эту задачу несколько раз, и вот что я бы сделал на вашем месте:
Сначала создайте модель памяти. Вы будете хотеть систему GC некоторого вида. Сначала проще сделать это, чем потом прикрутить.
Дизайн ваших структур данных. В моих реализациях у меня был базовый минус с несколькими базовыми типами: атом, строка, число, список, bool, примитивная функция.
Создайте свою виртуальную машину и не забывайте поддерживать API в чистоте. В моей последней реализации это было API-интерфейсом верхнего уровня (простите за форматирование - так что мой просмотр превосходит)
ConsBoxFactory &GetConsBoxFactory() { return mConsFactory; }
AtomFactory &GetAtomFactory() { return mAtomFactory; }
Environment &GetEnvironment() { return mEnvironment; }
t_ConsBox *Read(iostream &stm);
t_ConsBox *Eval(t_ConsBox *box);
void Print(basic_ostream<char> &stm, t_ConsBox *box);
void RunProgram(char *program);
void RunProgram(iostream &stm);
RunProgram не нужен - он реализован в терминах Read, Eval и Print. REPL - это общая схема для переводчиков, особенно LISP.
Доступен ConsBoxFactory для создания новых коробок с минусами и работы с ними. AtomFactory используется так, чтобы эквивалентные символические атомы отображались точно на один объект. Среда используется для поддержания привязки символов к минусам.
Большая часть вашей работы должна идти в эти три шага. Тогда вы обнаружите, что ваш клиентский код и код поддержки начинают очень похожи на LISP:
t_ConsBox *ConsBoxFactory::Cadr(t_ConsBox *list)
{
return Car(Cdr(list));
}
Вы можете написать анализатор в yacc / lex, но зачем? Lisp - невероятно простая пара грамматики и сканера / рекурсивного спуска, для которой требуется около двух часов работы. Хуже всего - написание предикатов для идентификации токенов (т. Е. IsString, IsNumber, IsQuotedExpr и т. Д.), А затем написание подпрограмм для преобразования токенов в блоки cons.
Упростите написание клея в коде C и из него и упростите отладку проблем, когда что-то пойдет не так.