bool gmCodeGenPrivate::GenExprConstant(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_CONSTANT); switch(a_node->m_subTypeType) { case CTNCT_INT : // INT { if(a_node->m_data.m_iValue == 0) { a_byteCode->Emit(BC_PUSHINT0); } else if(a_node->m_data.m_iValue == 1) { a_byteCode->Emit(BC_PUSHINT1); } else { #if 1 // 32bit Integers a_byteCode->Emit(BC_PUSHINT, *((gmint *) &a_node->m_data.m_iValue)); #else a_byteCode->EmitPtr(BC_PUSHINT, *((gmptr *) &a_node->m_data.m_iValue)); #endif } break; } case CTNCT_FLOAT : // FLOAT { a_byteCode->Emit(BC_PUSHFP, *((gmuint32 *) ((void *) &a_node->m_data.m_fValue))); break; } case CTNCT_STRING : // STRING { a_byteCode->EmitPtr(BC_PUSHSTR, m_hooks->GetStringId(a_node->m_data.m_string)); break; } case CTNCT_NULL : // NULL { a_byteCode->Emit(BC_PUSHNULL); break; } default: { if(m_log) m_log->LogEntry("unkown constant type"); return false; } } return true; }
bool gmCodeGenPrivate::GenExprOpDot(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_OPERATION && a_node->m_subTypeType == CTNOT_DOT); if(!Generate(a_node->m_children[0], a_byteCode)) return false; // make sure child 1 is an identifier const gmCodeTreeNode * id = a_node->m_children[1]; if(id && id->m_type == CTNT_EXPRESSION && id->m_subType == CTNET_IDENTIFIER) { return a_byteCode->EmitPtr(BC_GETDOT, m_hooks->GetSymbolId(a_node->m_children[1]->m_data.m_string)); } if(m_log) m_log->LogEntry("error (%d) illegal dot operator", a_node->m_lineNumber); return false; }
bool gmCodeGenPrivate::GenStmtContinue(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_STATEMENT && a_node->m_subType == CTNST_CONTINUE); if(m_currentLoop >= 0) { a_byteCode->Emit(BC_BRA); Patch * patch = &m_patches.InsertLast(); patch->m_address = a_byteCode->Skip(sizeof(gmptr)); // NOTE: Using gmptr size addresses patch->m_next = m_loopStack[m_currentLoop].m_continues; m_loopStack[m_currentLoop].m_continues = m_patches.Count()-1; return true; } if(m_log) m_log->LogEntry("error (%d) illegal continue statement", a_node->m_lineNumber); return false; }
bool gmCodeGenPrivate::GenExprOpShift(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_OPERATION); if(!Generate(a_node->m_children[0], a_byteCode)) return false; if(!Generate(a_node->m_children[1], a_byteCode)) return false; switch(a_node->m_subTypeType) { case CTNOT_SHIFT_LEFT : return a_byteCode->Emit(BC_BIT_SHL); case CTNOT_SHIFT_RIGHT : return a_byteCode->Emit(BC_BIT_SHR); default : { if(m_log) m_log->LogEntry("error (%d) unkown shift operator", a_node->m_lineNumber); } } return false; }
bool gmCodeGenPrivate::GenExprOpUnary(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_OPERATION); if(!Generate(a_node->m_children[0], a_byteCode)) return false; switch(a_node->m_subTypeType) { case CTNOT_UNARY_PLUS : return a_byteCode->Emit(BC_OP_POS); case CTNOT_UNARY_MINUS : return a_byteCode->Emit(BC_OP_NEG); case CTNOT_UNARY_NOT : return a_byteCode->Emit(BC_OP_NOT); case CTNOT_UNARY_COMPLEMENT : return a_byteCode->Emit(BC_BIT_INV); default : { if(m_log) m_log->LogEntry("error (%d) unkown operator", a_node->m_lineNumber); } } return false; }
bool gmCodeGenPrivate::GenExprOpAr(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_OPERATION); if(!Generate(a_node->m_children[0], a_byteCode)) return false; if(!Generate(a_node->m_children[1], a_byteCode)) return false; switch(a_node->m_subTypeType) { case CTNOT_TIMES : return a_byteCode->Emit(BC_OP_MUL); case CTNOT_DIVIDE : return a_byteCode->Emit(BC_OP_DIV); case CTNOT_REM : return a_byteCode->Emit(BC_OP_REM); case CTNOT_ADD : return a_byteCode->Emit(BC_OP_ADD); case CTNOT_MINUS : return a_byteCode->Emit(BC_OP_SUB); default : { if(m_log) m_log->LogEntry("error (%d) unkown arithmatic operator", a_node->m_lineNumber); } } return false; }
bool gmCodeGenPrivate::GenExprOpComparison(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_OPERATION); if(!Generate(a_node->m_children[0], a_byteCode)) return false; if(!Generate(a_node->m_children[1], a_byteCode)) return false; switch(a_node->m_subTypeType) { case CTNOT_LT : return a_byteCode->Emit(BC_OP_LT); case CTNOT_GT : return a_byteCode->Emit(BC_OP_GT); case CTNOT_LTE : return a_byteCode->Emit(BC_OP_LTE); case CTNOT_GTE : return a_byteCode->Emit(BC_OP_GTE); case CTNOT_EQ : return a_byteCode->Emit(BC_OP_EQ); case CTNOT_NEQ : return a_byteCode->Emit(BC_OP_NEQ); default : { if(m_log) m_log->LogEntry("error (%d) unkown comparison operator", a_node->m_lineNumber); } } return false; }
bool gmCodeGenPrivate::GenExprIdentifier(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode) { GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_IDENTIFIER); // if local, get local regardless // if member, get this // if global, get global // get global if((a_node->m_flags & gmCodeTreeNode::CTN_MEMBER) > 0) { return a_byteCode->EmitPtr(BC_GETTHIS, m_hooks->GetSymbolId(a_node->m_data.m_string)); } gmCodeTreeVariableType type; int offset = m_currentFunction->GetVariableOffset(a_node->m_data.m_string, type); if(offset >= 0 && type == CTVT_LOCAL) { return a_byteCode->Emit(BC_GETLOCAL, (gmuint32) offset); } else if(offset != -2) { if(type == CTVT_MEMBER) { return a_byteCode->EmitPtr(BC_GETTHIS, m_hooks->GetSymbolId(a_node->m_data.m_string)); } else if(type == CTVT_GLOBAL) { return a_byteCode->EmitPtr(BC_GETGLOBAL, m_hooks->GetSymbolId(a_node->m_data.m_string)); } if(m_log) m_log->LogEntry("internal error"); return false; } return a_byteCode->EmitPtr(BC_GETGLOBAL, m_hooks->GetSymbolId(a_node->m_data.m_string)); }
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::Generate(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode, bool a_siblings) { bool res = true; while(a_node) { // record line number static int s_line = 0; if(m_currentFunction) m_currentFunction->m_currentLine = a_node->m_lineNumber; // if we are in debug, emit a BC_LINE instruction if(m_debug && (s_line != a_node->m_lineNumber) && !(a_node->m_type == CTNT_STATEMENT && a_node->m_subType == CTNST_COMPOUND)) { a_byteCode->Emit(BC_LINE); s_line = a_node->m_lineNumber; } switch(a_node->m_type) { case CTNT_DECLARATION : { switch(a_node->m_subType) { case CTNDT_VARIABLE : res = GenDeclVariable(a_node, a_byteCode); break; default: { GM_ASSERT(false); return false; } } break; } case CTNT_STATEMENT : { switch(a_node->m_subType) { case CTNST_RETURN : res = GenStmtReturn(a_node, a_byteCode); break; case CTNST_BREAK : res = GenStmtBreak(a_node, a_byteCode); break; case CTNST_CONTINUE : res = GenStmtContinue(a_node, a_byteCode); break; case CTNST_FOR : res = GenStmtFor(a_node, a_byteCode); break; case CTNST_FOREACH : res = GenStmtForEach(a_node, a_byteCode); break; case CTNST_WHILE : res = GenStmtWhile(a_node, a_byteCode); break; case CTNST_DOWHILE : res = GenStmtDoWhile(a_node, a_byteCode); break; case CTNST_IF : res = GenStmtIf(a_node, a_byteCode); break; case CTNST_COMPOUND : res = GenStmtCompound(a_node, a_byteCode); break; #if GM_USE_FORK case CTNST_FORK : res = GenStmtFork(a_node, a_byteCode); break; #else //GM_USE_FORK case CTNST_FORK: // Unsupported, but tokens exist { if(m_log && m_currentFunction) { m_log->LogEntry("error (%d) 'fork' instruction not supported", m_currentFunction->m_currentLine); } return false; } #endif //GM_USE_FORK default: { GM_ASSERT(false); return false; } } break; } case CTNT_EXPRESSION : { switch(a_node->m_subType) { case CTNET_OPERATION : { switch(a_node->m_subTypeType) { case CTNOT_DOT : res = GenExprOpDot(a_node, a_byteCode); break; case CTNOT_UNARY_PLUS : case CTNOT_UNARY_MINUS : case CTNOT_UNARY_COMPLEMENT : case CTNOT_UNARY_NOT : res = GenExprOpUnary(a_node, a_byteCode); break; case CTNOT_ARRAY_INDEX : res = GenExprOpArrayIndex(a_node, a_byteCode); break; case CTNOT_TIMES : case CTNOT_DIVIDE : case CTNOT_REM : case CTNOT_MINUS : case CTNOT_ADD : res = GenExprOpAr(a_node, a_byteCode); break; case CTNOT_SHIFT_LEFT : case CTNOT_SHIFT_RIGHT : res = GenExprOpShift(a_node, a_byteCode); break; case CTNOT_LT : case CTNOT_GT : case CTNOT_LTE : case CTNOT_GTE : case CTNOT_EQ : case CTNOT_NEQ : res = GenExprOpComparison(a_node, a_byteCode); break; case CTNOT_BIT_AND : case CTNOT_BIT_XOR : case CTNOT_BIT_OR : res = GenExprOpBitwise(a_node, a_byteCode); break; case CTNOT_AND : res = GenExprOpAnd(a_node, a_byteCode); break; case CTNOT_OR : res = GenExprOpOr(a_node, a_byteCode); break; case CTNOT_ASSIGN : res = GenExprOpAssign(a_node, a_byteCode); break; default: { GM_ASSERT(false); return false; } } break; } case CTNET_CONSTANT : res = GenExprConstant(a_node, a_byteCode); break; case CTNET_IDENTIFIER : res = GenExprIdentifier(a_node, a_byteCode); break; case CTNET_CALL : res = GenExprCall(a_node, a_byteCode); break; case CTNET_THIS : res = GenExprThis(a_node, a_byteCode); break; case CTNET_FUNCTION : res = GenExprFunction(a_node, a_byteCode); break; case CTNET_TABLE : res = GenExprTable(a_node, a_byteCode); break; default : { GM_ASSERT(false); return false; } } break; } default: { GM_ASSERT(false); return false; } } if(!res) { return false; } if((a_node->m_flags & gmCodeTreeNode::CTN_POP) > 0) { a_byteCode->Emit(BC_POP); } if(a_siblings) { a_node = a_node->m_sibling; } else a_node = NULL; } return true; }
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; }