bic : интерпретатор AC и API ExplorerЭтот проект, который позволяет разработчикам исследовать и тестировать C-API с использованием цикла печатной печати Read Eval, также известного как реплика.

Зависимости времени выполнения BIC заключаются в следующем:
Чтобы построить BIC, вам понадобится:
Пожалуйста, убедитесь, что вы установили их перед строительством BIC. Следующая команда должна установить их в систему Debian/Ubuntu:
apt-get установить сборку LibReadline-Dev AutoConf-Archive Libgmp-Dev ожидайте гибкого бизона Automake M4 Libtool Pkg-Config
Вы также можете использовать следующую команду для установки требуемых зависимостей через Homebrew в системе MacOS.
Brew установить Bison Flex Gmp Line AutoConf-Archive
Вы можете скомпилировать и установить BIC со следующими командами:
AutoreConf -i ./configure-enable-debug делать сделать установку
Для создания системы macOS вам необходимо изменить строку настройки на:
Yacc = "$ (brew -prefix bison)/bin/bison -y" ./configure -enable -debug
Вы можете использовать Docker для строительства и запуска BIC со следующей командой:
Docker Build -t BIC https://github.com/hexagonal-sun/bic.git#master
Как только изображение будет построено, вы можете запустить BIC с:
Docker Run -i bic
Если вы используете Arch Linux, вы можете установить BIC из AUR:
Уу -S Бич
При вызове BIC без аргументов пользователю представлено подсказкой для реплики:
BIC>
Здесь вы можете ввести операторы C и #include различные заголовки системы, чтобы обеспечить доступ к различным API в системе. Заявления могут быть введены непосредственно в реплику; Нет необходимости определять функцию для их оценки. Скажем, мы хотим выполнить следующую программу C:
#include <stdio.h>
int main ()
{
FILE * f = fopen ( "out.txt" , "w" );
fputs ( "Hello, world!n" , f );
return 0 ;
}Мы можем сделать это на реплике с BIC, используя следующие команды:
Bic> #include <stdio.h>
Bic> file *f;
фон
Bic> f = fopen ("test.txt", "w");
Bic> fputs ("Привет, мир! N", f);
1
BIC>
Это приведет к тому, что BIC вызывает функции C-library fopen() и fputs() чтобы создать файл и записать в него строку Hello World. Если вы сейчас выходите из BIC, вы должны увидеть файл test.txt в текущем рабочем каталоге со строкой Hello, Worldn содержащимся в нем.
Обратите внимание, что после оценки выражения BIC будет печатать результат оценки. Это может быть полезно для тестирования простых выражений:
Bic> 2 * 8 + fileno (f); 19
Вы можете использовать BIC для получения информации о любой переменной или типе, который был объявлен с префиксом его имени с помощью ? Полем Этот специальный синтаксис работает только в Repl, но позволит вам получить различные характеристики о типах и переменных. Например:
Bic> #include <stdio.h> Bic>? Stdout Stdout - это указатель на struct _io_file. Значение stdout составляет 0x7ff1325bc5c0. sizeof (stdout) = 8 байт. Stdout был объявлен по адресу:/usr/include/stdio.h:138.
Когда заполняет, BIC увидит, существует ли ~/.bic . Если это происходит, это автоматически оценивается, и результирующая среда используется Repl. Это может быть полезно для определения функций или переменных, которые обычно используются. Например, скажем, наш файл ~/.bic содержит:
#include <stdio.h>
int increment ( int a )
{
return a + 1 ;
}
puts ( "Good morning, Dave." );Когда мы запускаем реплику, мы получаем:
$ bic Доброе утро, Дэйв. BIC> Приращение (2); 3
Если вы передаете BIC исходный файл вместе с -s , в качестве аргумента командной строки, он оценит его, вызывая функцию main() . Например, предположим, что у нас есть файл test.c , который содержит следующее:
#include <stdio.h>
int factorial ( int n )
{
if (! n )
{
return 1 ;
}
return n * factorial ( n - 1 );
}
int main ()
{
printf ( "Factorial of 4 is: %dn" , factorial ( 4 ));
return 0 ;
} Затем мы можем вызвать BIC с -s test.c чтобы оценить его:
$ bic -s test.c Фактор 4: 24
Если вы хотите передать аргументы в файл C, добавьте их в командную строку BIC. Как только BIC обработал аргумент -s , все другие аргументы рассматриваются как параметры, которые должны быть переданы в программу. Эти параметры создаются как переменные argc и argv и передаются main() . Значение argv[0] - это имя файла C, который выполняет BIC. Рассмотрим следующую программу C:
#include <stdio.h>
int main ( int argc , char * argv [])
{
for ( int i = 0 ; i < argc ; i ++ )
printf ( "argv[%d] = %sn" , i , argv [ i ]);
return 0 ;
}Если мы не передаем никаких аргументов:
$ bic -s test.c argv [0] = test.c
Принимая во внимание, что если мы вызовым BIC с большим количеством аргументов, они передаются в программу:
$ bic -s test.c -a foo -s bar abc argv [0] = test.c argv [1] = -a argv [2] = foo argv [3] = -s argv [4] = бар argv [5] = a argv [6] = b argv [7] = c
Вы также можете использовать специальное выражение: <REPL>; В вашем исходном коде, чтобы BIC бросил вас в повторную репутацию в определенной точке оценки файла:

Вы можете использовать BIC для изучения API других библиотек, кроме LIBC. Предположим, мы хотим изучить библиотеку Capstone, мы передаем опцию -l , чтобы сделать эту библиотеку, когда она начинается. Например:

Обратите внимание, что когда BIC печатает составной тип данных ( struct или union ), он показывает все имена членов и их соответствующие значения.
В основе реализации BIC лежит объект tree . Это общие объекты, которые можно использовать для представления всей программы, а также текущего состояния оценщика. Он реализован в tree.h и tree.c Каждый тип дерева определяется в c.lang . Файл c.lang представляет собой LISP-подобную спецификацию:
T_ADD .Addition .tADD .LHS и RHS .Код для создания объекта с приведенным выше набором атрибутов будет:
( deftype T_ADD " Addition " " tADD "
( " LHS " " RHS " ))После определения мы можем использовать этот объект в нашем коде C следующим образом:
tree make_increment ( tree number )
{
tree add = tree_make ( T_ADD );
tADD_LHS ( add ) = number ;
tADD_RHS ( add ) = tree_make_const_int ( 1 );
return add ;
} Обратите внимание, что набор аксессуаров Macros, tADD_LHS() и tADD_RHS() , был сгенерирован для нас для доступа к различным слотам свойств. Когда --enable-debug установлен во время компиляции, каждый из этих макросов расширяется на проверку, чтобы убедиться, что при установке свойства tADD_LHS объекта действительно является экземпляром T_ADD .
Файл c.lang читается многочисленными компиляторами источника к источникам, которые генерируют фрагменты кода. Эти коммунальные услуги включают в себя:
gentype : генерирует список типов объектов дерева.gentree : генерирует структуру, которая содержит все данные свойства для объектов деревьев.genctypes : генерирует список объектов дерева C -типа - они представляют фундаментальные типы данных в C.genaccess : генерируйте макросы доступа для свойств объекта дерева.gengc : генерируйте функцию MANK для каждого объекта дерева, это позволяет коллекционеру мусора проходить деревья объектов.gendump : генерируйте код, чтобы рекурсивно выпускать объекты дерева.gendot : генерируйте точечный файл для данной иерархии tree , позволяя его визуализировать. Вывод Lexer & Parser - это иерархия объекта tree , которая затем передается в оценщик ( evaluator.c ). Затем оценщик будет рекурсивно оценивать каждый элемент дерева, обновляя состояние внутреннего оценщика, тем самым выполняя программу.
Призывы к функциям, внешним по отношению к оценщику, обрабатываются в зависимости от платформы. В настоящее время x86_64 и AARCH64 являются единственными поддерживаемыми платформами, и код для обработки этого находится в папках x86_64 и aarch64 соответственно. Это работает, взяв объект tree вызовов функции (представленным T_FN_CALL ) из оценщика со всеми оцениваемыми аргументами и внедрением их в простой связанный список. Затем это пересекается в сборке, чтобы переместить значение в правильный регистр в соответствии с вызовом x86_64 или AARCH64, а затем разветвляется по адресу функции.
Парсер и лексер реализованы в parser.m4 и lex.m4 соответственно. После прохождения M4 вывод составляет два анализатора бизонов и два гибких лексеры.
Причина двух анализаторов заключается в том, что грамматика для C Spurp сильно отличается от грамма C -файла. Например, мы хотим, чтобы пользователь имел возможность вводить операторы, которые будут оцениваться на перепис без необходимости обернуть их в функцию. К сожалению, написание заявления, которое выходит за пределы функционального тела недопустимо, C. Таким образом, мы не хотим, чтобы пользователь мог писать заявления в файле C. Для достижения этого у нас есть два разных набора правил грамматики, которые производят два анализатора. Большинство правил грамматики перекрываются, и поэтому мы используем один файл M4, чтобы заботиться о различиях.