1 |
/* |
2 |
* Copyright (c) 2014-2016 Christian Schoenebeck |
3 |
* |
4 |
* http://www.linuxsampler.org |
5 |
* |
6 |
* This file is part of LinuxSampler and released under the same terms. |
7 |
* See README file for details. |
8 |
*/ |
9 |
|
10 |
// This header defines data types shared between the VM core implementation |
11 |
// (inside the current source directory) and other parts of the sampler |
12 |
// (located at other source directories). |
13 |
|
14 |
#ifndef LS_INSTR_SCRIPT_PARSER_COMMON_H |
15 |
#define LS_INSTR_SCRIPT_PARSER_COMMON_H |
16 |
|
17 |
#include "../common/global.h" |
18 |
#include <vector> |
19 |
#include <map> |
20 |
#include <stddef.h> // offsetof() |
21 |
|
22 |
namespace LinuxSampler { |
23 |
|
24 |
/** |
25 |
* Identifies the type of a noteworthy issue identified by the script |
26 |
* parser. That's either a parser error or parser warning. |
27 |
*/ |
28 |
enum ParserIssueType_t { |
29 |
PARSER_ERROR, ///< Script parser encountered an error, the script cannot be executed. |
30 |
PARSER_WARNING ///< Script parser encountered a warning, the script may be executed if desired, but the script may not necessarily behave as originally intended by the script author. |
31 |
}; |
32 |
|
33 |
/** @brief Expression's data type. |
34 |
* |
35 |
* Identifies to which data type an expression within a script evaluates to. |
36 |
* This can for example reflect the data type of script function arguments, |
37 |
* script function return values, but also the resulting data type of some |
38 |
* mathematical formula within a script. |
39 |
*/ |
40 |
enum ExprType_t { |
41 |
EMPTY_EXPR, ///< i.e. on invalid expressions or i.e. a function call that does not return a result value (the built-in wait() or message() functions for instance) |
42 |
INT_EXPR, ///< integer (scalar) expression |
43 |
INT_ARR_EXPR, ///< integer array expression |
44 |
STRING_EXPR, ///< string expression |
45 |
STRING_ARR_EXPR, ///< string array expression |
46 |
}; |
47 |
|
48 |
/** @brief Result flags of a script statement or script function call. |
49 |
* |
50 |
* A set of bit flags which provide informations about the success or |
51 |
* failure of a statement within a script. That's also especially used for |
52 |
* providing informations about success / failure of a call to a built-in |
53 |
* script function. The virtual machine evaluates these flags during runtime |
54 |
* to decide whether it should i.e. stop or suspend execution of a script. |
55 |
* |
56 |
* Since these are bit flags, these constants are bitwise combined. |
57 |
*/ |
58 |
enum StmtFlags_t { |
59 |
STMT_SUCCESS = 0, ///< Function / statement was executed successfully, no error occurred. |
60 |
STMT_ABORT_SIGNALLED = 1, ///< VM should stop the current callback execution (usually because of an error, but might also be without an error reason, i.e. when the built-in script function exit() was called). |
61 |
STMT_SUSPEND_SIGNALLED = (1<<1), ///< VM supended execution, either because the script called the built-in wait() script function or because the script consumed too much execution time and was forced by the VM to be suspended for some time |
62 |
STMT_ERROR_OCCURRED = (1<<2), ///< VM stopped execution due to some script runtime error that occurred |
63 |
}; |
64 |
|
65 |
/** @brief Virtual machine execution status. |
66 |
* |
67 |
* A set of bit flags which reflect the current overall execution status of |
68 |
* the virtual machine concerning a certain script execution instance. |
69 |
* |
70 |
* Since these are bit flags, these constants are bitwise combined. |
71 |
*/ |
72 |
enum VMExecStatus_t { |
73 |
VM_EXEC_NOT_RUNNING = 0, ///< Script is currently not executed by the VM. |
74 |
VM_EXEC_RUNNING = 1, ///< The VM is currently executing the script. |
75 |
VM_EXEC_SUSPENDED = (1<<1), ///< Script is currently suspended by the VM, either because the script called the built-in wait() script function or because the script consumed too much execution time and was forced by the VM to be suspended for some time. |
76 |
VM_EXEC_ERROR = (1<<2), ///< A runtime error occurred while executing the script (i.e. a call to some built-in script function failed). |
77 |
}; |
78 |
|
79 |
/** @brief Script event handler type. |
80 |
* |
81 |
* Identifies one of the possible event handler callback types defined by |
82 |
* the NKSP script language. |
83 |
*/ |
84 |
enum VMEventHandlerType_t { |
85 |
VM_EVENT_HANDLER_INIT, ///< Initilization event handler, that is script's "on init ... end on" code block. |
86 |
VM_EVENT_HANDLER_NOTE, ///< Note event handler, that is script's "on note ... end on" code block. |
87 |
VM_EVENT_HANDLER_RELEASE, ///< Release event handler, that is script's "on release ... end on" code block. |
88 |
VM_EVENT_HANDLER_CONTROLLER, ///< Controller event handler, that is script's "on controller ... end on" code block. |
89 |
}; |
90 |
|
91 |
// just symbol prototyping |
92 |
class VMIntExpr; |
93 |
class VMStringExpr; |
94 |
class VMIntArrayExpr; |
95 |
class VMStringArrayExpr; |
96 |
|
97 |
/** @brief Virtual machine expression |
98 |
* |
99 |
* This is the abstract base class for all expressions of scripts. |
100 |
* Deriving classes must implement the abstract method exprType(). |
101 |
* |
102 |
* An expression within a script is translated into one instance of this |
103 |
* class. It allows a high level access for the virtual machine to evaluate |
104 |
* and handle expressions appropriately during execution. Expressions are |
105 |
* for example all kinds of formulas, function calls, statements or a |
106 |
* combination of them. Most of them evaluate to some kind of value, which |
107 |
* might be further processed as part of encompassing expressions to outer |
108 |
* expression results and so forth. |
109 |
*/ |
110 |
class VMExpr { |
111 |
public: |
112 |
/** |
113 |
* Identifies the data type to which the result of this expression |
114 |
* evaluates to. This abstract method must be implemented by deriving |
115 |
* classes. |
116 |
*/ |
117 |
virtual ExprType_t exprType() const = 0; |
118 |
|
119 |
/** |
120 |
* In case this expression is an integer expression, then this method |
121 |
* returns a casted pointer to that VMIntExpr object. It returns NULL |
122 |
* if this expression is not an integer expression. |
123 |
* |
124 |
* @b Note: type casting performed by this method is strict! That means |
125 |
* if this expression is i.e. actually a string expression like "12", |
126 |
* calling asInt() will @b not cast that numerical string expression to |
127 |
* an integer expression 12 for you, instead this method will simply |
128 |
* return NULL! |
129 |
* |
130 |
* @see exprType() |
131 |
*/ |
132 |
VMIntExpr* asInt() const; |
133 |
|
134 |
/** |
135 |
* In case this expression is a string expression, then this method |
136 |
* returns a casted pointer to that VMStringExpr object. It returns NULL |
137 |
* if this expression is not a string expression. |
138 |
* |
139 |
* @b Note: type casting performed by this method is strict! That means |
140 |
* if this expression is i.e. actually an integer expression like 120, |
141 |
* calling asString() will @b not cast that integer expression to a |
142 |
* string expression "120" for you, instead this method will simply |
143 |
* return NULL! |
144 |
* |
145 |
* @see exprType() |
146 |
*/ |
147 |
VMStringExpr* asString() const; |
148 |
|
149 |
/** |
150 |
* In case this expression is an integer array expression, then this |
151 |
* method returns a casted pointer to that VMIntArrayExpr object. It |
152 |
* returns NULL if this expression is not an integer array expression. |
153 |
* |
154 |
* @b Note: type casting performed by this method is strict! That means |
155 |
* if this expression is i.e. an integer expression or a string |
156 |
* expression, calling asIntArray() will @b not cast those scalar |
157 |
* expressions to an array expression for you, instead this method will |
158 |
* simply return NULL! |
159 |
* |
160 |
* @see exprType() |
161 |
*/ |
162 |
VMIntArrayExpr* asIntArray() const; |
163 |
|
164 |
/** |
165 |
* Returns true in case this expression can be considered to be a |
166 |
* constant expression. A constant expression will retain the same |
167 |
* value throughout the entire life time of a script and the |
168 |
* expression's constant value may be evaluated already at script |
169 |
* parse time, which may result in performance benefits during script |
170 |
* runtime. |
171 |
* |
172 |
* @b NOTE: A constant expression is per se always also non modifyable. |
173 |
* But a non modifyable expression may not necessarily be a constant |
174 |
* expression! |
175 |
* |
176 |
* @see isModifyable() |
177 |
*/ |
178 |
virtual bool isConstExpr() const = 0; |
179 |
|
180 |
/** |
181 |
* Returns true in case this expression is allowed to be modified. |
182 |
* If this method returns @c false then this expression must be handled |
183 |
* as read-only expression, which means that assigning a new value to it |
184 |
* is either not possible or not allowed. |
185 |
* |
186 |
* @b NOTE: A constant expression is per se always also non modifyable. |
187 |
* But a non modifyable expression may not necessarily be a constant |
188 |
* expression! |
189 |
* |
190 |
* @see isConstExpr() |
191 |
*/ |
192 |
bool isModifyable() const; |
193 |
}; |
194 |
|
195 |
/** @brief Virtual machine integer expression |
196 |
* |
197 |
* This is the abstract base class for all expressions inside scripts which |
198 |
* evaluate to an integer (scalar) value. Deriving classes implement the |
199 |
* abstract method evalInt() to return the actual integer result value of |
200 |
* the expression. |
201 |
*/ |
202 |
class VMIntExpr : virtual public VMExpr { |
203 |
public: |
204 |
/** |
205 |
* Returns the result of this expression as integer (scalar) value. |
206 |
* This abstract method must be implemented by deriving classes. |
207 |
*/ |
208 |
virtual int evalInt() = 0; |
209 |
|
210 |
/** |
211 |
* Returns always INT_EXPR for instances of this class. |
212 |
*/ |
213 |
ExprType_t exprType() const OVERRIDE { return INT_EXPR; } |
214 |
}; |
215 |
|
216 |
/** @brief Virtual machine string expression |
217 |
* |
218 |
* This is the abstract base class for all expressions inside scripts which |
219 |
* evaluate to a string value. Deriving classes implement the abstract |
220 |
* method evalStr() to return the actual string result value of the |
221 |
* expression. |
222 |
*/ |
223 |
class VMStringExpr : virtual public VMExpr { |
224 |
public: |
225 |
/** |
226 |
* Returns the result of this expression as string value. This abstract |
227 |
* method must be implemented by deriving classes. |
228 |
*/ |
229 |
virtual String evalStr() = 0; |
230 |
|
231 |
/** |
232 |
* Returns always STRING_EXPR for instances of this class. |
233 |
*/ |
234 |
ExprType_t exprType() const OVERRIDE { return STRING_EXPR; } |
235 |
}; |
236 |
|
237 |
/** @brief Virtual Machine Array Value Expression |
238 |
* |
239 |
* This is the abstract base class for all expressions inside scripts which |
240 |
* evaluate to some kind of array value. Deriving classes implement the |
241 |
* abstract method arraySize() to return the amount of elements within the |
242 |
* array. |
243 |
*/ |
244 |
class VMArrayExpr : virtual public VMExpr { |
245 |
public: |
246 |
/** |
247 |
* Returns amount of elements in this array. This abstract method must |
248 |
* be implemented by deriving classes. |
249 |
*/ |
250 |
virtual int arraySize() const = 0; |
251 |
}; |
252 |
|
253 |
/** @brief Virtual Machine Integer Array Expression |
254 |
* |
255 |
* This is the abstract base class for all expressions inside scripts which |
256 |
* evaluate to an array of integer values. Deriving classes implement the |
257 |
* abstract methods arraySize(), evalIntElement() and assignIntElement() to |
258 |
* access the individual integer array values. |
259 |
*/ |
260 |
class VMIntArrayExpr : virtual public VMArrayExpr { |
261 |
public: |
262 |
/** |
263 |
* Returns the (scalar) integer value of the array element given by |
264 |
* element index @a i. |
265 |
* |
266 |
* @param i - array element index (must be between 0 .. arraySize() - 1) |
267 |
*/ |
268 |
virtual int evalIntElement(uint i) = 0; |
269 |
|
270 |
/** |
271 |
* Changes the current value of an element (given by array element |
272 |
* index @a i) of this integer array. |
273 |
* |
274 |
* @param i - array element index (must be between 0 .. arraySize() - 1) |
275 |
* @param value - new integer scalar value to be assigned to that array element |
276 |
*/ |
277 |
virtual void assignIntElement(uint i, int value) = 0; |
278 |
|
279 |
/** |
280 |
* Returns always INT_ARR_EXPR for instances of this class. |
281 |
*/ |
282 |
ExprType_t exprType() const OVERRIDE { return INT_ARR_EXPR; } |
283 |
}; |
284 |
|
285 |
/** @brief Arguments (parameters) for being passed to a built-in script function. |
286 |
* |
287 |
* An argument or a set of arguments passed to a script function are |
288 |
* translated by the parser to an instance of this class. This abstract |
289 |
* interface class is used by implementations of built-in functions to |
290 |
* obtain the individual function argument values being passed to them at |
291 |
* runtime. |
292 |
*/ |
293 |
class VMFnArgs { |
294 |
public: |
295 |
/** |
296 |
* Returns the amount of arguments going to be passed to the script |
297 |
* function. |
298 |
*/ |
299 |
virtual int argsCount() const = 0; |
300 |
|
301 |
/** |
302 |
* Returns the respective argument (requested by argument index @a i) of |
303 |
* this set of arguments. This method is called by implementations of |
304 |
* built-in script functions to obtain the value of each function |
305 |
* argument passed to the function at runtime. |
306 |
* |
307 |
* @param i - function argument index (indexed from left to right) |
308 |
*/ |
309 |
virtual VMExpr* arg(int i) = 0; |
310 |
}; |
311 |
|
312 |
/** @brief Result value returned from a call to a built-in script function. |
313 |
* |
314 |
* Implementations of built-in script functions return an instance of this |
315 |
* object to let the virtual machine obtain the result value of the function |
316 |
* call, which might then be further processed by the virtual machine |
317 |
* according to the script. It also provides informations about the success |
318 |
* or failure of the function call. |
319 |
*/ |
320 |
class VMFnResult { |
321 |
public: |
322 |
/** |
323 |
* Returns the result value of the function call, represented by a high |
324 |
* level expression object. |
325 |
*/ |
326 |
virtual VMExpr* resultValue() = 0; |
327 |
|
328 |
/** |
329 |
* Provides detailed informations of the success / failure of the |
330 |
* function call. The virtual machine is evaluating the flags returned |
331 |
* here to decide whether it must abort or suspend execution of the |
332 |
* script at this point. |
333 |
*/ |
334 |
virtual StmtFlags_t resultFlags() { return STMT_SUCCESS; } |
335 |
}; |
336 |
|
337 |
/** @brief Virtual machine built-in function. |
338 |
* |
339 |
* Abstract base class for built-in script functions, defining the interface |
340 |
* for all built-in script function implementations. All built-in script |
341 |
* functions are deriving from this abstract interface class in order to |
342 |
* provide their functionality to the virtual machine with this unified |
343 |
* interface. |
344 |
* |
345 |
* The methods of this interface class provide two purposes: |
346 |
* |
347 |
* 1. When a script is loaded, the script parser uses the methods of this |
348 |
* interface to check whether the script author was calling the |
349 |
* respective built-in script function in a correct way. For example |
350 |
* the parser checks whether the required amount of parameters were |
351 |
* passed to the function and whether the data types passed match the |
352 |
* data types expected by the function. If not, loading the script will |
353 |
* be aborted with a parser error, describing to the user (i.e. script |
354 |
* author) the precise misusage of the respective function. |
355 |
* 2. After the script was loaded successfully and the script is executed, |
356 |
* the virtual machine calls the exec() method of the respective built-in |
357 |
* function to provide the actual functionality of the built-in function |
358 |
* call. |
359 |
*/ |
360 |
class VMFunction { |
361 |
public: |
362 |
/** |
363 |
* Script data type of the function's return value. If the function does |
364 |
* not return any value (void), then it returns EMPTY_EXPR here. |
365 |
*/ |
366 |
virtual ExprType_t returnType() = 0; |
367 |
|
368 |
/** |
369 |
* Minimum amount of function arguments this function accepts. If a |
370 |
* script is calling this function with less arguments, the script |
371 |
* parser will throw a parser error. |
372 |
*/ |
373 |
virtual int minRequiredArgs() const = 0; |
374 |
|
375 |
/** |
376 |
* Maximum amount of function arguments this functions accepts. If a |
377 |
* script is calling this function with more arguments, the script |
378 |
* parser will throw a parser error. |
379 |
*/ |
380 |
virtual int maxAllowedArgs() const = 0; |
381 |
|
382 |
/** |
383 |
* Script data type of the function's @c iArg 'th function argument. |
384 |
* The information provided here is less strong than acceptsArgType(). |
385 |
* The parser will compare argument data types provided in scripts by |
386 |
* calling acceptsArgType(). The return value of argType() is used by the |
387 |
* parser instead to show an appropriate parser error which data type |
388 |
* this function usually expects as "default" data type. Reason: a |
389 |
* function may accept multiple data types for a certain function |
390 |
* argument and would automatically cast the passed argument value in |
391 |
* that case to the type it actually needs. |
392 |
* |
393 |
* @param iArg - index of the function argument in question |
394 |
* (must be between 0 .. maxAllowedArgs() - 1) |
395 |
*/ |
396 |
virtual ExprType_t argType(int iArg) const = 0; |
397 |
|
398 |
/** |
399 |
* This method is called by the parser to check whether arguments |
400 |
* passed in scripts to this function are accepted by this function. If |
401 |
* a script calls this function with an argument's data type not |
402 |
* accepted by this function, the parser will throw a parser error. On |
403 |
* such errors the data type returned by argType() will be used to |
404 |
* assemble an appropriate error message regarding the precise misusage |
405 |
* of the built-in function. |
406 |
* |
407 |
* @param iArg - index of the function argument in question |
408 |
* (must be between 0 .. maxAllowedArgs() - 1) |
409 |
* @param type - script data type used for this function argument by |
410 |
* currently parsed script |
411 |
* @return true if the given data type would be accepted for the |
412 |
* respective function argument by the function |
413 |
*/ |
414 |
virtual bool acceptsArgType(int iArg, ExprType_t type) const = 0; |
415 |
|
416 |
/** |
417 |
* This method is called by the parser to check whether some arguments |
418 |
* (and if yes which ones) passed to this script function will be |
419 |
* modified by this script function. Most script functions simply use |
420 |
* their arguments as inputs, that is they only read the argument's |
421 |
* values. However some script function may also use passed |
422 |
* argument(s) as output variables. In this case the function |
423 |
* implementation must return @c true for the respective argument |
424 |
* index here. |
425 |
* |
426 |
* @param iArg - index of the function argument in question |
427 |
* (must be between 0 .. maxAllowedArgs() - 1) |
428 |
*/ |
429 |
virtual bool modifiesArg(int iArg) const = 0; |
430 |
|
431 |
/** |
432 |
* Implements the actual function execution. This exec() method is |
433 |
* called by the VM whenever this function implementation shall be |
434 |
* executed at script runtime. This method blocks until the function |
435 |
* call completed. |
436 |
* |
437 |
* @param args - function arguments for executing this built-in function |
438 |
* @returns function's return value (if any) and general status |
439 |
* informations (i.e. whether the function call caused a |
440 |
* runtime error) |
441 |
*/ |
442 |
virtual VMFnResult* exec(VMFnArgs* args) = 0; |
443 |
|
444 |
/** |
445 |
* Convenience method for function implementations to show warning |
446 |
* messages during actual execution of the built-in function. |
447 |
* |
448 |
* @param txt - runtime warning text to be shown to user |
449 |
*/ |
450 |
void wrnMsg(const String& txt); |
451 |
|
452 |
/** |
453 |
* Convenience method for function implementations to show error |
454 |
* messages during actual execution of the built-in function. |
455 |
* |
456 |
* @param txt - runtime error text to be shown to user |
457 |
*/ |
458 |
void errMsg(const String& txt); |
459 |
}; |
460 |
|
461 |
/** @brief Virtual machine relative pointer. |
462 |
* |
463 |
* POD base of VMIntRelPtr and VMInt8RelPtr structures. Not intended to be |
464 |
* used directly. Use VMIntRelPtr or VMInt8RelPtr instead. |
465 |
* |
466 |
* @see VMIntRelPtr, VMInt8RelPtr |
467 |
*/ |
468 |
struct VMRelPtr { |
469 |
void** base; ///< Base pointer. |
470 |
int offset; ///< Offset (in bytes) relative to base pointer. |
471 |
bool readonly; ///< Whether the pointed data may be modified or just be read. |
472 |
}; |
473 |
|
474 |
/** @brief Pointer to built-in VM integer variable (of C/C++ type int). |
475 |
* |
476 |
* Used for defining built-in 32 bit integer script variables. |
477 |
* |
478 |
* @b CAUTION: You may only use this class for pointing to C/C++ variables |
479 |
* of type "int" (which on most systems is 32 bit in size). If the C/C++ int |
480 |
* variable you want to reference is only 8 bit in size, then you @b must |
481 |
* use VMInt8RelPtr instead! |
482 |
* |
483 |
* For efficiency reasons the actual native C/C++ int variable is referenced |
484 |
* by two components here. The actual native int C/C++ variable in memory |
485 |
* is dereferenced at VM run-time by taking the @c base pointer dereference |
486 |
* and adding @c offset bytes. This has the advantage that for a large |
487 |
* number of built-in int variables, only one (or few) base pointer need |
488 |
* to be re-assigned before running a script, instead of updating each |
489 |
* built-in variable each time before a script is executed. |
490 |
* |
491 |
* Refer to DECLARE_VMINT() for example code. |
492 |
* |
493 |
* @see VMInt8RelPtr, DECLARE_VMINT() |
494 |
*/ |
495 |
struct VMIntRelPtr : VMRelPtr { |
496 |
VMIntRelPtr() { |
497 |
base = NULL; |
498 |
offset = 0; |
499 |
readonly = false; |
500 |
} |
501 |
VMIntRelPtr(const VMRelPtr& data) { |
502 |
base = data.base; |
503 |
offset = data.offset; |
504 |
readonly = false; |
505 |
} |
506 |
virtual int evalInt() { return *(int*)&(*(uint8_t**)base)[offset]; } |
507 |
virtual void assign(int i) { *(int*)&(*(uint8_t**)base)[offset] = i; } |
508 |
}; |
509 |
|
510 |
/** @brief Pointer to built-in VM integer variable (of C/C++ type int8_t). |
511 |
* |
512 |
* Used for defining built-in 8 bit integer script variables. |
513 |
* |
514 |
* @b CAUTION: You may only use this class for pointing to C/C++ variables |
515 |
* of type "int8_t" (8 bit integer). If the C/C++ int variable you want to |
516 |
* reference is an "int" type (which is 32 bit on most systems), then you |
517 |
* @b must use VMIntRelPtr instead! |
518 |
* |
519 |
* For efficiency reasons the actual native C/C++ int variable is referenced |
520 |
* by two components here. The actual native int C/C++ variable in memory |
521 |
* is dereferenced at VM run-time by taking the @c base pointer dereference |
522 |
* and adding @c offset bytes. This has the advantage that for a large |
523 |
* number of built-in int variables, only one (or few) base pointer need |
524 |
* to be re-assigned before running a script, instead of updating each |
525 |
* built-in variable each time before a script is executed. |
526 |
* |
527 |
* Refer to DECLARE_VMINT() for example code. |
528 |
* |
529 |
* @see VMIntRelPtr, DECLARE_VMINT() |
530 |
*/ |
531 |
struct VMInt8RelPtr : VMIntRelPtr { |
532 |
VMInt8RelPtr() : VMIntRelPtr() {} |
533 |
VMInt8RelPtr(const VMRelPtr& data) : VMIntRelPtr(data) {} |
534 |
virtual int evalInt() OVERRIDE { |
535 |
return *(uint8_t*)&(*(uint8_t**)base)[offset]; |
536 |
} |
537 |
virtual void assign(int i) OVERRIDE { |
538 |
*(uint8_t*)&(*(uint8_t**)base)[offset] = i; |
539 |
} |
540 |
}; |
541 |
|
542 |
/** |
543 |
* Convenience macro for initializing VMIntRelPtr and VMInt8RelPtr |
544 |
* structures. Usage example: |
545 |
* @code |
546 |
* struct Foo { |
547 |
* uint8_t a; // native representation of a built-in integer script variable |
548 |
* int b; // native representation of another built-in integer script variable |
549 |
* int c; // native representation of another built-in integer script variable |
550 |
* uint8_t d; // native representation of another built-in integer script variable |
551 |
* }; |
552 |
* |
553 |
* // initializing the built-in script variables to some values |
554 |
* Foo foo1 = (Foo) { 1, 2000, 3000, 4 }; |
555 |
* Foo foo2 = (Foo) { 5, 6000, 7000, 8 }; |
556 |
* |
557 |
* Foo* pFoo; |
558 |
* |
559 |
* VMInt8RelPtr varA = DECLARE_VMINT(pFoo, class Foo, a); |
560 |
* VMIntRelPtr varB = DECLARE_VMINT(pFoo, class Foo, b); |
561 |
* VMIntRelPtr varC = DECLARE_VMINT(pFoo, class Foo, c); |
562 |
* VMInt8RelPtr varD = DECLARE_VMINT(pFoo, class Foo, d); |
563 |
* |
564 |
* pFoo = &foo1; |
565 |
* printf("%d\n", varA->evalInt()); // will print 1 |
566 |
* printf("%d\n", varB->evalInt()); // will print 2000 |
567 |
* printf("%d\n", varC->evalInt()); // will print 3000 |
568 |
* printf("%d\n", varD->evalInt()); // will print 4 |
569 |
* |
570 |
* // same printf() code, just with pFoo pointer being changed ... |
571 |
* |
572 |
* pFoo = &foo2; |
573 |
* printf("%d\n", varA->evalInt()); // will print 5 |
574 |
* printf("%d\n", varB->evalInt()); // will print 6000 |
575 |
* printf("%d\n", varC->evalInt()); // will print 7000 |
576 |
* printf("%d\n", varD->evalInt()); // will print 8 |
577 |
* @endcode |
578 |
* As you can see above, by simply changing one single pointer, you can |
579 |
* remap a huge bunch of built-in integer script variables to completely |
580 |
* different native values/native variables. Which especially reduces code |
581 |
* complexity inside the sampler engines which provide the actual script |
582 |
* functionalities. |
583 |
*/ |
584 |
#define DECLARE_VMINT(basePtr, T_struct, T_member) ( \ |
585 |
(VMRelPtr) { \ |
586 |
(void**) &basePtr, \ |
587 |
offsetof(T_struct, T_member), \ |
588 |
false \ |
589 |
} \ |
590 |
) \ |
591 |
|
592 |
/** |
593 |
* Same as DECLARE_VMINT(), but this one defines the VMIntRelPtr and |
594 |
* VMInt8RelPtr structures to be of read-only type. That means the script |
595 |
* parser will abort any script at parser time if the script is trying to |
596 |
* modify such a read-only built-in variable. |
597 |
* |
598 |
* @b NOTE: this is only intended for built-in read-only variables that |
599 |
* may change during runtime! If your built-in variable's data is rather |
600 |
* already available at parser time and won't change during runtime, then |
601 |
* you should rather register a built-in constant in your VM class instead! |
602 |
* |
603 |
* @see ScriptVM::builtInConstIntVariables() |
604 |
*/ |
605 |
#define DECLARE_VMINT_READONLY(basePtr, T_struct, T_member) ( \ |
606 |
(VMRelPtr) { \ |
607 |
(void**) &basePtr, \ |
608 |
offsetof(T_struct, T_member), \ |
609 |
true \ |
610 |
} \ |
611 |
) \ |
612 |
|
613 |
/** @brief Built-in VM 8 bit integer array variable. |
614 |
* |
615 |
* Used for defining built-in integer array script variables (8 bit per |
616 |
* array element). Currently there is no support for any other kind of array |
617 |
* type. So all integer arrays of scripts use 8 bit data types. |
618 |
*/ |
619 |
struct VMInt8Array { |
620 |
int8_t* data; |
621 |
int size; |
622 |
|
623 |
VMInt8Array() : data(NULL), size(0) {} |
624 |
}; |
625 |
|
626 |
/** @brief Virtual machine script variable. |
627 |
* |
628 |
* Common interface for all variables accessed in scripts. |
629 |
*/ |
630 |
class VMVariable : virtual public VMExpr { |
631 |
public: |
632 |
/** |
633 |
* Whether a script may modify the content of this variable by |
634 |
* assigning a new value to it. |
635 |
* |
636 |
* @see isConstExpr(), assign() |
637 |
*/ |
638 |
virtual bool isAssignable() const = 0; |
639 |
|
640 |
/** |
641 |
* In case this variable is assignable, this method will be called to |
642 |
* perform the value assignment to this variable with @a expr |
643 |
* reflecting the new value to be assigned. |
644 |
* |
645 |
* @param expr - new value to be assigned to this variable |
646 |
*/ |
647 |
virtual void assignExpr(VMExpr* expr) = 0; |
648 |
}; |
649 |
|
650 |
/** @brief Dynamically executed variable (abstract base class). |
651 |
* |
652 |
* Interface for the implementation of a dynamically generated content of |
653 |
* a built-in script variable. Most built-in variables are simply pointers |
654 |
* to some native location in memory. So when a script reads them, the |
655 |
* memory location is simply read to get the value of the variable. A |
656 |
* dynamic variable however is not simply a memory location. For each access |
657 |
* to a dynamic variable some native code is executed to actually generate |
658 |
* and provide the content (value) of this type of variable. |
659 |
*/ |
660 |
class VMDynVar : public VMVariable { |
661 |
public: |
662 |
/** |
663 |
* Returns true in case this dynamic variable can be considered to be a |
664 |
* constant expression. A constant expression will retain the same value |
665 |
* throughout the entire life time of a script and the expression's |
666 |
* constant value may be evaluated already at script parse time, which |
667 |
* may result in performance benefits during script runtime. |
668 |
* |
669 |
* However due to the "dynamic" behavior of dynamic variables, almost |
670 |
* all dynamic variables are probably not constant expressions. That's |
671 |
* why this method returns @c false by default. If you are really sure |
672 |
* that your dynamic variable implementation can be considered a |
673 |
* constant expression then you may override this method and return |
674 |
* @c true instead. Note that when you return @c true here, your |
675 |
* dynamic variable will really just be executed once; and exectly |
676 |
* already when the script is loaded! |
677 |
* |
678 |
* As an example you may implement a "constant" built-in dynamic |
679 |
* variable that checks for a certain operating system feature and |
680 |
* returns the result of that OS feature check as content (value) of |
681 |
* this dynamic variable. Since the respective OS feature might become |
682 |
* available/unavailable after OS updates, software migration, etc. the |
683 |
* OS feature check should at least be performed once each time the |
684 |
* application is launched. And since the OS feature check might take a |
685 |
* certain amount of execution time, it might make sense to only |
686 |
* perform the check if the respective variable name is actually |
687 |
* referenced at all in the script to be loaded. Note that the dynamic |
688 |
* variable will still be evaluated again though if the script is |
689 |
* loaded again. So it is up to you to probably cache the result in the |
690 |
* implementation of your dynamic variable. |
691 |
* |
692 |
* On doubt, please rather consider to use a constant built-in script |
693 |
* variable instead of implementing a "constant" dynamic variable, due |
694 |
* to the runtime overhead a dynamic variable may cause. |
695 |
* |
696 |
* @see isAssignable() |
697 |
*/ |
698 |
bool isConstExpr() const OVERRIDE { return false; } |
699 |
|
700 |
/** |
701 |
* In case this dynamic variable is assignable, the new value (content) |
702 |
* to be assigned to this dynamic variable. |
703 |
* |
704 |
* By default this method does nothing. Override and implement this |
705 |
* method in your subclass in case your dynamic variable allows to |
706 |
* assign a new value by script. |
707 |
* |
708 |
* @param expr - new value to be assigned to this variable |
709 |
*/ |
710 |
void assignExpr(VMExpr* expr) OVERRIDE {} |
711 |
}; |
712 |
|
713 |
/** @brief Dynamically executed variable (of integer data type). |
714 |
* |
715 |
* This is the base class for all built-in integer script variables whose |
716 |
* variable content needs to be provided dynamically by executable native |
717 |
* code on each script variable access. |
718 |
*/ |
719 |
class VMDynIntVar : virtual public VMDynVar, virtual public VMIntExpr { |
720 |
public: |
721 |
}; |
722 |
|
723 |
/** @brief Dynamically executed variable (of string data type). |
724 |
* |
725 |
* This is the base class for all built-in string script variables whose |
726 |
* variable content needs to be provided dynamically by executable native |
727 |
* code on each script variable access. |
728 |
*/ |
729 |
class VMDynStringVar : virtual public VMDynVar, virtual public VMStringExpr { |
730 |
public: |
731 |
}; |
732 |
|
733 |
/** @brief Provider for built-in script functions and variables. |
734 |
* |
735 |
* Abstract base class defining the high-level interface for all classes |
736 |
* which add and implement built-in script functions and built-in script |
737 |
* variables. |
738 |
*/ |
739 |
class VMFunctionProvider { |
740 |
public: |
741 |
/** |
742 |
* Returns pointer to the built-in function with the given function |
743 |
* @a name, or NULL if there is no built-in function with that function |
744 |
* name. |
745 |
* |
746 |
* @param name - function name (i.e. "wait" or "message" or "exit", etc.) |
747 |
*/ |
748 |
virtual VMFunction* functionByName(const String& name) = 0; |
749 |
|
750 |
/** |
751 |
* Returns a variable name indexed map of all built-in script variables |
752 |
* which point to native "int" scalar (usually 32 bit) variables. |
753 |
*/ |
754 |
virtual std::map<String,VMIntRelPtr*> builtInIntVariables() = 0; |
755 |
|
756 |
/** |
757 |
* Returns a variable name indexed map of all built-in script integer |
758 |
* array variables with array element type "int8_t" (8 bit). |
759 |
*/ |
760 |
virtual std::map<String,VMInt8Array*> builtInIntArrayVariables() = 0; |
761 |
|
762 |
/** |
763 |
* Returns a variable name indexed map of all built-in constant script |
764 |
* variables, which never change their value at runtime. |
765 |
*/ |
766 |
virtual std::map<String,int> builtInConstIntVariables() = 0; |
767 |
|
768 |
/** |
769 |
* Returns a variable name indexed map of all built-in dynamic variables, |
770 |
* which are not simply data stores, rather each one of them executes |
771 |
* natively to provide or alter the respective script variable data. |
772 |
*/ |
773 |
virtual std::map<String,VMDynVar*> builtInDynamicVariables() = 0; |
774 |
}; |
775 |
|
776 |
/** @brief Execution state of a virtual machine. |
777 |
* |
778 |
* An instance of this abstract base class represents exactly one execution |
779 |
* state of a virtual machine. This encompasses most notably the VM |
780 |
* execution stack, and VM polyphonic variables. It does not contain global |
781 |
* variables. Global variables are contained in the VMParserContext object. |
782 |
* You might see a VMExecContext object as one virtual thread of the virtual |
783 |
* machine. |
784 |
* |
785 |
* In contrast to a VMParserContext, a VMExecContext is not tied to a |
786 |
* ScriptVM instance. Thus you can use a VMExecContext with different |
787 |
* ScriptVM instances, however not concurrently at the same time. |
788 |
* |
789 |
* @see VMParserContext |
790 |
*/ |
791 |
class VMExecContext { |
792 |
public: |
793 |
virtual ~VMExecContext() {} |
794 |
|
795 |
/** |
796 |
* In case the script was suspended for some reason, this method returns |
797 |
* the amount of microseconds before the script shall continue its |
798 |
* execution. Note that the virtual machine itself does never put its |
799 |
* own execution thread(s) to sleep. So the respective class (i.e. sampler |
800 |
* engine) which is using the virtual machine classes here, must take |
801 |
* care by itself about taking time stamps, determining the script |
802 |
* handlers that shall be put aside for the requested amount of |
803 |
* microseconds, indicated by this method by comparing the time stamps in |
804 |
* real-time, and to continue passing the respective handler to |
805 |
* ScriptVM::exec() as soon as its suspension exceeded, etc. Or in other |
806 |
* words: all classes in this directory never have an idea what time it |
807 |
* is. |
808 |
* |
809 |
* You should check the return value of ScriptVM::exec() to determine |
810 |
* whether the script was actually suspended before calling this method |
811 |
* here. |
812 |
* |
813 |
* @see ScriptVM::exec() |
814 |
*/ |
815 |
virtual int suspensionTimeMicroseconds() const = 0; |
816 |
}; |
817 |
|
818 |
/** @brief Script callback for a certain event. |
819 |
* |
820 |
* Represents a script callback for a certain event, i.e. |
821 |
* "on note ... end on" code block. |
822 |
*/ |
823 |
class VMEventHandler { |
824 |
public: |
825 |
/** |
826 |
* Type of this event handler, which identifies its purpose. For example |
827 |
* for a "on note ... end on" script callback block, |
828 |
* @c VM_EVENT_HANDLER_NOTE would be returned here. |
829 |
*/ |
830 |
virtual VMEventHandlerType_t eventHandlerType() const = 0; |
831 |
|
832 |
/** |
833 |
* Name of the event handler which identifies its purpose. For example |
834 |
* for a "on note ... end on" script callback block, the name "note" |
835 |
* would be returned here. |
836 |
*/ |
837 |
virtual String eventHandlerName() const = 0; |
838 |
|
839 |
/** |
840 |
* Whether or not the event handler makes any use of so called |
841 |
* "polyphonic" variables. |
842 |
*/ |
843 |
virtual bool isPolyphonic() const = 0; |
844 |
}; |
845 |
|
846 |
/** |
847 |
* Encapsulates a noteworty parser issue. This encompasses the type of the |
848 |
* issue (either a parser error or parser warning), a human readable |
849 |
* explanation text of the error or warning and the location of the |
850 |
* encountered parser issue within the script. |
851 |
*/ |
852 |
struct ParserIssue { |
853 |
String txt; ///< Human readable explanation text of the parser issue. |
854 |
int firstLine; ///< The first line number within the script where this issue was encountered (indexed with 1 being the very first line). |
855 |
int lastLine; ///< The last line number within the script where this issue was encountered. |
856 |
int firstColumn; ///< The first column within the script where this issue was encountered (indexed with 1 being the very first column). |
857 |
int lastColumn; ///< The last column within the script where this issue was encountered. |
858 |
ParserIssueType_t type; ///< Whether this issue is either a parser error or just a parser warning. |
859 |
|
860 |
/** |
861 |
* Print this issue out to the console (stdio). |
862 |
*/ |
863 |
inline void dump() { |
864 |
switch (type) { |
865 |
case PARSER_ERROR: |
866 |
printf("[ERROR] line %d, column %d: %s\n", firstLine, firstColumn, txt.c_str()); |
867 |
break; |
868 |
case PARSER_WARNING: |
869 |
printf("[Warning] line %d, column %d: %s\n", firstLine, firstColumn, txt.c_str()); |
870 |
break; |
871 |
} |
872 |
} |
873 |
|
874 |
/** |
875 |
* Returns true if this issue is a parser error. In this case the parsed |
876 |
* script may not be executed! |
877 |
*/ |
878 |
inline bool isErr() const { return type == PARSER_ERROR; } |
879 |
|
880 |
/** |
881 |
* Returns true if this issue is just a parser warning. A parsed script |
882 |
* that only raises warnings may be executed if desired, however the |
883 |
* script may not behave exactly as intended by the script author. |
884 |
*/ |
885 |
inline bool isWrn() const { return type == PARSER_WARNING; } |
886 |
}; |
887 |
|
888 |
/** |
889 |
* Convenience function used for converting an ExprType_t constant to a |
890 |
* string, i.e. for generating error message by the parser. |
891 |
*/ |
892 |
inline String typeStr(const ExprType_t& type) { |
893 |
switch (type) { |
894 |
case EMPTY_EXPR: return "empty"; |
895 |
case INT_EXPR: return "integer"; |
896 |
case INT_ARR_EXPR: return "integer array"; |
897 |
case STRING_EXPR: return "string"; |
898 |
case STRING_ARR_EXPR: return "string array"; |
899 |
} |
900 |
return "invalid"; |
901 |
} |
902 |
|
903 |
/** @brief Virtual machine representation of a script. |
904 |
* |
905 |
* An instance of this abstract base class represents a parsed script, |
906 |
* translated into a virtual machine tree. You should first check if there |
907 |
* were any parser errors. If there were any parser errors, you should |
908 |
* refrain from executing the virtual machine. Otherwise if there were no |
909 |
* parser errors (i.e. only warnings), then you might access one of the |
910 |
* script's event handlers by i.e. calling eventHandlerByName() and pass the |
911 |
* respective event handler to the ScriptVM class (or to one of the ScriptVM |
912 |
* descendants) for execution. |
913 |
* |
914 |
* @see VMExecContext, ScriptVM |
915 |
*/ |
916 |
class VMParserContext { |
917 |
public: |
918 |
virtual ~VMParserContext() {} |
919 |
|
920 |
/** |
921 |
* Returns all noteworthy issues encountered when the script was parsed. |
922 |
* These are parser errors and parser warnings. |
923 |
*/ |
924 |
virtual std::vector<ParserIssue> issues() const = 0; |
925 |
|
926 |
/** |
927 |
* Same as issues(), but this method only returns parser errors. |
928 |
*/ |
929 |
virtual std::vector<ParserIssue> errors() const = 0; |
930 |
|
931 |
/** |
932 |
* Same as issues(), but this method only returns parser warnings. |
933 |
*/ |
934 |
virtual std::vector<ParserIssue> warnings() const = 0; |
935 |
|
936 |
/** |
937 |
* Returns the translated virtual machine representation of an event |
938 |
* handler block (i.e. "on note ... end on" code block) within the |
939 |
* parsed script. This translated representation of the event handler |
940 |
* can be executed by the virtual machine. |
941 |
* |
942 |
* @param index - index of the event handler within the script |
943 |
*/ |
944 |
virtual VMEventHandler* eventHandler(uint index) = 0; |
945 |
|
946 |
/** |
947 |
* Same as eventHandler(), but this method returns the event handler by |
948 |
* its name. So for a "on note ... end on" code block of the parsed |
949 |
* script you would pass "note" for argument @a name here. |
950 |
* |
951 |
* @param name - name of the event handler (i.e. "init", "note", |
952 |
* "controller", "release") |
953 |
*/ |
954 |
virtual VMEventHandler* eventHandlerByName(const String& name) = 0; |
955 |
}; |
956 |
|
957 |
class SourceToken; |
958 |
|
959 |
/** @brief Recognized token of a script's source code. |
960 |
* |
961 |
* Represents one recognized token of a script's source code, for example |
962 |
* a keyword, variable name, etc. and it provides further informations about |
963 |
* that particular token, i.e. the precise location (line and column) of the |
964 |
* token within the original script's source code. |
965 |
* |
966 |
* This class is not actually used by the sampler itself. It is rather |
967 |
* provided for external script editor applications. Primary purpose of |
968 |
* this class is syntax highlighting for external script editors. |
969 |
*/ |
970 |
class VMSourceToken { |
971 |
public: |
972 |
VMSourceToken(); |
973 |
VMSourceToken(SourceToken* ct); |
974 |
VMSourceToken(const VMSourceToken& other); |
975 |
virtual ~VMSourceToken(); |
976 |
|
977 |
// original text of this token as it is in the script's source code |
978 |
String text() const; |
979 |
|
980 |
// position of token in script |
981 |
int firstLine() const; ///< First line this source token is located at in script source code (indexed with 0 being the very first line). |
982 |
int firstColumn() const; ///< Last line this source token is located at in script source code. |
983 |
|
984 |
// base types |
985 |
bool isEOF() const; |
986 |
bool isNewLine() const; |
987 |
bool isKeyword() const; |
988 |
bool isVariableName() const; |
989 |
bool isIdentifier() const; |
990 |
bool isNumberLiteral() const; |
991 |
bool isStringLiteral() const; |
992 |
bool isComment() const; |
993 |
bool isPreprocessor() const; |
994 |
bool isOther() const; |
995 |
|
996 |
// extended types |
997 |
bool isIntegerVariable() const; |
998 |
bool isStringVariable() const; |
999 |
bool isArrayVariable() const; |
1000 |
bool isEventHandlerName() const; |
1001 |
|
1002 |
VMSourceToken& operator=(const VMSourceToken& other); |
1003 |
|
1004 |
private: |
1005 |
SourceToken* m_token; |
1006 |
}; |
1007 |
|
1008 |
} // namespace LinuxSampler |
1009 |
|
1010 |
#endif // LS_INSTR_SCRIPT_PARSER_COMMON_H |