/[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 2588 - (show annotations) (download)
Sun Jun 1 14:44:38 2014 UTC (9 years, 10 months ago) by schoenebeck
File size: 10605 byte(s)
* ScriptVM: refactoring and fixes.

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 "../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 ScriptVM::ScriptVM() : m_parserContext(NULL), fnWait(this) {
92 }
93
94 ScriptVM::~ScriptVM() {
95 }
96
97 VMParserContext* ScriptVM::loadScript(const String& s) {
98 std::istringstream iss(s);
99 return loadScript(&iss);
100 }
101
102 VMParserContext* ScriptVM::loadScript(std::istream* is) {
103 ParserContext* context = new ParserContext(this);
104 //printf("parserCtx=0x%lx\n", (uint64_t)context);
105
106 context->createScanner(is);
107
108 InstrScript_parse(context);
109 std::cout << "Allocating " << context->globalIntVarCount * sizeof(int) << " bytes of global int VM memory.\n";
110 std::cout << "Allocating " << context->globalStrVarCount << " of global VM string variables.\n";
111 if (!context->globalIntMemory)
112 context->globalIntMemory = new ArrayList<int>();
113 if (!context->globalStrMemory)
114 context->globalStrMemory = new ArrayList<String>();
115 context->globalIntMemory->resize(context->globalIntVarCount);
116 memset(&((*context->globalIntMemory)[0]), 0, context->globalIntVarCount * sizeof(int));
117
118 context->globalStrMemory->resize(context->globalStrVarCount);
119
120 context->destroyScanner();
121
122 return context;
123 }
124
125 void ScriptVM::dumpParsedScript(VMParserContext* context) {
126 ParserContext* ctx = dynamic_cast<ParserContext*>(context);
127 if (!ctx) {
128 std::cerr << "No VM context. So nothing to dump.\n";
129 return;
130 }
131 if (!ctx->handlers) {
132 std::cerr << "No event handlers defined in script. So nothing to dump.\n";
133 return;
134 }
135 if (!ctx->globalIntMemory) {
136 std::cerr << "Internal error: no global memory assigend to script VM.\n";
137 return;
138 }
139 ctx->handlers->dump();
140 }
141
142 VMExecContext* ScriptVM::createExecContext(VMParserContext* parserContext) {
143 ParserContext* parserCtx = dynamic_cast<ParserContext*>(parserContext);
144 ExecContext* execCtx = new ExecContext();
145
146 if (parserCtx->requiredMaxStackSize < 0) {
147 parserCtx->requiredMaxStackSize =
148 _requiredMaxStackSizeFor(&*parserCtx->handlers);
149 }
150 execCtx->stack.resize(parserCtx->requiredMaxStackSize);
151 std::cout << "Created VM exec context with "
152 << parserCtx->requiredMaxStackSize * sizeof(ExecContext::StackFrame)
153 << " bytes VM stack size.\n";
154 //printf("execCtx=0x%lx\n", (uint64_t)execCtx);
155 const int polySize = parserCtx->polyphonicIntVarCount;
156 execCtx->polyphonicIntMemory.resize(polySize);
157 memset(&execCtx->polyphonicIntMemory[0], 0, polySize * sizeof(int));
158
159 std::cout << "Allocated " << polySize * sizeof(int)
160 << " bytes polyphonic memory.\n";
161 return execCtx;
162 }
163
164 VMFunction* ScriptVM::functionByName(const String& name) {
165 if (name == "message") return &fnMessage;
166 else if (name == "exit") return &fnExit;
167 else if (name == "wait") return &fnWait;
168 return NULL;
169 }
170
171 VMParserContext* ScriptVM::currentVMParserContext() {
172 return m_parserContext;
173 }
174
175 VMExecContext* ScriptVM::currentVMExecContext() {
176 if (!m_parserContext) return NULL;
177 return m_parserContext->execContext;
178 }
179
180 VMExecStatus_t ScriptVM::exec(VMParserContext* parserContext, VMExecContext* execContex, VMEventHandler* handler) {
181 m_parserContext = dynamic_cast<ParserContext*>(parserContext);
182 if (!m_parserContext) {
183 std::cerr << "No VM parser context provided. Did you load a script?.\n";
184 return VMExecStatus_t(VM_EXEC_NOT_RUNNING | VM_EXEC_ERROR);
185 }
186
187 ExecContext* ctx = dynamic_cast<ExecContext*>(execContex);
188 if (!ctx) {
189 std::cerr << "Invalid VM exec context.\n";
190 return VMExecStatus_t(VM_EXEC_NOT_RUNNING | VM_EXEC_ERROR);
191 }
192 EventHandler* h = dynamic_cast<EventHandler*>(handler);
193 if (!h) return VM_EXEC_NOT_RUNNING;
194
195 m_parserContext->execContext = ctx;
196
197 ctx->status = VM_EXEC_RUNNING;
198 StmtFlags_t flags = STMT_SUCCESS;
199
200 int& frameIdx = ctx->stackFrame;
201 if (frameIdx < 0) { // start condition ...
202 frameIdx = -1;
203 ctx->pushStack(h);
204 }
205
206 while (flags == STMT_SUCCESS && frameIdx >= 0) {
207 if (frameIdx >= ctx->stack.size()) { // should never happen, otherwise it's a bug ...
208 std::cerr << "CRITICAL: VM stack overflow! (" << frameIdx << ")\n";
209 flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
210 break;
211 }
212
213 ExecContext::StackFrame& frame = ctx->stack[frameIdx];
214 switch (frame.statement->statementType()) {
215 case STMT_LEAF: {
216 #if DEBUG_SCRIPTVM_CORE
217 _printIndents(frameIdx);
218 printf("-> STMT_LEAF\n");
219 #endif
220 LeafStatement* leaf = (LeafStatement*) frame.statement;
221 flags = leaf->exec();
222 ctx->popStack();
223 break;
224 }
225
226 case STMT_LIST: {
227 #if DEBUG_SCRIPTVM_CORE
228 _printIndents(frameIdx);
229 printf("-> STMT_LIST subidx=%d\n", frame.subindex);
230 #endif
231 Statements* stmts = (Statements*) frame.statement;
232 if (stmts->statement(frame.subindex)) {
233 ctx->pushStack(
234 stmts->statement(frame.subindex++)
235 );
236 } else {
237 #if DEBUG_SCRIPTVM_CORE
238 _printIndents(frameIdx);
239 printf("[END OF LIST] subidx=%d\n", frame.subindex);
240 #endif
241 ctx->popStack();
242 }
243 break;
244 }
245
246 case STMT_BRANCH: {
247 #if DEBUG_SCRIPTVM_CORE
248 _printIndents(frameIdx);
249 printf("-> STMT_BRANCH\n");
250 #endif
251 if (frame.subindex < 0) ctx->popStack();
252 else {
253 BranchStatement* branchStmt = (BranchStatement*) frame.statement;
254 frame.subindex = branchStmt->evalBranch();
255 if (frame.subindex >= 0) {
256 ctx->pushStack(
257 branchStmt->branch(frame.subindex)
258 );
259 frame.subindex = -1;
260 } else ctx->popStack();
261 }
262 break;
263 }
264
265 case STMT_LOOP: {
266 #if DEBUG_SCRIPTVM_CORE
267 _printIndents(frameIdx);
268 printf("-> STMT_LOOP\n");
269 #endif
270 While* whileStmt = (While*) frame.statement;
271 if (whileStmt->evalLoopStartCondition() && whileStmt->statements()) {
272 ctx->pushStack(
273 whileStmt->statements()
274 );
275 } else ctx->popStack();
276 }
277 }
278 }
279
280 if (flags & STMT_SUSPEND_SIGNALLED) {
281 ctx->status = VM_EXEC_SUSPENDED;
282 } else {
283 ctx->status = VM_EXEC_NOT_RUNNING;
284 if (flags & STMT_ERROR_OCCURRED)
285 ctx->status = VM_EXEC_ERROR;
286 ctx->reset();
287 }
288
289 m_parserContext->execContext = NULL;
290 m_parserContext = NULL;
291 return ctx->status;
292 }
293
294 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC