bic :AC解釋器和API Explorer這個項目允許開發人員使用讀取的評估打印循環(也稱為REPL)探索和測試C-apis。

BIC的運行時間依賴項如下:
要構建BIC,您需要:
請在建造BIC之前確保已安裝這些內容。以下命令應將其安裝在Debian/Ubuntu系統上:
apt-get安裝build-Ender-exental libreadline-dev autoconf-arconf-arpgmp-dev期望flex bison automake m4 libtool pkg-config
您還可以使用以下命令通過MacOS系統上的Homebrew安裝所需的依賴項。
啤酒安裝野牛flex GMP讀取線AutoConf-Archive
您可以使用以下命令編譯並安裝BIC:
autoreconf -i ./configure-啟用 製作 進行安裝
對於MacOS系統上的構建,您需要將配置行更改為:
yacc =“ $(Brew -Prefix Bison)/bin/bish -y” ./configure -enable -debug
您可以使用Docker構建和運行以下命令:
docker build -t bic https://github.com/hexagonal-sun/bic.git#master
一旦構建圖像,您就可以使用BIC運行:
Docker Run -I BIC
如果您使用的是Arch Linux,則可以從AUR中安裝BIC:
是的-s bic
當沒有參數的BIC調用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進行此操作:
bic> #include <stdio.h> bic> file *f; 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獲取有關通過將其名稱前綴為A的任何變量或類型的信息? 。該特殊語法僅在臥底中起作用,但允許您獲得有關類型和變量的各種特徵。例如:
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." );當我們啟動depl時,我們會得到:
$ 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 ;
}然後,我們可以通過-s test.c調用BIC來評估它:
$ bic -s test.c 4的階乘是:24
如果您希望將論證傳遞到C文件,請將其附加到BIC的命令行。一旦BIC處理了-s參數,所有其他參數都被視為要將其傳遞給程序的參數。這些參數是作為argc和argv變量創建的,並傳遞到main() 。 argv[0]的值是BIC執行的C文件的名稱。考慮以下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] = bar argv [5] = a argv [6] = b argv [7] = c
您也可以使用特殊表達式: <REPL>;在您的源代碼中,使BIC在文件評估中的特定點將您置於REPL:

您可以使用BIC探索LIBC以外的其他庫的API。假設我們希望探索Capstone庫,我們通過-l選項,在啟動時將其庫進行biC負載。例如:

請注意,當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 ;
}請注意,已經生成了一組訪問器宏, tADD_LHS()和tADD_RHS() ,以供我們訪問其他屬性插槽。當在編譯過程中設置--enable-debug時,這些宏中的每個宏都會擴展到檢查中,以確保在設置對象的tADD_LHS屬性時,該對象確實是T_ADD的實例。
c.lang文件由許多生成代碼段的源代碼編譯器讀取。這些公用事業包括:
gentype :生成樹對像類型的列表。gentree :生成一個包含樹對象的所有屬性數據的結構。genctypes :生成C型樹對象的列表 - 這些代表C中的基本數據類型。genaccess :生成樹對象屬性的訪問宏。gengc :為每個樹對像生成標記函數,這允許垃圾收集器穿越對象樹。gendump :生成代碼以遞歸倒入樹對象。gendot :為給定的tree層次結構生成一個點文件,從而使其可視化。Lexer&Parser的輸出是tree對象層次結構,然後將其傳遞到評估器( evaluator.c )中。然後,評估者將遞歸評估每個樹元素,更新內部評估器狀態,從而執行程序。
評估器外部功能的呼叫以平台依賴性方式處理。當前,X86_64和AARCH64是唯一受支持的平台,處理此問題的代碼分別在x86_64和aarch64文件夾中。這是通過從評估器中獲取函數調用tree對象(由T_FN_CALL代表)的函數調用樹對象,並對所有參數進行了評估並將其編碼為簡單的鏈接列表。然後將其在彙編中遍歷,以根據X86_64或AARCH64調用contentions將值移至正確的寄存器中,然後分支到函數地址。
解析器和Lexer分別在parser.m4和lex.m4中實現。通過M4後,輸出是兩個野牛解析器和兩個彎曲詞。
兩個解析器的原因是,c repl的語法與c文件的語法大不相同。例如,我們希望用戶能夠在REPP上評估語句,而無需將其包裝在功能中。不幸的是,編寫一個函數外部的語句是無效的。因此,我們不希望用戶能夠在c文件中編寫裸語句。為了實現這一目標,我們有兩套不同的語法規則,它們產生了兩個解析器。大多數語法規則都重疊,因此我們使用單個M4文件來照顧差異。