{"id":13438545,"url":"https://github.com/hexagonal-sun/bic","last_synced_at":"2025-10-21T04:06:09.742Z","repository":{"id":35072787,"uuid":"39220207","full_name":"hexagonal-sun/bic","owner":"hexagonal-sun","description":"A C interpreter and API explorer.","archived":false,"fork":false,"pushed_at":"2022-02-16T07:50:04.000Z","size":1015,"stargazers_count":803,"open_issues_count":9,"forks_count":40,"subscribers_count":21,"default_branch":"master","last_synced_at":"2024-04-24T14:51:48.453Z","etag":null,"topics":["c","compiler","evaluator","interpreter","repl"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hexagonal-sun.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-07-16T20:58:57.000Z","updated_at":"2024-04-17T23:47:50.000Z","dependencies_parsed_at":"2022-09-16T10:50:49.005Z","dependency_job_id":null,"html_url":"https://github.com/hexagonal-sun/bic","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hexagonal-sun%2Fbic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hexagonal-sun%2Fbic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hexagonal-sun%2Fbic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hexagonal-sun%2Fbic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hexagonal-sun","download_url":"https://codeload.github.com/hexagonal-sun/bic/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244564905,"owners_count":20473155,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","compiler","evaluator","interpreter","repl"],"created_at":"2024-07-31T03:01:06.347Z","updated_at":"2025-10-21T04:06:09.635Z","avatar_url":"https://github.com/hexagonal-sun.png","language":"C","readme":"* ~bic~: A C interpreter and API explorer\n\n  [[https://travis-ci.org/hexagonal-sun/bic][https://travis-ci.org/hexagonal-sun/bic.svg?branch=master]]\n\n  This a project that allows developers to explore and test C-APIs using a read\n  eval print loop, also known as a REPL.\n\n  [[file:doc/img/hello-world.gif]]\n\n** Dependencies\n   BIC's run-time dependencies are as follows:\n   - [[https://tiswww.case.edu/php/chet/readline/rltop.html][GNU Readline]]\n   - [[https://gmplib.org/][GNU MP]]\n\n   To build BIC, you'll need:\n   - [[https://github.com/westes/flex][Flex]]\n   - [[https://www.gnu.org/software/bison/][GNU Bison]]\n   - [[https://www.gnu.org/software/automake/][GNU Automake]]\n   - [[https://www.gnu.org/software/m4/][GNU M4]]\n   - [[https://www.gnu.org/software/autoconf-archive/][GNU Autoconf Archive]]\n\n   Please ensure you have these installed before building bic. The following\n   command should install these on a Debian/Ubuntu system:\n\n   #+begin_example\napt-get install build-essential libreadline-dev autoconf-archive libgmp-dev expect flex bison automake m4 libtool pkg-config\n   #+end_example\n\n   You can also use the following command to install the required dependencies\n   via [[https://brew.sh/][Homebrew]] on a MacOS system.\n   #+begin_example\nbrew install bison flex gmp readline autoconf-archive\n   #+end_example\n\n** Installation\n   You can compile and install bic with the following commands:\n\n#+begin_example\nautoreconf -i\n./configure --enable-debug\nmake\nmake install\n#+end_example\n\n    For building on a MacOS system, you need to change the configure line to:\n#+begin_example\nYACC=\"$(brew --prefix bison)/bin/bison -y\" ./configure --enable-debug\n#+end_example\n\n*** Docker\n    You can use docker to build and run bic with the following command:\n\n#+begin_example\ndocker build -t bic https://github.com/hexagonal-sun/bic.git#master\n#+end_example\n\n    Once the image is build you can then run bic with:\n#+begin_example\ndocker run -i bic\n#+end_example\n\n*** Arch Linux\n    If you are using Arch Linux, you can install bic from AUR:\n\n#+begin_example\nyay -S bic\n#+end_example\n\n** Usage\n*** REPL\n    When invoking bic with no arguments the user is presented with a REPL prompt:\n\n    #+begin_example\nBIC\u003e\n    #+end_example\n\n    Here you can type C statements and =#include= various system headers to\n    provide access to different APIs on the system. Statements can be entered\n    directly into the REPL; there is no need to define a function for them to be\n    evaluated. Say we wish to execute the following C program:\n\n    #+begin_src C\n#include \u003cstdio.h\u003e\n\nint main()\n{\n    FILE *f = fopen(\"out.txt\", \"w\");\n    fputs(\"Hello, world!\\n\", f);\n    return 0;\n}\n    #+end_src\n\n    We can do this on the REPL with BIC using the following commands:\n\n    #+begin_example\nBIC\u003e #include \u003cstdio.h\u003e\nBIC\u003e FILE *f;\nf\nBIC\u003e f = fopen(\"test.txt\", \"w\");\nBIC\u003e fputs(\"Hello, World!\\n\", f);\n1\nBIC\u003e\n    #+end_example\n\n    This will cause bic to call out to the C-library =fopen()= and =fputs()=\n    functions to create a file and write the hello world string into it. If you\n    now exit bic, you should see a file ~test.txt~ in the current working\n    directory with the string ~Hello, World\\n~ contained within it.\n\n    Notice that after evaluating an expression bic will print the result of\n    evaluation. This can be useful for testing out simple expressions:\n\n    #+begin_example\nBIC\u003e 2 * 8 + fileno(f);\n19\n    #+end_example\n\n**** The Inspector\n\n     You can use bic to obtain information about any variable or type that has\n     been declared by prefixing it's name with a ~?~. This special syntax only\n     works in the REPL but will allow you to obtain various characteristics\n     about types and variables. For example:\n\n     #+begin_example\nBIC\u003e #include \u003cstdio.h\u003e\nBIC\u003e ?stdout\nstdout is a pointer to a struct _IO_FILE.\nvalue of stdout is 0x7ff1325bc5c0.\nsizeof(stdout) = 8 bytes.\nstdout was declared at: /usr/include/stdio.h:138.\n     #+end_example\n\n**** Startup Files\n\n     When the REPL starts, bic will see if =~/.bic= exists. If it does it is\n     automatically evaluated and the resulting enviroment is used by the REPL.\n     This can be useful for defining functions or varibles that are commonly\n     used. For instance, say our =~/.bic= file contains:\n\n     #+begin_src c\n#include \u003cstdio.h\u003e\n\nint increment(int a)\n{\n    return a + 1;\n}\n\nputs(\"Good morning, Dave.\");\n     #+end_src\n     \n     When we launch the REPL we get:\n\n     #+begin_example\n$ bic\nGood morning, Dave.\nBIC\u003e increment(2);\n3\n     #+end_example\n\n*** Evaluating Files\n\n    If you pass bic a source file, along with =-s=, as a command line argument\n    it will evaluate it, by calling a =main()= function. For example, suppose we\n    have the file ~test.c~ that contains the following:\n\n    #+begin_src c\n#include \u003cstdio.h\u003e\n\nint factorial(int n)\n{\n  if (!n)\n  {\n    return 1;\n  }\n\n  return n * factorial(n - 1);\n}\n\nint main()\n{\n  printf(\"Factorial of 4 is: %d\\n\", factorial(4));\n\n  return 0;\n}\n    #+end_src\n\n    We can then invoke bic with ~-s test.c~ to evaluate it:\n\n    #+begin_example\n$ bic -s test.c\nFactorial of 4 is: 24\n    #+end_example\n    \n    \n**** Passing Arguments\n\n     If you wish to pass arguments to a C file, append them to bic's command\n     line. Once bic has processed the ~-s~ argument all other arguments are\n     treated as parameters to be passed to the program. These parameters are\n     created as =argc= and =argv= variables and passed to =main()=. The value of\n     =argv[0]= is the name of the C file that bic is executing. Consider the\n     following C program:\n\n     #+begin_src C\n#include \u003cstdio.h\u003e\n\nint main(int argc, char *argv[])\n{\n    for (int i = 0; i \u003c argc; i++)\n        printf(\"argv[%d] = %s\\n\", i, argv[i]);\n\n    return 0;\n}\n     #+end_src\n     \n     If we don't pass any arguments:\n\n     #+begin_example\n$ bic -s test.c\nargv[0] = test.c\n    #+end_example\n     \n    Whereas if we invoke bic with more arguments, they are passed to the\n    program:\n\n    #+begin_example\n$ bic -s test.c -a foo -s bar a b c\nargv[0] = test.c\nargv[1] = -a\nargv[2] = foo\nargv[3] = -s\nargv[4] = bar\nargv[5] = a\nargv[6] = b\nargv[7] = c\n    #+end_example\n    \n**** Dropping Into a REPL\n\n    You can also use a special expression: =\u003cREPL\u003e;= in your source code to make\n    bic drop you into the repl at a particular point in the file evaluation:\n\n    [[file:doc/img/repl-interrupt.gif]]\n\n*** Exploring external libraries with the REPL\n\n    You can use bic to explore the APIs of other libraries other than libc. Let's\n    suppose we wish to explore the [[https://github.com/aquynh/capstone][Capstone]] library, we pass in a ~-l~ option to\n    make bic load that library when it starts.  For example:\n\n    [[file:doc/img/capstone.gif]]\n\n    Notice that when bic prints a compound data type (a =struct= or a =union=),\n    it shows all member names and their corresponding values.\n\n\n** Implementation Overview\n\n*** Tree Objects\n    At the heart of bic's implementation is the =tree= object. These are generic\n    objects that can be used to represent an entire program as well as the\n    current evaluator state. It is implemented in ~tree.h~ and ~tree.c~. Each\n    tree type is defined in ~c.lang~. The ~c.lang~ file is a lisp-like\n    specification of:\n\n    - Object name, for example =T_ADD=.\n    - A human readable name, such as ~Addition~.\n    - A property name prefix, such as ~tADD~.\n    - A list of properties for this type, such as ~LHS~ and ~RHS~.\n\n    The code to create an object with the above set of attributes would be:\n\n    #+begin_src lisp\n(deftype T_ADD \"Addition\" \"tADD\"\n         (\"LHS\" \"RHS\"))\n    #+end_src\n\n    Once defined, we can use this object in our C code in the following way:\n\n    #+begin_src C\ntree make_increment(tree number)\n{\n    tree add = tree_make(T_ADD);\n\n    tADD_LHS(add) = number;\n    tADD_RHS(add) = tree_make_const_int(1);\n\n    return add;\n}\n    #+end_src\n\n    Notice that a set of accessor macros, =tADD_LHS()= and =tADD_RHS()=, have\n    been generated for us to access the different property slots. When\n    ~--enable-debug~ is set during compilation each one of these macros expands\n    to a check to ensure that when setting the =tADD_LHS= property of an object\n    that the object is indeed an instance of a =T_ADD=.\n\n    The ~c.lang~ file is read by numerous source-to-source compilers that\n    generate code snippets. These utilities include:\n\n    - ~gentype~: Generates a list of tree object types.\n    - ~gentree~: Generates a structure that contains all the property data for\n      tree objects.\n    - ~genctypes~: Generates a list of C-Type tree objects - these represent the\n      fundamental data types in C.\n    - ~genaccess~: Generate accessor macros for tree object properties.\n    - ~gengc~: Generate a mark function for each tree object, this allows the\n      garbage collector to traverse object trees.\n    - ~gendump~: Generate code to dump out tree objects recursively.\n    - ~gendot~: Generate a dot file for a given =tree= hierarchy, allowing it to\n      be visualised.\n\n*** Evaluator\n\n    The output of the lexer \u0026 parser is a =tree= object hierarchy which is then\n    passed into the evaluator (~evaluator.c~). The evaluator will then\n    recursively evaluate each tree element, updating internal evaluator state,\n    thereby executing a program.\n\n    Calls to functions external to the evaluator are handled in a\n    platform-dependent way. Currently x86_64 and aarch64 are the only supported\n    platforms and the code to handle this is in the ~x86_64~ and ~aarch64~\n    folders respectively. This works by taking a function call =tree= object\n    (represented by a =T_FN_CALL=) from the evaluator with all arguments\n    evaluated and marshalling them into a simple linked-list. This is then\n    traversed in assembly to move the value into the correct register according\n    to the x86_64 or aarch64 calling-conventions and then branching to the\n    function address.\n\n*** Parser \u0026 Lexer\n    The parser and lexer are implemented in ~parser.m4~ and ~lex.m4~\n    respectively. After passing through M4 the output is two bison parsers and\n    two flex lexers.\n\n    The reason for two parsers is that the grammar for a C REPL is very\n    different than that of a C file. For example, we want the user to be able to\n    type in statements to be evaluated on the REPL without the need for wrapping\n    them in a function. Unfortunately writing a statement that is outside a\n    function body isn't valid C. As such, we don't want the user to be able to\n    write bare statements in a C file. To achieve this we have two different set\n    of grammar rules which produces two parsers. Most of the grammar rules do\n    overlap and therefore we use a single M4 file to take care of the\n    differences.\n","funding_links":[],"categories":["C"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhexagonal-sun%2Fbic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhexagonal-sun%2Fbic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhexagonal-sun%2Fbic/lists"}