/[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 2581 - (hide 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 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     #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