| // | |
| // Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| #include "compiler/DetectRecursion.h" | |
| DetectRecursion::FunctionNode::FunctionNode(const TString& fname) | |
| : name(fname), | |
| visit(PreVisit) | |
| { | |
| } | |
| const TString& DetectRecursion::FunctionNode::getName() const | |
| { | |
| return name; | |
| } | |
| void DetectRecursion::FunctionNode::addCallee( | |
| DetectRecursion::FunctionNode* callee) | |
| { | |
| for (size_t i = 0; i < callees.size(); ++i) { | |
| if (callees[i] == callee) | |
| return; | |
| } | |
| callees.push_back(callee); | |
| } | |
| bool DetectRecursion::FunctionNode::detectRecursion() | |
| { | |
| ASSERT(visit == PreVisit); | |
| visit = InVisit; | |
| for (size_t i = 0; i < callees.size(); ++i) { | |
| switch (callees[i]->visit) { | |
| case InVisit: | |
| // cycle detected, i.e., recursion detected. | |
| return true; | |
| case PostVisit: | |
| break; | |
| case PreVisit: { | |
| bool recursion = callees[i]->detectRecursion(); | |
| if (recursion) | |
| return true; | |
| break; | |
| } | |
| default: | |
| UNREACHABLE(); | |
| break; | |
| } | |
| } | |
| visit = PostVisit; | |
| return false; | |
| } | |
| DetectRecursion::DetectRecursion() | |
| : currentFunction(NULL) | |
| { | |
| } | |
| DetectRecursion::~DetectRecursion() | |
| { | |
| for (size_t i = 0; i < functions.size(); ++i) | |
| delete functions[i]; | |
| } | |
| bool DetectRecursion::visitAggregate(Visit visit, TIntermAggregate* node) | |
| { | |
| switch (node->getOp()) | |
| { | |
| case EOpPrototype: | |
| // Function declaration. | |
| // Don't add FunctionNode here because node->getName() is the | |
| // unmangled function name. | |
| break; | |
| case EOpFunction: { | |
| // Function definition. | |
| if (visit == PreVisit) { | |
| currentFunction = findFunctionByName(node->getName()); | |
| if (currentFunction == NULL) { | |
| currentFunction = new FunctionNode(node->getName()); | |
| functions.push_back(currentFunction); | |
| } | |
| } | |
| break; | |
| } | |
| case EOpFunctionCall: { | |
| // Function call. | |
| if (visit == PreVisit) { | |
| ASSERT(currentFunction != NULL); | |
| FunctionNode* func = findFunctionByName(node->getName()); | |
| if (func == NULL) { | |
| func = new FunctionNode(node->getName()); | |
| functions.push_back(func); | |
| } | |
| currentFunction->addCallee(func); | |
| } | |
| break; | |
| } | |
| default: | |
| break; | |
| } | |
| return true; | |
| } | |
| DetectRecursion::ErrorCode DetectRecursion::detectRecursion() | |
| { | |
| FunctionNode* main = findFunctionByName("main("); | |
| if (main == NULL) | |
| return kErrorMissingMain; | |
| if (main->detectRecursion()) | |
| return kErrorRecursion; | |
| return kErrorNone; | |
| } | |
| DetectRecursion::FunctionNode* DetectRecursion::findFunctionByName( | |
| const TString& name) | |
| { | |
| for (size_t i = 0; i < functions.size(); ++i) { | |
| if (functions[i]->getName() == name) | |
| return functions[i]; | |
| } | |
| return NULL; | |
| } | |