/[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 2619 - (hide annotations) (download)
Wed Jun 11 13:24:32 2014 UTC (9 years, 10 months ago) by schoenebeck
File size: 11442 byte(s)
* Implemented built-in instrument script function "abs()".
* Implemented built-in instrument script function "random()".
* Implemented built-in instrument script function "num_elements()".
* Disabled debug mode of RefPtr template class.
* Bumped version (1.0.0.svn51).

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

  ViewVC Help
Powered by ViewVC