/[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 2581 - (show annotations) (download)
Fri May 30 12:48:05 2014 UTC (9 years, 10 months ago) by schoenebeck
File size: 10517 byte(s)
* (WIP) Implemented parser and VM for upcoming new real-time instrument
  script support. It needs yet to be integrated into the sampler's
  sampler engines. You can toy around for now with the command line tool
  "ls_instr_script" and i.e. examples showing the core language features
  under src/scriptvm/examples/.
* Bumped version (1.0.0.svn41).

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

  ViewVC Help
Powered by ViewVC