--- linuxsampler/trunk/src/scriptvm/tree.cpp 2014/06/01 14:44:38 2588 +++ linuxsampler/trunk/src/scriptvm/tree.cpp 2019/08/01 10:22:56 3551 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Christian Schoenebeck and Andreas Persson + * Copyright (c) 2014 - 2019 Christian Schoenebeck and Andreas Persson * * http://www.linuxsampler.org * @@ -16,8 +16,7 @@ namespace LinuxSampler { bool isNoOperation(StatementRef statement) { - NoOperation* noOp = dynamic_cast(&*statement); - return noOp; + return statement->statementType() == STMT_NOOP; } Node::Node() { @@ -35,6 +34,17 @@ return ToString(evalInt()); } +String IntArrayExpr::evalCastToStr() { + String s = "{"; + for (int i = 0; i < arraySize(); ++i) { + int val = evalIntElement(i); + if (i) s += ","; + s += ToString(val); + } + s += "}"; + return s; +} + int IntLiteral::evalInt() { return value; } @@ -102,8 +112,12 @@ int Div::evalInt() { IntExpr* pLHS = dynamic_cast(&*lhs); - IntExpr* pRHS = dynamic_cast(&*rhs);; - return (pLHS && pRHS) ? pRHS->evalInt() == 0 ? 0 : pLHS->evalInt() / pRHS->evalInt() : 0; + IntExpr* pRHS = dynamic_cast(&*rhs); + if (!pLHS || !pRHS) return 0; + int l = pLHS->evalInt(); + int r = pRHS->evalInt(); + if (r == 0) return 0; + return l / r; } void Div::dump(int level) { @@ -144,6 +158,13 @@ printf(")\n"); } +bool Args::isPolyphonic() const { + for (int i = 0; i < args.size(); ++i) + if (args[i]->isPolyphonic()) + return true; + return false; +} + EventHandlers::EventHandlers() { //printf("EventHandlers::Constructor 0x%lx\n", (long long)this); } @@ -177,6 +198,13 @@ return const_cast(&*args.at(index)); } +bool EventHandlers::isPolyphonic() const { + for (int i = 0; i < args.size(); ++i) + if (args[i]->isPolyphonic()) + return true; + return false; +} + Assignment::Assignment(VariableRef variable, ExpressionRef value) : variable(variable), value(value) { @@ -194,6 +222,11 @@ return STMT_SUCCESS; } +EventHandler::EventHandler(StatementsRef statements) { + this->statements = statements; + usingPolyphonics = statements->isPolyphonic(); +} + void EventHandler::dump(int level) { printIndents(level); printf("EventHandler {\n"); @@ -217,6 +250,44 @@ return &*args.at(i); } +bool Statements::isPolyphonic() const { + for (int i = 0; i < args.size(); ++i) + if (args[i]->isPolyphonic()) + return true; + return false; +} + +DynamicVariableCall::DynamicVariableCall(const String& name, ParserContext* ctx, VMDynVar* v) + : Variable(ctx, 0, false), dynVar(v), varName(name) +{ +} + +int DynamicVariableCall::evalInt() { + VMIntExpr* expr = dynamic_cast(dynVar); + if (!expr) return 0; + return expr->evalInt(); +} + +String DynamicVariableCall::evalStr() { + VMStringExpr* expr = dynamic_cast(dynVar); + if (!expr) return ""; + return expr->evalStr(); +} + +String DynamicVariableCall::evalCastToStr() { + if (dynVar->exprType() == STRING_EXPR) { + return evalStr(); + } else { + VMIntExpr* intExpr = dynamic_cast(dynVar); + return intExpr ? ToString(intExpr->evalInt()) : ""; + } +} + +void DynamicVariableCall::dump(int level) { + printIndents(level); + printf("Dynamic Variable '%s'\n", varName.c_str()); +} + void FunctionCall::dump(int level) { printIndents(level); printf("FunctionCall '%s' args={\n", functionName.c_str()); @@ -252,6 +323,13 @@ return intExpr->evalInt(); } +VMIntArrayExpr* FunctionCall::asIntArray() const { + VMFnResult* result = const_cast(this)->execVMFn(); + if (!result) return 0; + VMIntArrayExpr* intArrExpr = dynamic_cast(result->resultValue()); + return intArrExpr; +} + String FunctionCall::evalStr() { VMFnResult* result = execVMFn(); if (!result) return ""; @@ -298,11 +376,12 @@ void IntVariable::assign(Expression* expr) { IntExpr* intExpr = dynamic_cast(expr); - if (intExpr) + if (intExpr) { if (polyphonic) context->execContext->polyphonicIntMemory[memPos] = intExpr->evalInt(); else (*context->globalIntMemory)[memPos] = intExpr->evalInt(); + } } int IntVariable::evalInt() { @@ -316,6 +395,7 @@ void IntVariable::dump(int level) { printIndents(level); + printf("IntVariable\n"); //printf("IntVariable memPos=%d\n", memPos); } @@ -345,6 +425,26 @@ printf("ConstIntVariable val=%d\n", value); } +BuiltInIntVariable::BuiltInIntVariable(const String& name, VMIntRelPtr* ptr) + : IntVariable(NULL,false,false), name(name), ptr(ptr) +{ +} + +void BuiltInIntVariable::assign(Expression* expr) { + IntExpr* valueExpr = dynamic_cast(expr); + if (!valueExpr) return; + ptr->assign(valueExpr->evalInt()); +} + +int BuiltInIntVariable::evalInt() { + return ptr->evalInt(); +} + +void BuiltInIntVariable::dump(int level) { + printIndents(level); + printf("Built-in IntVar '%s'\n", name.c_str()); +} + PolyphonicIntVariable::PolyphonicIntVariable(ParserContext* ctx) : IntVariable(ctx,true,false) { @@ -362,8 +462,8 @@ memset(&values[0], 0, size * sizeof(int)); } -IntArrayVariable::IntArrayVariable(ParserContext* ctx, int size, ArgsRef values) - : Variable(ctx, 0, false) +IntArrayVariable::IntArrayVariable(ParserContext* ctx, int size, ArgsRef values, bool _bConst) + : Variable(ctx, 0, _bConst) { this->values.resize(size); for (int i = 0; i < values->argsCount(); ++i) { @@ -372,6 +472,11 @@ } } +IntArrayVariable::IntArrayVariable(ParserContext* ctx, bool bConst) + : Variable(ctx, 0, bConst) +{ +} + int IntArrayVariable::evalIntElement(uint i) { if (i >= values.size()) return 0; return values[i]; @@ -396,7 +501,26 @@ printf(")\n"); } -IntArrayElement::IntArrayElement(IntArrayVariableRef array, IntExprRef arrayIndex) +BuiltInIntArrayVariable::BuiltInIntArrayVariable(const String& name, VMInt8Array* array) + : IntArrayVariable(NULL, false), name(name), array(array) +{ +} + +int BuiltInIntArrayVariable::evalIntElement(uint i) { + return i >= array->size ? 0 : array->data[i]; +} + +void BuiltInIntArrayVariable::assignIntElement(uint i, int value) { + if (i >= array->size) return; + array->data[i] = value; +} + +void BuiltInIntArrayVariable::dump(int level) { + printIndents(level); + printf("Built-In Int Array Variable '%s'\n", name.c_str()); +} + +IntArrayElement::IntArrayElement(IntArrayExprRef array, IntExprRef arrayIndex) : IntVariable(NULL, false, false, 0), array(array), index(arrayIndex) { } @@ -493,6 +617,12 @@ return NULL; } +bool If::isPolyphonic() const { + if (condition->isPolyphonic() || ifStatements->isPolyphonic()) + return true; + return elseStatements ? elseStatements->isPolyphonic() : false; +} + void SelectCase::dump(int level) { printIndents(level); if (select) @@ -543,6 +673,14 @@ return NULL; } +bool SelectCase::isPolyphonic() const { + if (select->isPolyphonic()) return true; + for (int i = 0; i < branches.size(); ++i) + if (branches[i].statements->isPolyphonic()) + return true; + return false; +} + // void Case::addBranch(IntExprRef condition, StatementsRef statements) { // CaseBranchRef b = new CaseBranchRef; // b->from = condition; @@ -585,13 +723,34 @@ return m_condition->evalInt(); } +void SyncBlock::dump(int level) { + printIndents(level); + printf("sync {\n"); + m_statements->dump(level+1); + printIndents(level); + printf("}\n"); +} + +Statements* SyncBlock::statements() const { + return (m_statements) ? const_cast( &*m_statements ) : NULL; +} + void Neg::dump(int level) { printIndents(level); printf("Negative Expr\n"); } String ConcatString::evalStr() { - return lhs->evalCastToStr() + rhs->evalCastToStr(); + // temporaries required here to enforce the associative left (to right) order + // ( required for GCC and Visual Studio, see: + // http://stackoverflow.com/questions/25842902/why-stdstring-concatenation-operator-works-like-right-associative-one + // Personally I am not convinced that this is "not a bug" of the + // compiler/STL implementation and the allegedly underlying "function call" + // nature causing this is IMO no profound reason that the C++ language's + // "+" operator's left associativity is ignored. -- Christian, 2016-07-14 ) + String l = lhs->evalCastToStr(); + String r = rhs->evalCastToStr(); + return l + r; } void ConcatString::dump(int level) { @@ -669,8 +828,9 @@ int Or::evalInt() { IntExpr* pLHS = dynamic_cast(&*lhs); + if (pLHS->evalInt()) return 1; IntExpr* pRHS = dynamic_cast(&*rhs);; - return pLHS->evalInt() || pRHS->evalInt(); + return (pRHS->evalInt()) ? 1 : 0; } void Or::dump(int level) { @@ -684,10 +844,28 @@ printf(")\n"); } +int BitwiseOr::evalInt() { + IntExpr* pLHS = dynamic_cast(&*lhs); + IntExpr* pRHS = dynamic_cast(&*rhs); + return pLHS->evalInt() | pRHS->evalInt(); +} + +void BitwiseOr::dump(int level) { + printIndents(level); + printf("BitwiseOr(\n"); + lhs->dump(level+1); + printIndents(level); + printf(",\n"); + rhs->dump(level+1); + printIndents(level); + printf(")\n"); +} + int And::evalInt() { IntExpr* pLHS = dynamic_cast(&*lhs); - IntExpr* pRHS = dynamic_cast(&*rhs);; - return pLHS->evalInt() && pRHS->evalInt(); + if (!pLHS->evalInt()) return 0; + IntExpr* pRHS = dynamic_cast(&*rhs); + return (pRHS->evalInt()) ? 1 : 0; } void And::dump(int level) { @@ -701,6 +879,23 @@ printf(")\n"); } +int BitwiseAnd::evalInt() { + IntExpr* pLHS = dynamic_cast(&*lhs); + IntExpr* pRHS = dynamic_cast(&*rhs); + return pLHS->evalInt() & pRHS->evalInt(); +} + +void BitwiseAnd::dump(int level) { + printIndents(level); + printf("BitwiseAnd(\n"); + lhs->dump(level+1); + printIndents(level); + printf(",\n"); + rhs->dump(level+1); + printIndents(level); + printf(")\n"); +} + void Not::dump(int level) { printIndents(level); printf("Not(\n"); @@ -709,6 +904,21 @@ printf(")\n"); } +void BitwiseNot::dump(int level) { + printIndents(level); + printf("BitwiseNot(\n"); + expr->dump(level+1); + printIndents(level); + printf(")\n"); +} + +StatementsRef ParserContext::userFunctionByName(const String& name) { + if (!userFnTable.count(name)) { + return StatementsRef(); + } + return userFnTable.find(name)->second; +} + VariableRef ParserContext::variableByName(const String& name) { if (!vartable.count(name)) { return VariableRef(); @@ -742,24 +952,39 @@ } } -void ParserContext::addErr(int line, const char* txt) { +void ParserContext::addErr(int firstLine, int lastLine, int firstColumn, int lastColumn, const char* txt) { ParserIssue e; e.type = PARSER_ERROR; e.txt = txt; - e.line = line; + e.firstLine = firstLine; + e.lastLine = lastLine; + e.firstColumn = firstColumn; + e.lastColumn = lastColumn; vErrors.push_back(e); vIssues.push_back(e); } -void ParserContext::addWrn(int line, const char* txt) { +void ParserContext::addWrn(int firstLine, int lastLine, int firstColumn, int lastColumn, const char* txt) { ParserIssue w; w.type = PARSER_WARNING; w.txt = txt; - w.line = line; + w.firstLine = firstLine; + w.lastLine = lastLine; + w.firstColumn = firstColumn; + w.lastColumn = lastColumn; vWarnings.push_back(w); vIssues.push_back(w); } +void ParserContext::addPreprocessorComment(int firstLine, int lastLine, int firstColumn, int lastColumn) { + CodeBlock block; + block.firstLine = firstLine; + block.lastLine = lastLine; + block.firstColumn = firstColumn; + block.lastColumn = lastColumn; + vPreprocessorComments.push_back(block); +} + bool ParserContext::setPreprocessorCondition(const char* name) { if (builtinPreprocessorConditions.count(name)) return false; if (userPreprocessorConditions.count(name)) return false; @@ -791,6 +1016,10 @@ return vWarnings; } +std::vector ParserContext::preprocessorComments() const { + return vPreprocessorComments; +} + VMEventHandler* ParserContext::eventHandler(uint index) { if (!handlers) return NULL; return handlers->eventHandler(index); @@ -801,4 +1030,59 @@ return handlers->eventHandlerByName(name); } +void ParserContext::registerBuiltInConstIntVariables(const std::map& vars) { + for (std::map::const_iterator it = vars.begin(); + it != vars.end(); ++it) + { + ConstIntVariableRef ref = new ConstIntVariable(it->second); + vartable[it->first] = ref; + } +} + +void ParserContext::registerBuiltInIntVariables(const std::map& vars) { + for (std::map::const_iterator it = vars.begin(); + it != vars.end(); ++it) + { + BuiltInIntVariableRef ref = new BuiltInIntVariable(it->first, it->second); + vartable[it->first] = ref; + } +} + +void ParserContext::registerBuiltInIntArrayVariables(const std::map& vars) { + for (std::map::const_iterator it = vars.begin(); + it != vars.end(); ++it) + { + BuiltInIntArrayVariableRef ref = new BuiltInIntArrayVariable(it->first, it->second); + vartable[it->first] = ref; + } +} + +void ParserContext::registerBuiltInDynVariables(const std::map& vars) { + for (std::map::const_iterator it = vars.begin(); + it != vars.end(); ++it) + { + DynamicVariableCallRef ref = new DynamicVariableCall(it->first, this, it->second); + vartable[it->first] = ref; + } +} + +ExecContext::ExecContext() : + status(VM_EXEC_NOT_RUNNING), flags(STMT_SUCCESS), stackFrame(-1), + suspendMicroseconds(0), instructionsCount(0) +{ + exitRes.value = NULL; +} + +void ExecContext::forkTo(VMExecContext* ectx) const { + ExecContext* child = dynamic_cast(ectx); + + child->polyphonicIntMemory.copyFlatFrom(polyphonicIntMemory); + child->status = VM_EXEC_SUSPENDED; + child->flags = STMT_SUCCESS; + child->stack.copyFlatFrom(stack); + child->stackFrame = stackFrame; + child->suspendMicroseconds = 0; + child->instructionsCount = 0; +} + } // namespace LinuxSampler