/[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 2588 - (hide 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 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    
106     context->createScanner(is);
107 schoenebeck 2581
108 schoenebeck 2588 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 schoenebeck 2581
120 schoenebeck 2588 context->destroyScanner();
121 schoenebeck 2581
122 schoenebeck 2588 return context;
123 schoenebeck 2581 }
124    
125 schoenebeck 2588 void ScriptVM::dumpParsedScript(VMParserContext* context) {
126     ParserContext* ctx = dynamic_cast<ParserContext*>(context);
127     if (!ctx) {
128 schoenebeck 2581 std::cerr << "No VM context. So nothing to dump.\n";
129     return;
130     }
131 schoenebeck 2588 if (!ctx->handlers) {
132 schoenebeck 2581 std::cerr << "No event handlers defined in script. So nothing to dump.\n";
133     return;
134     }
135 schoenebeck 2588 if (!ctx->globalIntMemory) {
136 schoenebeck 2581 std::cerr << "Internal error: no global memory assigend to script VM.\n";
137     return;
138     }
139 schoenebeck 2588 ctx->handlers->dump();
140 schoenebeck 2581 }
141    
142 schoenebeck 2588 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 schoenebeck 2581 std::cout << "Created VM exec context with "
152 schoenebeck 2588 << parserCtx->requiredMaxStackSize * sizeof(ExecContext::StackFrame)
153 schoenebeck 2581 << " bytes VM stack size.\n";
154 schoenebeck 2588 //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 schoenebeck 2581 std::cout << "Allocated " << polySize * sizeof(int)
160     << " bytes polyphonic memory.\n";
161 schoenebeck 2588 return execCtx;
162 schoenebeck 2581 }
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 schoenebeck 2588
171     VMParserContext* ScriptVM::currentVMParserContext() {
172     return m_parserContext;
173     }
174    
175 schoenebeck 2581 VMExecContext* ScriptVM::currentVMExecContext() {
176 schoenebeck 2588 if (!m_parserContext) return NULL;
177     return m_parserContext->execContext;
178 schoenebeck 2581 }
179    
180 schoenebeck 2588 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 schoenebeck 2581 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 schoenebeck 2588 m_parserContext->execContext = ctx;
196 schoenebeck 2581
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 schoenebeck 2588 m_parserContext->execContext = NULL;
290     m_parserContext = NULL;
291 schoenebeck 2581 return ctx->status;
292     }
293    
294     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC