{"id":20255303,"url":"https://github.com/projectm-visualizer/projectm-eval","last_synced_at":"2026-02-28T21:32:29.942Z","repository":{"id":72407556,"uuid":"602482599","full_name":"projectM-visualizer/projectm-eval","owner":"projectM-visualizer","description":"The projectM Expression Evaluation Library. A portable drop-in replacement of Milkdrop's \"ns-eel2\" expression parser for use in Milkdrop, projectM and other applications. MIT licensed.","archived":false,"fork":false,"pushed_at":"2025-03-17T14:12:57.000Z","size":228,"stargazers_count":7,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-11T00:05:28.979Z","etag":null,"topics":["bison-flex","expression-evaluator","milkdrop","milkdrop2","presets"],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/projectM-visualizer.png","metadata":{"files":{"readme":"ReadMe.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-02-16T09:59:28.000Z","updated_at":"2025-03-17T14:09:06.000Z","dependencies_parsed_at":null,"dependency_job_id":"daea3b3a-ef5c-4f59-829c-e92bdea1b031","html_url":"https://github.com/projectM-visualizer/projectm-eval","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/projectM-visualizer%2Fprojectm-eval","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/projectM-visualizer%2Fprojectm-eval/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/projectM-visualizer%2Fprojectm-eval/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/projectM-visualizer%2Fprojectm-eval/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/projectM-visualizer","download_url":"https://codeload.github.com/projectM-visualizer/projectm-eval/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248317707,"owners_count":21083528,"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":["bison-flex","expression-evaluator","milkdrop","milkdrop2","presets"],"created_at":"2024-11-14T10:38:03.041Z","updated_at":"2026-02-28T21:32:29.829Z","avatar_url":"https://github.com/projectM-visualizer.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"projectM Expression Evaluation Library\n======================================\n\nThis repository contains the source code for the projectM Expression Evaluation Library, short \"projectm-eval\", which is\na cross-platform and cross-architecture reimplementation of Milkdrop's pendant, the NullSoft Expression Evaluation\nLibrary 2, or short \"ns-eel2\".\n\nThis library aims at being as portable as possible, sacrificing some performance over portability. The original ns-eel2\nlibrary directly assembles machine code from compiled assembler fragments. While this is super performant, the assembler\ncode needs to be rewritten manually for every target platform and CPU architecture and is really hard to read or edit.\n\nprojectM's Expression Evaluation Library was implemented as a separate project and put under the MIT license to make it\nuseful in other projects, open source and closed source, while the core projectM library stays under the LGPL license.\n\nImplementation and usage details can be found in the [\"docs\" subdirectory](docs).\n\n## Building the Library\n\nThe projectM Expression Evaluation Library is always being built as a static library. It can also be used as an object\nlibrary in a subproject of other CMake projects, see the instructions below on how to use it this way.\n\n### Requirements\n\nIf you just want to build the library, no other dependencies besides a working toolchain, CMake (3.20 or higher) and a\nbuild processor like Make, Ninja, Visual Studio or Xcode are required.\n\nTo recreate the parser and lexer or to run tests, additional dependencies need to be installed:\n\n- Bison 3.8 and Flex 2.6 to regenerate the code compiler from the .y/.l files.\n- GTest 1.10 or higher to run the unit tests\n- Google Benchmark to run the benchmarks.\n\nTo specify custom locations for Bison and Flex, set BISON_EXECUTABLE and FLEX_EXECUTABLE accordingly when configuring\nthe project.\n\n### Configure and Build\n\nFor a default build, the library doesn't need any additional specifiers other than the standard CMake parameters like\nsource dir, build dir and generator. Execute the following commands from the source directory (where this file resides):\n\n```shell\nmkdir cmake-build\ncmake -S . -B cmake-build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/path/to/install/dir\ncmake --build cmake-build\ncmake --install cmake-build\n```\n\nThe resulting files can then be used in other projects. See the Quick Start Guide below for details.\n\n## Quick Start Guide\n\nThe following guide gives a short overview on what is needed to get your first script running.\n\nIf you need to use the ns-eel2 API, please refer to the [NullSoft shim ReadMe](ns-eel2-shim/ReadMe.md) instead.\n\n### Using the Library with CMake\n\n#### As an External Project (Static Library)\n\nIf you want to use projectM-Eval as an external project in your CMake builds, use `find_package()` in your project's\nCMakeLists.txt:\n\n```cmake\nfind_package(projectM-Eval REQUIRED)\n```\n\nYou may need to point CMake to the installation directory via\nthe [`CMAKE_PREFIX_PATH` variable](https://cmake.org/cmake/help/latest/variable/CMAKE_PREFIX_PATH.html).\n\nTo add the include dir and link the static library, simply link the `projectM::Eval` target to your target, application\nor library:\n\n```cmake\nadd_executable(MyApp\n    # Sources go here\n)\ntarget_link_libraries(MyApp\n    PRIVATE\n    projectM::Eval\n)\n```\n\nImportant: If your final target is a static library, this will _not_ copy any code into it! Any application using this\nstatic library will also have to link the `projectM::Eval` static library. To include the projectM-Eval object code into\nanother static library, use the object library/subproject approach below.\n\n#### As a Subproject (Static or Object Library)\n\nIf projectM-Eval is an integral part of your project, adding it as a subproject inside the source tree may be the best\napproach, as it will reduce the number of external dependencies and makes building easier.\n\nIf possible, using git submodules is highly recommended as it makes updating the sources from upstream easier. Copying\nthe code into the source tree is also fine though.\n\nGiven the sources are checked out/copied to a subdirectory named \"projectm-eval\" of the directory with the current\nCMakeLists.txt, simply adding the subdirectory will suffice:\n\n```cmake\nadd_subdirectory(projectm-eval)\n```\n\nAfter this include directive, the `projectM::Eval` target is available for linking, same as with the external package\nvariant. To link the library as a static library, the CMake code is identical:\n\n```cmake\nadd_executable(MyApp\n    # Sources go here\n)\ntarget_link_libraries(MyApp\n    PRIVATE\n    projectM::Eval\n)\n```\n\nIf the target is a static library, to which the projectM-Eval object files should be added, then an additional line in\nthe target source list is required:\n\n```cmake\nadd_library(MyLib STATIC\n    $\u003cTARGET_OBJECTS:projectM::Eval\u003e\n    # Other sources go here\n)\ntarget_link_libraries(MyApp\n    PRIVATE\n    projectM::Eval\n)\n```\n\nNote that the library still needs to be linked. While this won't add any code to the target, it will populate the\nrequired include directories and compiler flags needed to use the headers.\n\n#### Using the Library with Other Build Systems\n\nIf CMake is not an option, the static library can be linked manually and the `projectm-eval.h` header file can be copied\ninto the project or pointed to via the include directory settings of the build system used.\n\nOn UNIX operating systems such as Linux, macOS or BSD and if `ENABLE_PROJECTM_EVAL_INSTALL` is enabled, a\n`projectm-eval.pc` pkg-config file will be installed into the destination library dir and can be used by any\npkg-config-compatible build system to link the static library (using `pkg-config --libs projectm-eval`) and retrieve the\ncorrect include dir (using `pkg-config --cflags projectm-eval`).\n\nTo use it as an object library, please refer to the platform build tools on how to unpack the static library into its\nobject files or how to copy its contents into another static library.\n\n### Running the First Code\n\nTo integrate projectM-Eval into another application, only a few steps are required to get things set up:\n\n- Implement the memory locking callbacks.\n- Create an execution context.\n- Compile some code.\n- Register and set variables.\n- Run the code.\n- Destroy the code and context.\n\nOptionally, custom global memory handling can be used. Please see the [memory handling docs](docs/Memory-Handling.md)\nfor details.\n\nIn production code, always check returned pointers before using them!\n\nIn most cases, multi-threading will not be used, so the memory stubs can be empty functions. Either add a separate code\nfile, or put the following code into any existing implementation file:\n\n```c\n#include \u003cprojectm-eval.h\u003e\n\nvoid projectm_eval_memory_host_lock_mutex() {}\nvoid projectm_eval_memory_host_unlock_mutex() {}\n```\n\nIn C, including the header is optional. If the file is a C++ file, either including the header or adding `extern \"C\"{}`\naround the implementations is mandatory to prevent the compiler from performing C++ name mangling on the functions.\n\nTo run any code, an execution context is required. It will maintain the variables and megabuf data, while also giving\naccess to the reg variables and gmegabuf as needed. In this example, we'll use the internal global memory structures for\nsimplicity, thus we create the context by passing NULL to both parameters.\n\n```c\n#include \u003cprojectm-eval.h\u003e\n\n#include \u003cstdio.h\u003e\n\nint main()\n{\n    struct projectm_eval_context* ctx = projectm_eval_context_create(NULL, NULL);\n    /* Insert additional code here */\n    \n    return 0;\n}\n```\n\nNow that the context is created, we can already compile code:\n\n```c\nstruct projectm_eval_code* code = projectm_eval_code_compile(ctx, \"x = a; y = 2;\");\n```\n\nIf the code couldn't be compiled, NULL is returned. The `projectm_eval_get_error()` function can be used to retrieve the\nparser error, including line and column.\n\nThe above code will surely compile, but uses a variable `a` which isn't set explicitly. If that's the case, any variable\nthat was never set before will have an initial value of `0`. Yet in most cases, expressions will run on some input from\nthe application, so in this example, `a` would be the input. To pass a value to the code, we can register the variable\nand use the returned pointer to set or read the value. In this example, we register all three variables and set `a`\nto `100` initially:\n\n```c\nPRJM_EVAL_F* var_a = projectm_eval_context_register_variable(ctx, \"a\");\nPRJM_EVAL_F* var_x = projectm_eval_context_register_variable(ctx, \"x\");\nPRJM_EVAL_F* var_y = projectm_eval_context_register_variable(ctx, \"y\");\n\n*var_a = 100.0;\n```\n\nThe internal `reg00` to `reg99` variables can be registered in the same way.\n\nThe megabuf and gmegabuf contents cannot be accessed from the outside. If that is required, compile an expression that\ncopies it into a normal variable, register the variable, then execute the code and read the variable contents.\n\nNow the code can be executed:\n\n```c\nprojectm_eval_code_execute(code);\n```\n\nNote that only the code handle is required. The context is stored inside this opaque structure, as any compiled code is\nfirmly tied to a single context. This said, executing code after destroying the context it was compiled in _will_ crash\nthe application!\n\nIn this example, the return value of `projectm_eval_code_execute()` is ignored. If your application is not interested in\nvariables, but the result of the _last_ statement in the expression, this is the value returned by the function. In this\nexample, it would be `2`, as this is the result of the `y = 2` expression.\n\nThe execution has changed the contents of the `x` and `y` variables, so we can now output all three values to see their\nactual contents:\n\n```c\nprintf(\"a = %f\\nx = %f\\ny = %f\\n\", *var_a, *var_x, *var_y);\n```\n\nAfter we're done with the context and code, everything should be cleaned up properly:\n\n```c\nprojectm_eval_code_destroy(code);\nprojectm_eval_context_destroy(ctx);\n```\n\nA few notes on cleanup:\n\n- The order in which the context, code handles and memory buffers are destroyed doesn't matter.\n- After destroying a handle, do _not_ use this handle or any associated data, e.g. registered variables after the\n  context was destroyed. This will crash the application.\n- Code handles can be destroyed right after execution. As variables are stored in the context, their values remain\n  unchanged as long as the context isn't destroyed.\n- _Never_ call `free()` on the registered variable pointers. The memory they point to is owned and freed by the context.\n\n## Further Reading\n\nThe [`docs`](docs) directory contains a few more documents regarding the API and expression syntax:\n\n- [Compiler Internals](docs/Compiler-Internals.md): A few technical details on how the projectM-Eval compiler/parser\n  works internally.\n- [Expression Syntax](docs/Expression-Syntax.md): Full documentation on the expression code syntax, including tricks and\n  caveats. This document is also valid for the original Milkdrop parser.\n- [Memory Handling](docs/Memory-Handling.md): Additional information for using global memory buffers and share them\n  between contexts, plus multi-threading considerations.\n\nIf there are still open questions, feel free to visit us on our Discord server. An invitation link can be found in\nthe [libprojectM repository on GitHub](https://github.com/projectM-visualizer/projectm).\n\nFor bugs and feature requests, feel free to contribute a pull request or open an issue in the bug tracker.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprojectm-visualizer%2Fprojectm-eval","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprojectm-visualizer%2Fprojectm-eval","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprojectm-visualizer%2Fprojectm-eval/lists"}