diff options
Diffstat (limited to 'util/statetrace/printer.cc')
-rw-r--r-- | util/statetrace/printer.cc | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/util/statetrace/printer.cc b/util/statetrace/printer.cc new file mode 100644 index 000000000..b14671f2c --- /dev/null +++ b/util/statetrace/printer.cc @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "tracechild.hh" +#include "printer.hh" + +using namespace std; + +//Types of printers. If none is found, or there is an error in the input, +//there are psuedo types to return. +enum PrinterType {PRINTER_NONE, PRINTER_ERROR, PRINTER_NESTING, PRINTER_REG}; + +int findEndOfRegPrinter(string, int); +int findEndOfNestingPrinter(string, int); +PrinterType findSub(string, int &, int &); + +//This is pretty easy. Just find the closing parenthesis. +int findEndOfRegPrinter(string config, int startPos) +{ + int pos = config.find(")", startPos); + if(pos == string::npos) + { + cerr << "Couldn't find the closing parenthesis for a reg printer" << endl; + return 0; + } + return pos; +} + +//This is a little harder. We need to make sure we don't +//grab an ending parenthesis that belongs to the nesting printer. +int findEndOfNestingPrinter(string config, int startPos) +{ + int length = config.length(); + int pos = startPos; + int endPos = length; + int parenPos = config.find(")", pos); + //If we didn't find an ending parenthesis at all, we're in trouble + if(parenPos == string::npos) + { + cerr << "Couldn't find the closing parenthesis for a nesting printer on the first try" << endl; + return 0; + } + //Keep pulling out embedded stuff until we can't any more + //we need to make sure we aren't skipping over the parenthesis + //that ends -this- printer. + PrinterType type = findSub(config, pos, endPos); + if(type == PRINTER_ERROR) + return 0; + while(type != PRINTER_NONE && endPos >= parenPos) + { + //Find the next closest ending parenthesis since we passed + //up the last one + parenPos = config.find(")", endPos + 1); + //If we didn't find one, we're in trouble + if(parenPos == string::npos) + { + cerr << "Couldn't find the closing parenthesis for a nested printer on later tries" << endl; + return 0; + } + //Start looking for the end of this printer and embedded + //stuff past the one we just found + pos = endPos + 1; + //Reset endPos so we search to the end of config + endPos = length; + type = findSub(config, pos, endPos); + if(type == PRINTER_ERROR) + return 0; + } + //We ran out of embedded items, and we didn't pass up our last + //closing paren. This must be the end of this printer. + return parenPos; +} + +//Find a sub printer. This looks for things which have a type defining +//character and then an opening parenthesis. The type is returned, and +//startPos and endPos are set to the beginning and end of the sub printer +//On entry, the search starts at index startPos and ends at either index +//endPos or a closing parenthesis, whichever comes first +PrinterType findSub(string config, int & startPos, int & endPos) +{ + int length = config.length(); + //Figure out where the different types of sub printers may start + int regPos = config.find("%(", startPos); + int nestingPos = config.find("~(", startPos); + //If a type of printer wasn't found, say it was found too far away. + //This simplifies things later + if(regPos == string::npos) + regPos = endPos; + if(nestingPos == string::npos) + nestingPos = endPos; + //If we find a closing paren, that marks the + //end of the region we're searching. + int closingPos = config.find(")", startPos); + if(closingPos != string::npos && + closingPos < regPos && + closingPos < nestingPos) + return PRINTER_NONE; + //If we didn't find anything close enough, say so. + if(regPos >= endPos && nestingPos >= endPos) + return PRINTER_NONE; + //At this point, we know that one of the options starts legally + //We need to find which one is first and return that + if(regPos < nestingPos) + { + int regEnd = findEndOfRegPrinter(config, regPos + 2); + //If we couldn't find the end... + if(!regEnd) + { + cerr << "Couldn't find the end of the reg printer" << endl; + return PRINTER_ERROR; + } + //Report the sub printer's vitals. + startPos = regPos; + endPos = regEnd; + return PRINTER_REG; + } + else + { + int nestingEnd = findEndOfNestingPrinter(config, nestingPos + 2); + //If we couldn't find the end... + if(!nestingEnd) + { + cerr << "Couldn't find the end of the nesting printer" << endl; + return PRINTER_ERROR; + } + //Report the sub printer's vitals. + startPos = nestingPos; + endPos = nestingEnd; + return PRINTER_NESTING; + } + return PRINTER_NONE; +} + +//Set up a nesting printer. This printer can contain sub printers +bool NestingPrinter::configure(string config) +{ + //Clear out any old stuff + constStrings.clear(); + numPrinters = 0; + printers.clear(); + int length = config.length(); + int startPos = 0, endPos = length; + int lastEndPos = -1; + //Try to find a sub printer + PrinterType type = findSub(config, startPos, endPos); + if(type == PRINTER_ERROR) + { + cerr << "Problem finding first sub printer" << endl; + return false; + } + while(type != PRINTER_NONE) + { + string prefix = config.substr(lastEndPos + 1, startPos - lastEndPos - 1); + lastEndPos = endPos; + constStrings.push_back(prefix); + string subConfig, subString; + int commaPos, lastCommaPos, childSwitchVar; + switch(type) + { + //If we found a plain register printer + case PRINTER_REG: + numPrinters++; + //Get the register name + subConfig = config.substr(startPos + 2, endPos - startPos - 2); + //Set up the register printer + RegPrinter * regPrinter = new RegPrinter(child); + if(!regPrinter->configure(subConfig)) + { + delete regPrinter; + cerr << "Error configuring reg printer" << endl; + return false; + } + printers.push_back(regPrinter); + break; + //If we found an embedded nesting printer + case PRINTER_NESTING: + numPrinters++; + //Punt on reading in all the parameters of the nesting printer + NestingPrinter * nestingPrinter = new NestingPrinter(child); + subConfig = config.substr(startPos + 2, endPos - startPos - 2); + lastCommaPos = string::npos; + commaPos = subConfig.find(","); + if(commaPos == string::npos) + return false; + childSwitchVar = child->getRegNum(subConfig.substr(0, commaPos)); + if(childSwitchVar == -1) + { + cerr << "Couldn't configure switching variable!" << endl; + return false; + } + //Eat up remaining arguments + while(commaPos != string::npos) + { + lastCommaPos = commaPos; + commaPos = subConfig.find(",", commaPos + 1); + } + if(lastCommaPos != string::npos) + { + subConfig = subConfig.substr(lastCommaPos + 1, subConfig.length() - lastCommaPos - 1); + } + if(!nestingPrinter->configure(subConfig)) + { + delete nestingPrinter; + cerr << "Error configuring nesting printer" << endl; + return false; + } + nestingPrinter->switchVar = childSwitchVar; + printers.push_back(nestingPrinter); + break; + default: + cerr << "Unrecognized printer type" << endl; + return false; + } + //Move down past what we just parsed + startPos = endPos + 1; + endPos = length; + type = findSub(config, startPos, endPos); + if(type == PRINTER_ERROR) + { + cerr << "Unable to find subprinters on later tries" << endl; + return false; + } + } + //Put in the trailing stuff + string trailer = config.substr(startPos, length - startPos); + constStrings.push_back(trailer); + return true; +} + +bool RegPrinter::configure(string config) +{ + //Figure out what our register number is based on the name we're given + int num = child->getRegNum(config); + if(num == -1) + { + cerr << "Couldn't find register " << config << endl; + return false; + } + regNum(num); + return true; +} + +ostream & NestingPrinter::writeOut(ostream & os) +{ + if(switchVar == -1 || child->diffSinceUpdate(switchVar)) + { + int x; + for(x = 0; x < numPrinters; x++) + { + os << constStrings[x]; + os << printers[x]; + } + os << constStrings[x]; + } + return os; +} + +ostream & RegPrinter::writeOut(ostream & os) +{ + os << child->printReg(intRegNum); + return os; +} + |