{"id":13781361,"url":"https://github.com/peterwankman/libisp","last_synced_at":"2025-05-11T14:35:00.928Z","repository":{"id":6615364,"uuid":"7858839","full_name":"peterwankman/libisp","owner":"peterwankman","description":"Lisp interpreter based on SICP","archived":false,"fork":false,"pushed_at":"2017-03-24T13:35:33.000Z","size":311,"stargazers_count":4,"open_issues_count":1,"forks_count":1,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-11-17T16:42:40.214Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"wtfpl","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/peterwankman.png","metadata":{"files":{"readme":"readme.txt","changelog":null,"contributing":null,"funding":null,"license":"license.txt","code_of_conduct":"code-of-conduct.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-01-27T22:08:21.000Z","updated_at":"2020-01-07T21:25:27.000Z","dependencies_parsed_at":"2022-09-16T07:51:37.287Z","dependency_job_id":null,"html_url":"https://github.com/peterwankman/libisp","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peterwankman%2Flibisp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peterwankman%2Flibisp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peterwankman%2Flibisp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peterwankman%2Flibisp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/peterwankman","download_url":"https://codeload.github.com/peterwankman/libisp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253580381,"owners_count":21930933,"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":[],"created_at":"2024-08-03T18:01:25.266Z","updated_at":"2025-05-11T14:35:00.634Z","avatar_url":"https://github.com/peterwankman.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"\n '-._                  ___.....___\n     `.__           ,-'        ,-.`-,\n         `''-------'          ( p )  `._\n                               `-'      (        Have you conjured the spirits\n                                         \\             of your computer today?\n                                .         \\\n                                 \\\\---..,--'\n         .............._           --...--,\n                        `-.._         _.-'\n                             `'-----''                     Read SICP for help.\n\n\nlibisp -- Lisp evaluator based on SICP\n(C) 2013-2017 Martin Wolters\n\n1. HOW TO USE\n-------------\n\n1.1. GENERAL\n------------\n\nlibisp.h is the main header file for the whole library.\n\n1.2. INITIALIZING A CONTEXT\n---------------------------\n\nYou need to create a context for each instance of the interpreter you are going\nto use. The function creating a context is\n\n\tlisp_ctx_t *lisp_make_context(const size_t mem_lim_soft, \n\t\tconst size_t mem_lim_hard, const size_t mem_verbosity, \n\t\tconst size_t thread_timeout);\n\t\nwhere mem_lim_soft is the amount of allocated memory within the context, that\nwill trigger the garbage collector. mem_lim_hard will cause the allocator to\nrefuse allocating new memory.\n\nmem_verbosity can be one of LISP_GC_SILENT or LISP_GC_VERBOSE. The latter will\nmake the allocator and garbage collector notify you of what they're doing.\n\nthread_timeout is the number of seconds after which the evaluator thread will\nbe terminated.\n\n1.2. PRIMITIVE PROCEDURES\n-------------------------\n\nYou can add your own procedures as primitives with the supplied function\nlisp_add_prim_proc(), by providing a name under which the procedure will be\nknown to Lisp, and a pointer to the procedure itself:\n\n\tvoid lisp_add_prim_proc(char *name, lisp_prim_proc proc, \n\t\tlisp_ctx_t *context);\n\nWhere lisp_prim_proc is typedef'd to be\n\n\ttypedef struct lisp_data_t* (*lisp_prim_proc)(const struct lisp_data_t*, \n\t\tlisp_ctx_t *context);\n\nlisp_data_t is a pointer to the following struct:\n\n\ttypedef struct lisp_data_t {\n\t\tlisp_type_t type;\n\t\tunion {\n\t\t\tint integer;\n\t\t\tdouble decimal;\n\t\t\tchar *string;\n\t\t\tchar *symbol;\n\t\t\tchar *error;\n\t\t\tlisp_prim_proc proc;\n\t\t\tstruct lisp_cons_t *pair;\n\t\t};\n\t} lisp_data_t;\n\nand lisp_type_t and lisp_cons_t are \n\n\ttypedef enum lisp_type_t {\n\t\tlisp_type_integer, \n\t\tlisp_type_decimal, \n\t\tlisp_type_string, \n\t\tlisp_type_symbol, \n\t\tlisp_type_pair, \n\t\tlisp_type_prim,\n\t\tlisp_type_error\n\t} lisp_type_t;\n\t\n\ttypedef struct lisp_cons_t {\n\t\tstruct lisp_data_t *l, *r;\n\t} lisp_cons_t;\n\t\nWhen your primitive procedure is called, it receives a Lisp data structure in\nthe first parameter. First check the type and then use lisp_data_t-\u003e[type] as\nyou need.\n\n1.3. CONFIG VARIABLES\n---------------------\n\nYou can use variables to interface the interpreter with your program. Register\na variable as a config var with\n\n\tvoid lisp_add_cvar(const char *name, const size_t *valptr, \n\t\tconst int access, lisp_ctx_t *context);\n\t\t\nwhere name is the identifier for the variable within Lisp, valptr a pointer to\nthe variable in C and access one of  LISP_CVAR_RO and LISP_CVAR_RW.\n\nConfig variables can be accessed from Lisp using\n\n\t(get-cvar \u003cidentifier\u003e)\n\t(set-cvar! \u003cidentifier\u003e \u003cvalue\u003e)\n\nThe following config variables are provided with every new context:\n\n\tmem_allocated\t\t(LISP_CVAR_RO)\n\tmem_lim_hard\t\t(LISP_CVAR_RO)\n\tmem_lim_soft\t\t(LISP_CVAR_RO)\n\tmem_list_entries\t(LISP_CVAR_RO)\n\tmem_verbosity\t\t(LISP_CVAR_RW)\n\tthread_timeout\t\t(LISP_CVAR_RW)\n\t\n1.5. INITIALIZING THE ENVIRONMENT\n---------------------------------\n\nAfter adding the needed primitive procedures and config variables, finalize the\ninitialization of your context with\n\n\tlisp_setup_env(lisp_ctx_t *context);\n\t\nThis will register all primitive procedures and config variables with Lisp and\ndefine some useful compound procedures. Finally the garbage collector will be\nrun and you can begin using your Lisp context.\n\n1.5. EVALUATING AN EXPRESSION\n-----------------------------\n\nBefore evaluating an expression, you must first read it into a Lisp data struc-\nture. lisp_read() will do that for you.\n\n\tlisp_data_t *lisp_read(const char *exp, size_t *readto, \n\t\tint *error, lisp_ctx_t *context);\n\t\nexp will be the expression to evaluate, *readto is a pointer to the last byte\nread by the reader. You can use it to get to the next expression in the next\nstep of the REPL. *error will be 1 if the reader encountered a syntax error.\n\nThe returned data structure can now be used to evaluate the expression.\n\n\tlisp_data_t *lisp_eval(const lisp_data_t *exp, lisp_ctx_t *context);\n\t\nlisp_eval() spawns a thread to do the evaluation in. If the thread takes longer\nthan specified in thread_timeout, the thread will be terminated and it will\nreturn NULL. Else, it returns a Lisp data structure, which can be printed to\nthe screen (like any other Lisp structure, say from lisp_read()) with\n\n\tvoid lisp_print(const lisp_data_t *d, lisp_ctx_t *context);\n\t\nor be manipulated however you like.\n\nYou can also evaluate an expression in the current context and discard the\nresult. This is useful for defining variables and non-primitive procedures,\nthat will be used by your program. The usage of the function should be trivial.\n\n\tvoid lisp_run(const char *exp, lisp_ctx_t *context);\n\n1.6. MEMORY MANAGEMENT\n----------------------\n\nThe memory management uses two variables to determine its behaviour:\n\n\tsize_t mem_lim_soft\n\tsize_t mem_lim_hard\n\nAfter mem_lim_hard is reached, the allocator will refuse to allocate any more\nmemory and return an error. The soft limit tells the garbage collector, when to\nactually reclaim memory.\n\nYou need to call the garbage collector manually. Just use\n\n\tsize_t lisp_gc(int force, lisp_ctx_t *context);\n\nThe parameter can be LISP_GC_FORCE, which will always reclaim any unreachable\nmemory, or LISP_GC_LOWMEM, which will only reclaim memory, when more than\nmem_lim_soft is in use. It will return the number of bytes reclaimed (if any).\n\nYou can also free data structures manually, using the functions\n\n\tvoid lisp_free_data(lisp_data_t *in, lisp_ctx_t *context);\n\tvoid lisp_free_data_rec(lisp_data_t *in, lisp_ctx_t *context);\n\nThe former will free just the data structure supplied, while the latter will\nfree a list structure recursively. After you are done with using your context,\ndestroy it with\n\n\tvoid lisp_destroy_context(lisp_ctx_t *context);\n\t\nThis will run the garbage collector, free the global environment and then free\nthe list of primitive procedures. After that, everything allocated by libisp\nin that context is free()d.\n\nThere is a function which shows allocated instances of data_t that have not yet\nbeen freed.\n\n\tvoid lisp_gc_stats(FILE *fp, lisp_ctx_t *context);\n\t\nThe argument allows for output to stderr or a log file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeterwankman%2Flibisp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpeterwankman%2Flibisp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeterwankman%2Flibisp/lists"}