/************************************************************************** * * Copyright 2012 VMware, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * **************************************************************************/ #include #include #include #include #include #include #include using namespace trace; // Parser class for call sets class CallSetParser { CallSet &set; protected: char lookahead; CallSetParser(CallSet &_set) : set(_set), lookahead(0) {} public: void parse() { skipWhiteSpace(); while (lookahead) { assert(!isSpace()); parseRange(); // skip any comma isOperator(','); } } private: void parseRange() { CallNo start = std::numeric_limits::min(); CallNo stop = std::numeric_limits::max(); CallNo step = 1; CallFlags freq = FREQUENCY_ALL; if (isAlpha()) { freq = parseFrequency(); } else { if (isOperator('*')) { // no-change } else { start = parseCallNo(); if (isOperator('-')) { if (isDigit()) { stop = parseCallNo(); } else { // no-change } } else { stop = start; } } if (isOperator('/')) { if (isDigit()) { step = parseCallNo(); } else { freq = parseFrequency(); } } } set.addRange(CallRange(start, stop, step, freq)); } // match and consume an operator bool isOperator(char c) { if (lookahead == c) { consume(); skipWhiteSpace(); return true; } else { return false; } } CallNo parseCallNo() { CallNo number = 0; if (isDigit()) { do { CallNo digit = consume() - '0'; number = number * 10 + digit; } while (isDigit()); } else { std::cerr << "error: expected digit, found '" << lookahead << "'\n"; exit(0); } skipWhiteSpace(); return number; } CallFlags parseFrequency() { std::string freq; if (isAlpha()) { do { freq.push_back(consume()); } while (isAlpha()); } else { std::cerr << "error: expected frequency, found '" << lookahead << "'\n"; exit(0); } skipWhiteSpace(); if (freq == "frame") { return FREQUENCY_FRAME; } else if (freq == "rendertarget" || freq == "fbo") { return FREQUENCY_RENDERTARGET; } else if (freq == "render" || freq == "draw") { return FREQUENCY_RENDER; } else { std::cerr << "error: expected frequency, found '" << freq << "'\n"; exit(0); return FREQUENCY_NONE; } } // match lookahead with a digit (does not consume) bool isDigit() const { return lookahead >= '0' && lookahead <= '9'; } bool isAlpha() const { return lookahead >= 'a' && lookahead <= 'z'; } void skipWhiteSpace() { while (isSpace()) { consume(); } } bool isSpace() const { return lookahead == ' ' || lookahead == '\t' || lookahead == '\r' || lookahead == '\n'; } virtual char consume() = 0; }; class StringCallSetParser : public CallSetParser { const char *buf; public: StringCallSetParser(CallSet &_set, const char *_buf) : CallSetParser(_set), buf(_buf) { lookahead = *buf; } char consume() { char c = lookahead; if (lookahead) { ++buf; lookahead = *buf; } return c; } }; class FileCallSetParser : public CallSetParser { std::ifstream stream; public: FileCallSetParser(CallSet &_set, const char *filename) : CallSetParser(_set) { stream.open(filename); if (!stream.is_open()) { std::cerr << "error: failed to open \"" << filename << "\"\n"; exit(1); } stream.get(lookahead); } char consume() { char c = lookahead; if (stream.eof()) { lookahead = 0; } else { stream.get(lookahead); } return c; } }; CallSet::CallSet(const char *string): limits(std::numeric_limits::min(), std::numeric_limits::max()) { if (*string == '@') { FileCallSetParser parser(*this, &string[1]); parser.parse(); } else { StringCallSetParser parser(*this, string); parser.parse(); } } CallSet::CallSet(CallFlags freq): limits(std::numeric_limits::min(), std::numeric_limits::max()) { if (freq != FREQUENCY_NONE) { CallNo start = std::numeric_limits::min(); CallNo stop = std::numeric_limits::max(); CallNo step = 1; addRange(CallRange(start, stop, step, freq)); assert(!empty()); } }