| /* |
| * Copyright (c) 2006-2007 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; |
| long int commaPos, lastCommaPos, childSwitchVar; |
| //Set up the register printer |
| RegPrinter * regPrinter = new RegPrinter(child); |
| NestingPrinter * nestingPrinter = new NestingPrinter(child); |
| 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); |
| 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 |
| 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; |
| } |
| |