/* * analyze and generate best switch statement. */ void genxswitch(Statement *stmt) { int oldbreak; oldbreak = breaklab; breaklab = nextlabel++; GenerateSwitch(stmt); GenerateCase(stmt->s1); GenerateLabel(breaklab); breaklab = oldbreak; }
/* * Generate code for a specific non-virtual operation. */ static void GenerateNonVirtual(TreeCCContext *context, const TreeCCNonVirtual *nonVirt, TreeCCOperation *oper) { TreeCCStream *stream; TreeCCOperationCase *operCase; int number; /* Determine which stream to write to */ if(context->language == TREECC_LANG_JAVA) { if(oper->className) { stream = TreeCCStreamGetJava(context, oper->className); } else { stream = TreeCCStreamGetJava(context, oper->name); } } else { stream = oper->source; } /* Output start declarations for the operation */ (*(nonVirt->genStart))(context, stream, oper); /* If the operation is not inline, then output functions for all cases */ if((oper->flags & TREECC_OPER_INLINE) == 0) { number = 1; operCase = oper->firstCase; while(operCase != 0) { (*(nonVirt->genCaseFunc))(context, stream, operCase, number); operCase->number = number++; operCase = operCase->next; } } /* Process split non-virtuals */ if(oper->numTriggers > 1 && (oper->flags & TREECC_OPER_SPLIT) != 0) { /* Split the switch statement over multiple levels of functions, so that no single function grows too large */ AssignTriggerPosns(context, oper); GenerateSplitMultiSwitch(context, stream, nonVirt, oper, oper->sortedCases, 0, 1, oper->params, 0); (*(nonVirt->genEnd))(context, stream, oper); return; } /* Output the entry point for the operation */ (*(nonVirt->genEntry))(context, stream, oper); /* Generate the switch statement for the outer-most level */ if(oper->numTriggers <= 1) { GenerateSwitch(context, stream, nonVirt, oper, oper->firstCase, 0); } else { AssignTriggerPosns(context, oper); GenerateMultiSwitch(context, stream, nonVirt, oper, oper->sortedCases, 0, 1, oper->params, 0); } /* Output the exit point for the operation */ (*(nonVirt->genExit))(context, stream, oper); /* Output the end declarations for the operation */ (*(nonVirt->genEnd))(context, stream, oper); }
/* * Generate code for a "switch" on a trigger. */ static TreeCCOperationCase *GenerateSwitch (TreeCCContext *context, TreeCCStream *stream, const TreeCCNonVirtual *nonVirt, TreeCCOperation *oper, TreeCCOperationCase *operCase, int triggerNum) { TreeCCParam *param; int num, markBit; int paramNum; TreeCCOperationCase *firstCase; TreeCCTrigger *trigger; TreeCCNode *node; int isEnum; /* Generate the head of the switch for this level */ param = oper->params; num = 0; paramNum = 1; while(param != 0) { if((param->flags & TREECC_PARAM_TRIGGER) != 0) { if(num == triggerNum) { break; } ++num; } if(!(param->name)) { ++paramNum; } param = param->next; } if(!param) { /* Output the code for the case */ if((oper->flags & TREECC_OPER_INLINE) != 0) { (*(nonVirt->genCaseInline))(context, stream, operCase, triggerNum - 1); } else { (*(nonVirt->genCaseCall))(context, stream, operCase, operCase->number, triggerNum - 1); } return operCase->next; } node = TreeCCNodeFindByType(context, param->type); isEnum = ((node->flags & TREECC_NODE_ENUM) != 0); if(param->name) { (*(nonVirt->genSwitchHead))(context, stream, param->name, triggerNum, isEnum); } else { char paramName[64]; sprintf(paramName, "P%d__", paramNum); (*(nonVirt->genSwitchHead))(context, stream, paramName, triggerNum, isEnum); } /* Recurse to handle the next-inner level of switch statements */ markBit = TREECC_NODE_MARK(triggerNum); TreeCCNodeClearMarking(context, markBit); firstCase = operCase; do { /* Output the "case" statements to match this operation case */ trigger = operCase->triggers; num = 0; while(trigger != 0 && num < triggerNum) { ++num; trigger = trigger->next; } if(trigger) { if(!GenerateSelectors(context, stream, nonVirt, trigger->node, markBit, triggerNum)) { /* We already output code for this with another case */ TreeCCErrorOnLine(context->input, operCase->filename, operCase->linenum, "this operation case duplicates another"); } } (*(nonVirt->genEndSelectors))(context, stream, triggerNum); /* Generate the next level of "switch"'s */ operCase = GenerateSwitch(context, stream, nonVirt, oper, operCase, triggerNum + 1); /* Terminate the "case" statement */ (*(nonVirt->genEndCase))(context, stream, triggerNum); } while(operCase != 0 && LevelsMatch(firstCase, operCase, triggerNum)); /* Generate the end of the switch for this level */ (*(nonVirt->genEndSwitch))(context, stream, triggerNum); /* Return the next case to be handled to the caller */ return operCase; }