Как стать автором
Обновить

CPrompt — интерпретатор языка си

Время на прочтение3 мин
Количество просмотров6.9K
С июня 2009 года я занимаюсь разработкой интерпретатора Си. (я уже упоминал об этом в статье о вызовах функций).
Сейчас уже реализовано достаточно много конструкций: циклы, выбор, вычисление выражений, вызовы функций (как объявленных пользователем, так и стандартных), инклуды и другое.

Название CPrompt программа получила по аналогии с «prompt» — приглашением командной строки (D:>, root@comp#, ...).

Немного о работе самого интерпретатора


Запуск на интерпретацию файла с исходным кодом делается просто:
$cprompt /path/to/file.c

Интерпретация разделена на 3 этапа:
1) Препроцессинг
2) Построение дерева выполнения
3) Вызов main()

Первый этап, препроцессинг, важный и скучный: обрабатывает инклуды, дефайны, комментарии и другое.
На выходе — чистый код, без директив и лишнего текста.

Второй этап — построение дерева выполнения. Тут берется код и строится граф (дерево), в корне которого лежит некий объект APPLICATION, который содержит информацию о запускаемом файле. В поддеревьях — функции, каждая лексема переходит в элемент дерева. Каждый элемент графа имеет свой «тип» — число, которое показывает его предназначение.
Функции делятся на 2 типа — объявленные пользователем и «внешние». Последние — например, стандартные из libc, из других разделяемых библиотек.

На выходе получается дерево, подобное этому:

Tree was built:
t0;APPLICATION;;;
| t0;FUNCTIONS;;;
| | t14;double;cos;;
| | t14;double;floor;;
| | t14;int;isdigit;;

| | t2;double;round;;
| | | t5;floor(value+0.5);;;
| | t14;int;printf;;
| | t2;int;main;;
| | | t1;int;l;round(7.2);

(это часть лога, который выводит интерпретатор).
t0, t2, t14 — тип элементов.
0 — без типа
1 — выражение (присвоение считается одной из операций, наравне с +,-,*… но в другом приоритете).
2 — функция
5 — «return»
14 — «внешняя функция»,
И другие, для разных действий.
Аргументы к функциям хранятся в структурах, поэтому их нет в видимой части дерева. На самом деле указатели на них прописаны в в каждой ветке функции.

Все выполнение программы логируется очень подробно — при указании параметра --dbg выводит в стандартный вывод много информации.
Если посмотреть лог, то вы заметите что выполнение разделено на 5 пунктов, а не на 3 как я говорил в начале. Два пункта — перед препроцессингом и после — это парсинг исходного текста. Парсинг перед обработкой — и разбор обработанного текста.

Единственный выход за рамки стандарта, который я себе позволил — добавил конструкцию «outside», которая ввиду невозможности статической линковки позволяет объявлять функции из внешних библиотек. Сейчас возможно объявить только те функции, с библиотеками которых был собран интерпретатор, но в будущем будет возможность импорта из разделяемых библиотек.
Например,
outside cdecl: double cos(double x);
outside cdecl: double floor(double x);

Где cdecl — соглашение вызова функции. Подробнее о таком вызове функций.

Пишется продукт на С++.
Посмотреть или скачать исходный код (Google Code).
Надеюсь, скоро появится рабочий релиз продукта, который можно будет использовать, так как с каждым днем я всё ближе приближаюсь к стандарту. Конечная цель — полная поддержка C99.

Пример


#include <cmath>

int main(int argv,char* argc[])
{
int l=round(7.2);
}

На такой код лог будет таким.
Много лишнего, но при желании разобрать можно.
А какие ваши варианты использования интерпретатора си? Где бы можно было применить этот продукт?

UPD перенес в Языки программирования
UPD2 Добавил в репозиторий make-файл.
Для компиляции:
svn checkout cprompt.googlecode.com/svn/trunk/ cprompt
cd cprompt
make

и запускаем ./cprompt /path/to/file
Теги:
Хабы:
Всего голосов 50: ↑38 и ↓12+26
Комментарии74

Публикации

Истории

Ближайшие события

15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань