bool gmCodeGenPrivate::GenStmtForEach(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { unsigned int breakAddress, continueAddress, loc1, loc2; // Generate table if(!Generate(a_node->m_children[0], a_byteCode)) { return false; } PushLoop(); // Push the first iterator a_byteCode->Emit(BC_PUSHINT, (gmuint32) -2); // first iterator value. continueAddress = a_byteCode->Tell(); // Generate call const char * keyVar = s_tempVarName1; if(a_node->m_children[2]) keyVar = a_node->m_children[2]->m_data.m_string; const char * valueVar = a_node->m_children[1]->m_data.m_string; gmuint16 keyOffset = (gmuint16) m_currentFunction->SetVariableType(keyVar, CTVT_LOCAL); gmuint16 valueOffset = (gmuint16) m_currentFunction->SetVariableType(valueVar, CTVT_LOCAL); gmuint32 opcode = (keyOffset << 16) | (valueOffset & 0xffff); loc1 = a_byteCode->Tell(); a_byteCode->Emit(BC_FOREACH, opcode); // Skip space for jump loc2 = a_byteCode->Skip(SIZEOF_BC_BRA); // Generate body if(!Generate(a_node->m_children[3], a_byteCode)) { PopLoop(); return false; } a_byteCode->EmitPtr(BC_BRA, (gmuint32) loc1); breakAddress = a_byteCode->Seek(loc2); a_byteCode->EmitPtr(BC_BRZ, breakAddress); a_byteCode->Seek(breakAddress); // pop table and iterator a_byteCode->Emit(BC_POP2); ApplyPatches(m_loopStack[m_currentLoop].m_breaks, a_byteCode, breakAddress); ApplyPatches(m_loopStack[m_currentLoop].m_continues, a_byteCode, continueAddress); PopLoop(); return true; }
bool gmCodeGenPrivate::GenStmtFork(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_STATEMENT && a_node->m_subType == CTNST_FORK ); gmuint32 loc1,loc2; // create the var for the thread id const char * valname = 0; gmuint32 valref = 0; if ( a_node->m_children[1]) { valname = a_node->m_children[1]->m_data.m_string; valref = m_currentFunction->SetVariableType( valname, CTVT_LOCAL ); } loc1 = a_byteCode->Skip( SIZEOF_BC_BRA ); if (!valname) a_byteCode->Emit( BC_POP ); // if not specified then just pop else a_byteCode->Emit( BC_SETLOCAL, valref ); // store the thread id if (!Generate(a_node->m_children[0], a_byteCode )) return false; a_byteCode->Emit( BC_RET ); loc2 = a_byteCode->Seek( loc1 ); a_byteCode->Emit( BC_FORK, loc2 ); a_byteCode->Seek( loc2 ); if (!valname) a_byteCode->Emit( BC_POP ); // if not specified then just pop else a_byteCode->Emit( BC_SETLOCAL, valref ); // store the thread id return true; }
bool gmCodeGenPrivate::GenDeclVariable(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_DECLARATION && a_node->m_subType == CTNDT_VARIABLE); GM_ASSERT(m_currentFunction); m_currentFunction->SetVariableType(a_node->m_children[0]->m_data.m_string, (gmCodeTreeVariableType) a_node->m_subTypeType); return true; }
bool gmCodeGenPrivate::GenExprFunction(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_FUNCTION); gmptr id = m_hooks->GetFunctionId(); a_byteCode->EmitPtr(BC_PUSHFN, id); // Create the function PushFunction(); // Get a debug function name as the name of the variable the function is assigned to if(m_debug && a_node->m_parent && a_node->m_parent->m_type == CTNT_EXPRESSION && a_node->m_parent->m_subType == CTNET_OPERATION && (a_node->m_parent->m_subTypeType == CTNOT_ASSIGN || a_node->m_parent->m_subTypeType == CTNOT_ASSIGN_FIELD) && a_node->m_parent->m_children[1] == a_node) { const gmCodeTreeNode * debugName = a_node->m_parent->m_children[0]; if(debugName && debugName->m_type == CTNT_EXPRESSION && debugName->m_subType == CTNET_IDENTIFIER) { } else if(debugName->m_type == CTNT_EXPRESSION && debugName->m_subType == CTNET_OPERATION && debugName->m_subTypeType == CTNOT_DOT) { debugName = debugName->m_children[1]; } else { debugName = NULL; } if(debugName) { GM_ASSERT(debugName->m_type == CTNT_EXPRESSION && debugName->m_subType == CTNET_IDENTIFIER); m_currentFunction->m_debugName = debugName->m_data.m_string; } } // Parameters const gmCodeTreeNode * params = a_node->m_children[0]; int numParams = 0; while(params) { const gmCodeTreeNode * param = params->m_children[0]; GM_ASSERT(param->m_type == CTNT_EXPRESSION && param->m_subType == CTNET_IDENTIFIER); if(m_currentFunction->SetVariableType(param->m_data.m_string, CTVT_LOCAL) != numParams) { if(m_log) m_log->LogEntry("error (%d) parameter %s already declared", param->m_lineNumber, param->m_data.m_string); PopFunction(); return false; } ++numParams; params = params->m_sibling; } // Generate the code bool res = Generate(a_node->m_children[1], &m_currentFunction->m_byteCode); // Generate a return incase the function didnt have one. m_currentFunction->m_byteCode.Emit(BC_RET); if(res) { // Create a locals table const char ** locals = NULL; if(m_debug) { locals = (const char **) alloca(sizeof(const char *) * m_currentFunction->m_numLocals); memset(locals, 0, sizeof(const char *) * m_currentFunction->m_numLocals); for(gmuint v = 0; v < m_currentFunction->m_variables.Count(); ++v) { Variable &variable = m_currentFunction->m_variables[v]; if(variable.m_offset != -1) { locals[variable.m_offset] = variable.m_symbol; } } } // Add the function to the hooks. gmSortDebugLines(m_currentFunction->m_lineInfo); gmFunctionInfo info; info.m_id = id; info.m_root = false; info.m_byteCode = m_currentFunction->m_byteCode.GetData(); info.m_byteCodeLength = m_currentFunction->m_byteCode.Tell(); info.m_numParams = numParams; info.m_numLocals = m_currentFunction->m_numLocals - numParams; info.m_symbols = locals; info.m_maxStackSize = m_currentFunction->m_byteCode.GetMaxTos(); info.m_lineInfoCount = m_currentFunction->m_lineInfo.Count(); info.m_lineInfo = m_currentFunction->m_lineInfo.GetData(); info.m_debugName = m_currentFunction->m_debugName; m_hooks->AddFunction(info); //gmByteCodePrint(stdout, info.m_byteCode, info.m_byteCodeLength); } PopFunction(); return res; }
bool gmCodeGenPrivate::GenExprOpAssign(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_OPERATION); // value on left hand side must be an l-value... ie, a dot, array or identifier. const gmCodeTreeNode * lValue = a_node->m_children[0]; int type = 0; if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_OPERATION && lValue->m_subTypeType == CTNOT_DOT) { // Generate half l-value if(!Generate(lValue->m_children[0], a_byteCode)) return false; type = 0; } else if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_OPERATION && lValue->m_subTypeType == CTNOT_ARRAY_INDEX) { // Generate half l-value if(!Generate(lValue->m_children[0], a_byteCode)) return false; if(!Generate(lValue->m_children[1], a_byteCode)) return false; type = 1; } else if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_IDENTIFIER) { type = 2; } else { if(m_log) m_log->LogEntry("error (%d) illegal l-value for '=' operator", a_node->m_lineNumber); return false; } // Generate r-value if(!Generate(a_node->m_children[1], a_byteCode)) return false; // complete assignment if(type == 0) { a_byteCode->EmitPtr(BC_SETDOT, m_hooks->GetSymbolId(lValue->m_children[1]->m_data.m_string)); } else if(type == 1) { a_byteCode->Emit(BC_SETIND); } else if(type == 2) { gmCodeTreeVariableType vtype; int offset = m_currentFunction->GetVariableOffset(lValue->m_data.m_string, vtype); // if local, set local regardless // if member set this // if global, set global // set and add local if((lValue->m_flags & gmCodeTreeNode::CTN_MEMBER) > 0) { return a_byteCode->EmitPtr(BC_SETTHIS, m_hooks->GetSymbolId(lValue->m_data.m_string)); } if(offset >= 0 && vtype == CTVT_LOCAL) { return a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset); } else if(offset == -1) { if(vtype == CTVT_MEMBER) { return a_byteCode->EmitPtr(BC_SETTHIS, m_hooks->GetSymbolId(lValue->m_data.m_string)); } else if(vtype == CTVT_GLOBAL) { return a_byteCode->EmitPtr(BC_SETGLOBAL, m_hooks->GetSymbolId(lValue->m_data.m_string)); } if(m_log) m_log->LogEntry("internal error"); return false; } offset = m_currentFunction->SetVariableType(lValue->m_data.m_string, CTVT_LOCAL); return a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset); } else { // paranoia if(m_log) m_log->LogEntry("internal error"); return false; } return true; }
bool gmCodeGenPrivate::GenExprOpPreIncDec(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_OPERATION); // Make sure child 0 is an l-value const gmCodeTreeNode * lValue = a_node->m_children[0]; int type = 0; if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_OPERATION && lValue->m_subTypeType == CTNOT_DOT) { // Generate half l-value if(!Generate(lValue->m_children[0], a_byteCode)) return false; a_byteCode->Emit(BC_DUP); a_byteCode->EmitPtr(BC_GETDOT, m_hooks->GetSymbolId(lValue->m_children[1]->m_data.m_string)); type = 0; } else if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_OPERATION && lValue->m_subTypeType == CTNOT_ARRAY_INDEX) { // Generate half l-value if(!Generate(lValue->m_children[0], a_byteCode)) return false; if(!Generate(lValue->m_children[1], a_byteCode)) return false; a_byteCode->Emit(BC_DUP2); a_byteCode->Emit(BC_GETIND); type = 1; } else if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_IDENTIFIER) { if(!Generate(lValue, a_byteCode)) return false; type = 2; } else { if(m_log) m_log->LogEntry("illegal l-value for '++/--' operator, line %d", a_node->m_lineNumber); return false; } // Perform inc/dec switch(a_node->m_subTypeType) { case CTNOT_PRE_INC : a_byteCode->Emit(BC_OP_INC); break; case CTNOT_PRE_DEC : a_byteCode->Emit(BC_OP_DEC); break; default : { if(m_log) m_log->LogEntry("unkown operator"); return false; } } // Write back the value if(type == 0) { int offset = m_currentFunction->SetVariableType(s_tempVarName0, CTVT_LOCAL); a_byteCode->Emit(BC_DUP); a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset); a_byteCode->EmitPtr(BC_SETDOT, m_hooks->GetSymbolId(lValue->m_children[1]->m_data.m_string)); a_byteCode->Emit(BC_GETLOCAL, (gmuint32) offset); } else if(type == 1) { int offset = m_currentFunction->SetVariableType(s_tempVarName0, CTVT_LOCAL); a_byteCode->Emit(BC_DUP); a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset); a_byteCode->Emit(BC_SETIND); a_byteCode->Emit(BC_GETLOCAL, (gmuint32) offset); } else if(type == 2) { a_byteCode->Emit(BC_DUP); gmCodeTreeVariableType vtype; int offset = m_currentFunction->GetVariableOffset(lValue->m_data.m_string, vtype); // if local, set local regardless // if member set this // if global, set global // set and add local if((lValue->m_flags & gmCodeTreeNode::CTN_MEMBER) > 0) { return a_byteCode->EmitPtr(BC_SETTHIS, m_hooks->GetSymbolId(lValue->m_data.m_string)); } if(offset >= 0 && vtype == CTVT_LOCAL) { return a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset); } else if(offset == -1) { if(vtype == CTVT_MEMBER) { return a_byteCode->EmitPtr(BC_SETTHIS, m_hooks->GetSymbolId(lValue->m_data.m_string)); } else if(vtype == CTVT_GLOBAL) { return a_byteCode->EmitPtr(BC_SETGLOBAL, m_hooks->GetSymbolId(lValue->m_data.m_string)); } if(m_log) m_log->LogEntry("internal error"); return false; } offset = m_currentFunction->SetVariableType(lValue->m_data.m_string, CTVT_LOCAL); return a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset); } else { // paranoia if(m_log) m_log->LogEntry("internal error"); return false; } return true; }