/[svn]/linuxsampler/trunk/src/scriptvm/ScriptVM.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/scriptvm/ScriptVM.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2611 - (hide annotations) (download)
Mon Jun 9 19:20:37 2014 UTC (9 years, 10 months ago) by schoenebeck
File size: 11258 byte(s)
* Fixed crash when loading an instrument script.
* Fixed "init" script handler only to be executed once:
  when the script was loaded.
* Fixed aftertouch script event which always had value zero
  and controller number was set to aftertouch value instead.
* gig Engine: Fixed handling of "smartmidi" dimension, which
  was recognized as "unknown" dimension.
* Fixed script function gig_set_dim_zone(): was accessing
  wrong event.
* ls_instr_script command line tool: is now not limited to
  core language scripts, but can now also parse sampler format
  dependent instrument scripts, with the respective specific
  built-in script variables and functions.
* ScriptVM: Fixed runtime behavior of "and" and "or" binary
  script expressions, which also evaluated the right hand side
  of the expression even if the left hand side already failed
  the overall expression semantic to become true.
* Bumped version (1.0.0.svn46).

1 schoenebeck 2581 /*
2     * Copyright (c) 2014 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     #include "ScriptVM.h"
11    
12 schoenebeck 2588 #include <string.h>
13 schoenebeck 2581 #include "../common/global_private.h"
14     #include "tree.h"
15    
16     #define DEBUG_SCRIPTVM_CORE 0
17    
18     int InstrScript_parse(LinuxSampler::ParserContext*);
19    
20     namespace LinuxSampler {
21    
22     static void _printIndents(int n) {
23     for (int i = 0; i < n; ++i) printf(" ");
24     fflush(stdout);
25     }
26    
27     static int _requiredMaxStackSizeFor(Statement* statement, int depth = 0) {
28     if (!statement) return 1;
29    
30     switch (statement->statementType()) {
31     case STMT_LEAF:
32     #if DEBUG_SCRIPTVM_CORE
33     _printIndents(depth);
34     printf("-> STMT_LEAF\n");
35     #endif
36     return 1;
37    
38     case STMT_LIST: {
39     #if DEBUG_SCRIPTVM_CORE
40     _printIndents(depth);
41     printf("-> STMT_LIST\n");
42     #endif
43     Statements* stmts = (Statements*) statement;
44     int max = 0;
45     for (int i = 0; stmts->statement(i); ++i) {
46     int size = _requiredMaxStackSizeFor( stmts->statement(i), depth+1 );
47     if (max < size) max = size;
48     }
49     return max + 1;
50     }
51    
52     case STMT_BRANCH: {
53     #if DEBUG_SCRIPTVM_CORE
54     _printIndents(depth);
55     printf("-> STMT_BRANCH\n");
56     #endif
57     BranchStatement* branchStmt = (BranchStatement*) statement;
58     int max = 0;
59     for (int i = 0; branchStmt->branch(i); ++i) {
60     int size = _requiredMaxStackSizeFor( branchStmt->branch(i), depth+1 );
61     if (max < size) max = size;
62     }
63     return max + 1;
64     }
65    
66     case STMT_LOOP: {
67     #if DEBUG_SCRIPTVM_CORE
68     _printIndents(depth);
69     printf("-> STMT_LOOP\n");
70     #endif
71     While* whileStmt = (While*) statement;
72     if (whileStmt->statements())
73     return _requiredMaxStackSizeFor( whileStmt->statements() ) + 1;
74     else
75     return 1;
76     }
77     }
78    
79     return 1; // actually just to avoid compiler warning
80     }
81    
82     static int _requiredMaxStackSizeFor(EventHandlers* handlers) {
83     int max = 1;
84     for (int i = 0; i < handlers->size(); ++i) {
85     int size = _requiredMaxStackSizeFor(handlers->eventHandler(i));
86     if (max < size) max = size;
87     }
88     return max;
89     }
90    
91 schoenebeck 2588 ScriptVM::ScriptVM() : m_parserContext(NULL), fnWait(this) {
92 schoenebeck 2581 }
93    
94     ScriptVM::~ScriptVM() {
95     }
96    
97 schoenebeck 2588 VMParserContext* ScriptVM::loadScript(const String& s) {
98 schoenebeck 2581 std::istringstream iss(s);
99 schoenebeck 2588 return loadScript(&iss);
100 schoenebeck 2581 }
101    
102 schoenebeck 2588 VMParserContext* ScriptVM::loadScript(std::istream* is) {
103     ParserContext* context = new ParserContext(this);
104     //printf("parserCtx=0x%lx\n", (uint64_t)context);
105 schoenebeck 2594
106     context->registerBuiltInConstIntVariables( builtInConstIntVariables() );
107     context->registerBuiltInIntVariables( builtInIntVariables() );
108     context->registerBuiltInIntArrayVariables( builtInIntArrayVariables() );
109    
110 schoenebeck 2588 context->createScanner(is);
111 schoenebeck 2581
112 schoenebeck 2588 InstrScript_parse(context);
113 schoenebeck 2611 dmsg(2,("Allocating %d bytes of global int VM memory.\n", context->globalIntVarCount * sizeof(int)));
114     dmsg(2,("Allocating %d of global VM string variables.\n", context->globalStrVarCount));
115 schoenebeck 2588 if (!context->globalIntMemory)
116     context->globalIntMemory = new ArrayList<int>();
117     if (!context->globalStrMemory)
118     context->globalStrMemory = new ArrayList<String>();
119     context->globalIntMemory->resize(context->globalIntVarCount);
120     memset(&((*context->globalIntMemory)[0]), 0, context->globalIntVarCount * sizeof(int));
121    
122     context->globalStrMemory->resize(context->globalStrVarCount);
123 schoenebeck 2581
124 schoenebeck 2588 context->destroyScanner();
125 schoenebeck 2581
126 schoenebeck 2588 return context;
127 schoenebeck 2581 }
128    
129 schoenebeck 2588 void ScriptVM::dumpParsedScript(VMParserContext* context) {
130     ParserContext* ctx = dynamic_cast<ParserContext*>(context);
131     if (!ctx) {
132 schoenebeck 2581 std::cerr << "No VM context. So nothing to dump.\n";
133     return;
134     }
135 schoenebeck 2588 if (!ctx->handlers) {
136 schoenebeck 2581 std::cerr << "No event handlers defined in script. So nothing to dump.\n";
137     return;
138     }
139 schoenebeck 2588 if (!ctx->globalIntMemory) {
140 schoenebeck 2581 std::cerr << "Internal error: no global memory assigend to script VM.\n";
141     return;
142     }
143 schoenebeck 2588 ctx->handlers->dump();
144 schoenebeck 2581 }
145    
146 schoenebeck 2588 VMExecContext* ScriptVM::createExecContext(VMParserContext* parserContext) {
147     ParserContext* parserCtx = dynamic_cast<ParserContext*>(parserContext);
148     ExecContext* execCtx = new ExecContext();
149    
150     if (parserCtx->requiredMaxStackSize < 0) {
151     parserCtx->requiredMaxStackSize =
152     _requiredMaxStackSizeFor(&*parserCtx->handlers);
153     }
154     execCtx->stack.resize(parserCtx->requiredMaxStackSize);
155 schoenebeck 2611 dmsg(2,("Created VM exec context with %d bytes VM stack size.\n",
156     parserCtx->requiredMaxStackSize * sizeof(ExecContext::StackFrame)));
157 schoenebeck 2588 //printf("execCtx=0x%lx\n", (uint64_t)execCtx);
158     const int polySize = parserCtx->polyphonicIntVarCount;
159     execCtx->polyphonicIntMemory.resize(polySize);
160     memset(&execCtx->polyphonicIntMemory[0], 0, polySize * sizeof(int));
161    
162 schoenebeck 2611 dmsg(2,("Allocated %d bytes polyphonic memory.\n", polySize * sizeof(int)));
163 schoenebeck 2588 return execCtx;
164 schoenebeck 2581 }
165    
166     VMFunction* ScriptVM::functionByName(const String& name) {
167     if (name == "message") return &fnMessage;
168     else if (name == "exit") return &fnExit;
169     else if (name == "wait") return &fnWait;
170     return NULL;
171     }
172 schoenebeck 2588
173 schoenebeck 2594 std::map<String,VMIntRelPtr*> ScriptVM::builtInIntVariables() {
174     return std::map<String,VMIntRelPtr*>();
175     }
176    
177     std::map<String,VMInt8Array*> ScriptVM::builtInIntArrayVariables() {
178     return std::map<String,VMInt8Array*>();
179     }
180    
181     std::map<String,int> ScriptVM::builtInConstIntVariables() {
182     return std::map<String,int>();
183     }
184    
185 schoenebeck 2588 VMParserContext* ScriptVM::currentVMParserContext() {
186     return m_parserContext;
187     }
188    
189 schoenebeck 2581 VMExecContext* ScriptVM::currentVMExecContext() {
190 schoenebeck 2588 if (!m_parserContext) return NULL;
191     return m_parserContext->execContext;
192 schoenebeck 2581 }
193    
194 schoenebeck 2588 VMExecStatus_t ScriptVM::exec(VMParserContext* parserContext, VMExecContext* execContex, VMEventHandler* handler) {
195     m_parserContext = dynamic_cast<ParserContext*>(parserContext);
196     if (!m_parserContext) {
197     std::cerr << "No VM parser context provided. Did you load a script?.\n";
198 schoenebeck 2581 return VMExecStatus_t(VM_EXEC_NOT_RUNNING | VM_EXEC_ERROR);
199     }
200    
201 schoenebeck 2611 // a ParserContext object is always tied to exactly one ScriptVM object
202     assert(m_parserContext->functionProvider == this);
203    
204 schoenebeck 2581 ExecContext* ctx = dynamic_cast<ExecContext*>(execContex);
205     if (!ctx) {
206     std::cerr << "Invalid VM exec context.\n";
207     return VMExecStatus_t(VM_EXEC_NOT_RUNNING | VM_EXEC_ERROR);
208     }
209     EventHandler* h = dynamic_cast<EventHandler*>(handler);
210     if (!h) return VM_EXEC_NOT_RUNNING;
211    
212 schoenebeck 2588 m_parserContext->execContext = ctx;
213 schoenebeck 2581
214     ctx->status = VM_EXEC_RUNNING;
215     StmtFlags_t flags = STMT_SUCCESS;
216    
217     int& frameIdx = ctx->stackFrame;
218     if (frameIdx < 0) { // start condition ...
219     frameIdx = -1;
220     ctx->pushStack(h);
221     }
222    
223     while (flags == STMT_SUCCESS && frameIdx >= 0) {
224     if (frameIdx >= ctx->stack.size()) { // should never happen, otherwise it's a bug ...
225     std::cerr << "CRITICAL: VM stack overflow! (" << frameIdx << ")\n";
226     flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
227     break;
228     }
229    
230     ExecContext::StackFrame& frame = ctx->stack[frameIdx];
231     switch (frame.statement->statementType()) {
232     case STMT_LEAF: {
233     #if DEBUG_SCRIPTVM_CORE
234     _printIndents(frameIdx);
235     printf("-> STMT_LEAF\n");
236     #endif
237     LeafStatement* leaf = (LeafStatement*) frame.statement;
238     flags = leaf->exec();
239     ctx->popStack();
240     break;
241     }
242    
243     case STMT_LIST: {
244     #if DEBUG_SCRIPTVM_CORE
245     _printIndents(frameIdx);
246     printf("-> STMT_LIST subidx=%d\n", frame.subindex);
247     #endif
248     Statements* stmts = (Statements*) frame.statement;
249     if (stmts->statement(frame.subindex)) {
250     ctx->pushStack(
251     stmts->statement(frame.subindex++)
252     );
253     } else {
254     #if DEBUG_SCRIPTVM_CORE
255     _printIndents(frameIdx);
256     printf("[END OF LIST] subidx=%d\n", frame.subindex);
257     #endif
258     ctx->popStack();
259     }
260     break;
261     }
262    
263     case STMT_BRANCH: {
264     #if DEBUG_SCRIPTVM_CORE
265     _printIndents(frameIdx);
266     printf("-> STMT_BRANCH\n");
267     #endif
268     if (frame.subindex < 0) ctx->popStack();
269     else {
270     BranchStatement* branchStmt = (BranchStatement*) frame.statement;
271     frame.subindex = branchStmt->evalBranch();
272     if (frame.subindex >= 0) {
273     ctx->pushStack(
274     branchStmt->branch(frame.subindex)
275     );
276     frame.subindex = -1;
277     } else ctx->popStack();
278     }
279     break;
280     }
281    
282     case STMT_LOOP: {
283     #if DEBUG_SCRIPTVM_CORE
284     _printIndents(frameIdx);
285     printf("-> STMT_LOOP\n");
286     #endif
287     While* whileStmt = (While*) frame.statement;
288     if (whileStmt->evalLoopStartCondition() && whileStmt->statements()) {
289     ctx->pushStack(
290     whileStmt->statements()
291     );
292     } else ctx->popStack();
293     }
294     }
295     }
296    
297     if (flags & STMT_SUSPEND_SIGNALLED) {
298     ctx->status = VM_EXEC_SUSPENDED;
299     } else {
300     ctx->status = VM_EXEC_NOT_RUNNING;
301     if (flags & STMT_ERROR_OCCURRED)
302     ctx->status = VM_EXEC_ERROR;
303     ctx->reset();
304     }
305    
306 schoenebeck 2588 m_parserContext->execContext = NULL;
307     m_parserContext = NULL;
308 schoenebeck 2581 return ctx->status;
309     }
310    
311     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC