FORTH
Как я писал форт "за вечер"/как рекомендую это делать:
там всего несколько вариантов для самого начала:
1) компиляция в байткод — я использовал, довольно приятно.
2) интерпретация — не так приятно потому что контекст меняется, но легко делается поверх (1) потом.
3) компиляция в машинный код — сложно с поддержкой потом, ну разве только LLVM взять.
Также надо определиться с форматом шитого кода, реализациями словарей и стеков.
Дальше ерунда, взял во входном потоке слово, нашёл в словаре, иначе — ошибка. Если слово нативное (реализованное тобой на языке реализации) — вызвал стандартным механизмом языка, если нет — послал туда интерпретатор байткода если (1), просто интерпретатор если (2), ну а если (3) то все слова нативные. Дли ненативных слов не забываем слежить за стеком возвратов.
эм.. по большей части всё. Для реализации нативных слов не помешают функции работы со входным потоком и управлением интерпретатором. Байткод не жадитесь, берите от 32 бит на команду — что не потратите эффективно, сожмёт архиватор.
конкретнее можно спрашивать в комментариях.