I need to program a C++ application which will basically work as a script interpreter, but with extremely basic and limited scripts.
The scripts will have a format like this:
processedA = doProcessA(source)
processedB = doProcessB(source)
destination = mix(processedA, processedB)
This denotes that in my C++ application this should happen (pseudocode):
while(source)
{
processedA = doProcessA(*source);
processedB = doProcessB(*source);
*destination = mix(processedA, processedB);
source++;
destination++;
}
I am not sure what my option are for interpreting my language. Parsing it should be simple.
Should I build an interpreter for my language, use llvm somehow to compile the flow (I’m not sure how), use a scripting language with c++ bindings or something else entirely?
I also need this to be reasonably fast (there isn’t a limit but the faster the better).
4
There are many easily embeddable interpreters, notably GNU guile (and other Scheme variants, e.g. libscheme), Lua, Tcl, and even Python, OCaml, Perl (e.g. with parrot), NekoVM …
Notice that if your software becomes popular enough, and if its (advanced) users are permitted to script it (i.e. if the scripting ability is documented and accessible or configurable), there are chances that some remote user would use a lot (and even abuse) the scripting facilities.
So the implicit premises in your question (“extremely basic scripts”) will eventually become false. At some point the scripts won’t be basic anymore!
This is why a scripting language has to be a good enough programming language (with a familiar look). Some weird user will eventually code many thousands lines in it. (BTW, this social issue is probably what Ousterhout, the famous author of Tcl, under-estimated: he originally designed the first Tcl for small scripts, but eventually some people wrote huge Tcl scripts, and then Tcl became a burden, because it purposely lacks some features that real programming languages should have… efficient data structures, modularity, etc.. Since then, Tcl improved significantly.).
If for some reason you cannot (or do no want) to embed an existing interpreter in your product and decided to write your own scripting interpreter (which means many months of work!), study several programming and scripting languages before designing your own (and document the languages that inspired you). Take care of having good internal representation(s) of the interpreted script (at least some AST, and preferably some bytecode). Read notably Scott’s book: programming language pragmatics and Queinnec’s book: Lisp in Small Pieces and study several Domain Specific Languages; read about garbage collection, and perhaps application checkpointing & persistence.
You may consider using JIT compilation techniques (e.g. with llvm, libjit, libgccjit, luajit …) and you could also consider instead generating C (or C++) code on the fly and compiling it and dlopen
-ing it as a plugin (as I did in MELT). Current machines are fast enough to make that compatible with a REPL interaction.
Notice that embedding some interpreter in your application has a huge architectural impact, and should probably change or deeply affect the design of your application, and how it would be used by advanced users.
Remember that a scripting language is almost always Turing-complete (unless you take special care in its design to avoid that). Never forget about the halting problem.
In the audio processing world, read about Faustine (by Karim Barkati, Haisheng Wang, and Pierre Jouvelot) and Faust (by Grame team in France).
5
Use an existing one -= don’t bother reinventing the wheel when there are better wheels available, that are cheaper for you to use.
Lua seems to be the most common C/C++ embedded script interpreter. There are even youtube tutorials on embeddeding it into your C++ programs, or codeproject.