160 |
* @see exprType() |
* @see exprType() |
161 |
*/ |
*/ |
162 |
VMIntArrayExpr* asIntArray() const; |
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 |
|
virtual bool isConstExpr() const = 0; |
173 |
|
|
174 |
|
bool isModifyable() const; |
175 |
}; |
}; |
176 |
|
|
177 |
/** @brief Virtual machine integer expression |
/** @brief Virtual machine integer expression |
378 |
virtual ExprType_t argType(int iArg) const = 0; |
virtual ExprType_t argType(int iArg) const = 0; |
379 |
|
|
380 |
/** |
/** |
381 |
* This function is called by the parser to check whether arguments |
* This method is called by the parser to check whether arguments |
382 |
* passed in scripts to this function are accepted by this function. If |
* passed in scripts to this function are accepted by this function. If |
383 |
* a script calls this function with an argument's data type not |
* a script calls this function with an argument's data type not |
384 |
* accepted by this function, the parser will throw a parser error. On |
* accepted by this function, the parser will throw a parser error. On |
396 |
virtual bool acceptsArgType(int iArg, ExprType_t type) const = 0; |
virtual bool acceptsArgType(int iArg, ExprType_t type) const = 0; |
397 |
|
|
398 |
/** |
/** |
399 |
|
* This method is called by the parser to check whether some arguments |
400 |
|
* (and if yes which ones) passed to this script function will be |
401 |
|
* modified by this script function. Most script functions simply use |
402 |
|
* their arguments as inputs, that is they only read the argument's |
403 |
|
* values. However some script function may also use passed |
404 |
|
* argument(s) as output variables. In this case the function |
405 |
|
* implementation must return @c true for the respective argument |
406 |
|
* index here. |
407 |
|
* |
408 |
|
* @param iArg - index of the function argument in question |
409 |
|
* (must be between 0 .. maxAllowedArgs() - 1) |
410 |
|
*/ |
411 |
|
virtual bool modifiesArg(int iArg) const = 0; |
412 |
|
|
413 |
|
/** |
414 |
* Implements the actual function execution. This exec() method is |
* Implements the actual function execution. This exec() method is |
415 |
* called by the VM whenever this function implementation shall be |
* called by the VM whenever this function implementation shall be |
416 |
* executed at script runtime. This method blocks until the function |
* executed at script runtime. This method blocks until the function |
450 |
struct VMRelPtr { |
struct VMRelPtr { |
451 |
void** base; ///< Base pointer. |
void** base; ///< Base pointer. |
452 |
int offset; ///< Offset (in bytes) relative to base pointer. |
int offset; ///< Offset (in bytes) relative to base pointer. |
453 |
|
bool readonly; ///< Whether the pointed data may be modified or just be read. |
454 |
}; |
}; |
455 |
|
|
456 |
/** @brief Pointer to built-in VM integer variable (of C/C++ type int). |
/** @brief Pointer to built-in VM integer variable (of C/C++ type int). |
478 |
VMIntRelPtr() { |
VMIntRelPtr() { |
479 |
base = NULL; |
base = NULL; |
480 |
offset = 0; |
offset = 0; |
481 |
|
readonly = false; |
482 |
} |
} |
483 |
VMIntRelPtr(const VMRelPtr& data) { |
VMIntRelPtr(const VMRelPtr& data) { |
484 |
base = data.base; |
base = data.base; |
485 |
offset = data.offset; |
offset = data.offset; |
486 |
|
readonly = false; |
487 |
} |
} |
488 |
virtual int evalInt() { return *(int*)&(*(uint8_t**)base)[offset]; } |
virtual int evalInt() { return *(int*)&(*(uint8_t**)base)[offset]; } |
489 |
virtual void assign(int i) { *(int*)&(*(uint8_t**)base)[offset] = i; } |
virtual void assign(int i) { *(int*)&(*(uint8_t**)base)[offset] = i; } |
566 |
#define DECLARE_VMINT(basePtr, T_struct, T_member) ( \ |
#define DECLARE_VMINT(basePtr, T_struct, T_member) ( \ |
567 |
(VMRelPtr) { \ |
(VMRelPtr) { \ |
568 |
(void**) &basePtr, \ |
(void**) &basePtr, \ |
569 |
offsetof(T_struct, T_member) \ |
offsetof(T_struct, T_member), \ |
570 |
|
false \ |
571 |
} \ |
} \ |
572 |
) \ |
) \ |
573 |
|
|
574 |
|
/** |
575 |
|
* Same as DECLARE_VMINT(), but this one defines the VMIntRelPtr and |
576 |
|
* VMInt8RelPtr structures to be of read-only type. That means the script |
577 |
|
* parser will abort any script at parser time if the script is trying to |
578 |
|
* modify such a read-only built-in variable. |
579 |
|
* |
580 |
|
* @b NOTE: this is only intended for built-in read-only variables that |
581 |
|
* may change during runtime! If your built-in variable's data is rather |
582 |
|
* already available at parser time and won't change during runtime, then |
583 |
|
* you should rather register a built-in constant in your VM class instead! |
584 |
|
* |
585 |
|
* @see ScriptVM::builtInConstIntVariables() |
586 |
|
*/ |
587 |
|
#define DECLARE_VMINT_READONLY(basePtr, T_struct, T_member) ( \ |
588 |
|
(VMRelPtr) { \ |
589 |
|
(void**) &basePtr, \ |
590 |
|
offsetof(T_struct, T_member), \ |
591 |
|
true \ |
592 |
|
} \ |
593 |
|
) \ |
594 |
|
|
595 |
/** @brief Built-in VM 8 bit integer array variable. |
/** @brief Built-in VM 8 bit integer array variable. |
596 |
* |
* |
597 |
* Used for defining built-in integer array script variables (8 bit per |
* Used for defining built-in integer array script variables (8 bit per |
605 |
VMInt8Array() : data(NULL), size(0) {} |
VMInt8Array() : data(NULL), size(0) {} |
606 |
}; |
}; |
607 |
|
|
608 |
|
/** @brief Virtual machine script variable. |
609 |
|
* |
610 |
|
* Common interface for all variables accessed in scripts. |
611 |
|
*/ |
612 |
|
class VMVariable : virtual public VMExpr { |
613 |
|
public: |
614 |
|
/** |
615 |
|
* Whether a script may modify the content of this variable by |
616 |
|
* assigning a new value to it. |
617 |
|
* |
618 |
|
* @see isConstExpr(), assign() |
619 |
|
*/ |
620 |
|
virtual bool isAssignable() const = 0; |
621 |
|
|
622 |
|
/** |
623 |
|
* In case this variable is assignable, this method will be called to |
624 |
|
* perform the value assignment to this variable with @a expr |
625 |
|
* reflecting the new value to be assigned. |
626 |
|
* |
627 |
|
* @param expr - new value to be assigned to this variable |
628 |
|
*/ |
629 |
|
virtual void assignExpr(VMExpr* expr) = 0; |
630 |
|
}; |
631 |
|
|
632 |
|
/** @brief Dynamically executed variable (abstract base class). |
633 |
|
* |
634 |
|
* Interface for the implementation of a dynamically generated content of |
635 |
|
* a built-in script variable. Most built-in variables are simply pointers |
636 |
|
* to some native location in memory. So when a script reads them, the |
637 |
|
* memory location is simply read to get the value of the variable. A |
638 |
|
* dynamic variable however is not simply a memory location. For each access |
639 |
|
* to a dynamic variable some native code is executed to actually generate |
640 |
|
* and provide the content (value) of this type of variable. |
641 |
|
*/ |
642 |
|
class VMDynVar : public VMVariable { |
643 |
|
public: |
644 |
|
/** |
645 |
|
* Returns true in case this dynamic variable can be considered to be a |
646 |
|
* constant expression. A constant expression will retain the same value |
647 |
|
* throughout the entire life time of a script and the expression's |
648 |
|
* constant value may be evaluated already at script parse time, which |
649 |
|
* may result in performance benefits during script runtime. |
650 |
|
* |
651 |
|
* However due to the "dynamic" behavior of dynamic variables, almost |
652 |
|
* all dynamic variables are probably not constant expressions. That's |
653 |
|
* why this method returns @c false by default. If you are really sure |
654 |
|
* that your dynamic variable implementation can be considered a |
655 |
|
* constant expression then you may override this method and return |
656 |
|
* @c true instead. Note that when you return @c true here, your |
657 |
|
* dynamic variable will really just be executed once; and exectly |
658 |
|
* already when the script is loaded! |
659 |
|
* |
660 |
|
* As an example you may implement a "constant" built-in dynamic |
661 |
|
* variable that checks for a certain operating system feature and |
662 |
|
* returns the result of that OS feature check as content (value) of |
663 |
|
* this dynamic variable. Since the respective OS feature might become |
664 |
|
* available/unavailable after OS updates, software migration, etc. the |
665 |
|
* OS feature check should at least be performed once each time the |
666 |
|
* application is launched. And since the OS feature check might take a |
667 |
|
* certain amount of execution time, it might make sense to only |
668 |
|
* perform the check if the respective variable name is actually |
669 |
|
* referenced at all in the script to be loaded. Note that the dynamic |
670 |
|
* variable will still be evaluated again though if the script is |
671 |
|
* loaded again. So it is up to you to probably cache the result in the |
672 |
|
* implementation of your dynamic variable. |
673 |
|
* |
674 |
|
* On doubt, please rather consider to use a constant built-in script |
675 |
|
* variable instead of implementing a "constant" dynamic variable, due |
676 |
|
* to the runtime overhead a dynamic variable may cause. |
677 |
|
* |
678 |
|
* @see isAssignable() |
679 |
|
*/ |
680 |
|
bool isConstExpr() const OVERRIDE { return false; } |
681 |
|
|
682 |
|
/** |
683 |
|
* In case this dynamic variable is assignable, the new value (content) |
684 |
|
* to be assigned to this dynamic variable. |
685 |
|
* |
686 |
|
* By default this method does nothing. Override and implement this |
687 |
|
* method in your subclass in case your dynamic variable allows to |
688 |
|
* assign a new value by script. |
689 |
|
* |
690 |
|
* @param expr - new value to be assigned to this variable |
691 |
|
*/ |
692 |
|
void assignExpr(VMExpr* expr) OVERRIDE {} |
693 |
|
}; |
694 |
|
|
695 |
|
/** @brief Dynamically executed variable (of integer data type). |
696 |
|
* |
697 |
|
* This is the base class for all built-in integer script variables whose |
698 |
|
* variable content needs to be provided dynamically by executable native |
699 |
|
* code on each script variable access. |
700 |
|
*/ |
701 |
|
class VMDynIntVar : virtual public VMDynVar, virtual public VMIntExpr { |
702 |
|
public: |
703 |
|
}; |
704 |
|
|
705 |
|
/** @brief Dynamically executed variable (of string data type). |
706 |
|
* |
707 |
|
* This is the base class for all built-in string script variables whose |
708 |
|
* variable content needs to be provided dynamically by executable native |
709 |
|
* code on each script variable access. |
710 |
|
*/ |
711 |
|
class VMDynStringVar : virtual public VMDynVar, virtual public VMStringExpr { |
712 |
|
public: |
713 |
|
}; |
714 |
|
|
715 |
/** @brief Provider for built-in script functions and variables. |
/** @brief Provider for built-in script functions and variables. |
716 |
* |
* |
717 |
* Abstract base class defining the high-level interface for all classes |
* Abstract base class defining the high-level interface for all classes |
746 |
* variables, which never change their value at runtime. |
* variables, which never change their value at runtime. |
747 |
*/ |
*/ |
748 |
virtual std::map<String,int> builtInConstIntVariables() = 0; |
virtual std::map<String,int> builtInConstIntVariables() = 0; |
749 |
|
|
750 |
|
/** |
751 |
|
* Returns a variable name indexed map of all built-in dynamic variables, |
752 |
|
* which are not simply data stores, rather each one of them executes |
753 |
|
* natively to provide or alter the respective script variable data. |
754 |
|
*/ |
755 |
|
virtual std::map<String,VMDynVar*> builtInDynamicVariables() = 0; |
756 |
}; |
}; |
757 |
|
|
758 |
/** @brief Execution state of a virtual machine. |
/** @brief Execution state of a virtual machine. |
833 |
*/ |
*/ |
834 |
struct ParserIssue { |
struct ParserIssue { |
835 |
String txt; ///< Human readable explanation text of the parser issue. |
String txt; ///< Human readable explanation text of the parser issue. |
836 |
int line; ///< Line number within the script where this issue was encountered. |
int firstLine; ///< The first line number within the script where this issue was encountered (indexed with 1 being the very first line). |
837 |
|
int lastLine; ///< The last line number within the script where this issue was encountered. |
838 |
|
int firstColumn; ///< The first column within the script where this issue was encountered (indexed with 1 being the very first column). |
839 |
|
int lastColumn; ///< The last column within the script where this issue was encountered. |
840 |
ParserIssueType_t type; ///< Whether this issue is either a parser error or just a parser warning. |
ParserIssueType_t type; ///< Whether this issue is either a parser error or just a parser warning. |
841 |
|
|
842 |
/** |
/** |
845 |
inline void dump() { |
inline void dump() { |
846 |
switch (type) { |
switch (type) { |
847 |
case PARSER_ERROR: |
case PARSER_ERROR: |
848 |
printf("[ERROR] line %d: %s\n", line, txt.c_str()); |
printf("[ERROR] line %d, column %d: %s\n", firstLine, firstColumn, txt.c_str()); |
849 |
break; |
break; |
850 |
case PARSER_WARNING: |
case PARSER_WARNING: |
851 |
printf("[Warning] line %d: %s\n", line, txt.c_str()); |
printf("[Warning] line %d, column %d: %s\n", firstLine, firstColumn, txt.c_str()); |
852 |
break; |
break; |
853 |
} |
} |
854 |
} |
} |
936 |
virtual VMEventHandler* eventHandlerByName(const String& name) = 0; |
virtual VMEventHandler* eventHandlerByName(const String& name) = 0; |
937 |
}; |
}; |
938 |
|
|
939 |
|
class SourceToken; |
940 |
|
|
941 |
|
/** @brief Recognized token of a script's source code. |
942 |
|
* |
943 |
|
* Represents one recognized token of a script's source code, for example |
944 |
|
* a keyword, variable name, etc. and it provides further informations about |
945 |
|
* that particular token, i.e. the precise location (line and column) of the |
946 |
|
* token within the original script's source code. |
947 |
|
* |
948 |
|
* This class is not actually used by the sampler itself. It is rather |
949 |
|
* provided for external script editor applications. Primary purpose of |
950 |
|
* this class is syntax highlighting for external script editors. |
951 |
|
*/ |
952 |
|
class VMSourceToken { |
953 |
|
public: |
954 |
|
VMSourceToken(); |
955 |
|
VMSourceToken(SourceToken* ct); |
956 |
|
VMSourceToken(const VMSourceToken& other); |
957 |
|
virtual ~VMSourceToken(); |
958 |
|
|
959 |
|
// original text of this token as it is in the script's source code |
960 |
|
String text() const; |
961 |
|
|
962 |
|
// position of token in script |
963 |
|
int firstLine() const; ///< First line this source token is located at in script source code (indexed with 0 being the very first line). |
964 |
|
int firstColumn() const; ///< Last line this source token is located at in script source code. |
965 |
|
|
966 |
|
// base types |
967 |
|
bool isEOF() const; |
968 |
|
bool isNewLine() const; |
969 |
|
bool isKeyword() const; |
970 |
|
bool isVariableName() const; |
971 |
|
bool isIdentifier() const; |
972 |
|
bool isNumberLiteral() const; |
973 |
|
bool isStringLiteral() const; |
974 |
|
bool isComment() const; |
975 |
|
bool isPreprocessor() const; |
976 |
|
bool isOther() const; |
977 |
|
|
978 |
|
// extended types |
979 |
|
bool isIntegerVariable() const; |
980 |
|
bool isStringVariable() const; |
981 |
|
bool isArrayVariable() const; |
982 |
|
bool isEventHandlerName() const; |
983 |
|
|
984 |
|
VMSourceToken& operator=(const VMSourceToken& other); |
985 |
|
|
986 |
|
private: |
987 |
|
SourceToken* m_token; |
988 |
|
}; |
989 |
|
|
990 |
} // namespace LinuxSampler |
} // namespace LinuxSampler |
991 |
|
|
992 |
#endif // LS_INSTR_SCRIPT_PARSER_COMMON_H |
#endif // LS_INSTR_SCRIPT_PARSER_COMMON_H |