2006-09-17 09:46:30 +02:00
|
|
|
/*
|
2007-07-29 05:34:17 +02:00
|
|
|
* Copyright (c) 2006-2007 The Regents of The University of Michigan
|
2006-09-17 09:46:30 +02:00
|
|
|
* 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;
|
2007-07-29 05:34:17 +02:00
|
|
|
long int commaPos, lastCommaPos, childSwitchVar;
|
|
|
|
//Set up the register printer
|
|
|
|
RegPrinter * regPrinter = new RegPrinter(child);
|
|
|
|
NestingPrinter * nestingPrinter = new NestingPrinter(child);
|
2006-09-17 09:46:30 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|