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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2619 - (show 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 /*
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 #include <string.h>
13 #include <assert.h>
14 #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 ScriptVM::ScriptVM() : m_parserContext(NULL), fnWait(this) {
93 }
94
95 ScriptVM::~ScriptVM() {
96 }
97
98 VMParserContext* ScriptVM::loadScript(const String& s) {
99 std::istringstream iss(s);
100 return loadScript(&iss);
101 }
102
103 VMParserContext* ScriptVM::loadScript(std::istream* is) {
104 ParserContext* context = new ParserContext(this);
105 //printf("parserCtx=0x%lx\n", (uint64_t)context);
106
107 context->registerBuiltInConstIntVariables( builtInConstIntVariables() );
108 context->registerBuiltInIntVariables( builtInIntVariables() );
109 context->registerBuiltInIntArrayVariables( builtInIntArrayVariables() );
110
111 context->createScanner(is);
112
113 InstrScript_parse(context);
114 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 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
125 context->destroyScanner();
126
127 return context;
128 }
129
130 void ScriptVM::dumpParsedScript(VMParserContext* context) {
131 ParserContext* ctx = dynamic_cast<ParserContext*>(context);
132 if (!ctx) {
133 std::cerr << "No VM context. So nothing to dump.\n";
134 return;
135 }
136 if (!ctx->handlers) {
137 std::cerr << "No event handlers defined in script. So nothing to dump.\n";
138 return;
139 }
140 if (!ctx->globalIntMemory) {
141 std::cerr << "Internal error: no global memory assigend to script VM.\n";
142 return;
143 }
144 ctx->handlers->dump();
145 }
146
147 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 dmsg(2,("Created VM exec context with %d bytes VM stack size.\n",
157 parserCtx->requiredMaxStackSize * sizeof(ExecContext::StackFrame)));
158 //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 dmsg(2,("Allocated %d bytes polyphonic memory.\n", polySize * sizeof(int)));
164 return execCtx;
165 }
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 else if (name == "abs") return &fnAbs;
172 else if (name == "random") return &fnRandom;
173 else if (name == "num_elements") return &fnNumElements;
174 return NULL;
175 }
176
177 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 VMParserContext* ScriptVM::currentVMParserContext() {
190 return m_parserContext;
191 }
192
193 VMExecContext* ScriptVM::currentVMExecContext() {
194 if (!m_parserContext) return NULL;
195 return m_parserContext->execContext;
196 }
197
198 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 return VMExecStatus_t(VM_EXEC_NOT_RUNNING | VM_EXEC_ERROR);
203 }
204
205 // a ParserContext object is always tied to exactly one ScriptVM object
206 assert(m_parserContext->functionProvider == this);
207
208 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 m_parserContext->execContext = ctx;
217
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 m_parserContext->execContext = NULL;
311 m_parserContext = NULL;
312 return ctx->status;
313 }
314
315 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC