13a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca#!/usr/bin/env python
23a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca##########################################################################
33a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca#
43a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
53a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# All Rights Reserved.
63a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca#
73a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# Permission is hereby granted, free of charge, to any person obtaining a
83a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# copy of this software and associated documentation files (the
93a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# "Software"), to deal in the Software without restriction, including
103a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# without limitation the rights to use, copy, modify, merge, publish,
113a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# distribute, sub license, and/or sell copies of the Software, and to
123a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# permit persons to whom the Software is furnished to do so, subject to
133a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# the following conditions:
143a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca#
153a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# The above copyright notice and this permission notice (including the
163a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# next paragraph) shall be included in all copies or substantial portions
173a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# of the Software.
183a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca#
193a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
203a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
213a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
223a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
233a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
243a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
253a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
263a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca#
273a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca##########################################################################
283a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
293a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
303a618da6e15a6dc4351eb933583569a1ecefc768José Fonsecaimport sys
313a618da6e15a6dc4351eb933583569a1ecefc768José Fonsecaimport xml.parsers.expat
323a618da6e15a6dc4351eb933583569a1ecefc768José Fonsecaimport binascii
333a618da6e15a6dc4351eb933583569a1ecefc768José Fonsecaimport optparse
343a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
353a618da6e15a6dc4351eb933583569a1ecefc768José Fonsecafrom model import *
363a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
373a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
383a618da6e15a6dc4351eb933583569a1ecefc768José FonsecaELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF = range(4)
393a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
403a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
413a618da6e15a6dc4351eb933583569a1ecefc768José Fonsecaclass XmlToken:
423a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
433a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def __init__(self, type, name_or_data, attrs = None, line = None, column = None):
443a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        assert type in (ELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF)
453a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.type = type
463a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.name_or_data = name_or_data
473a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.attrs = attrs
483a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.line = line
493a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.column = column
503a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
513a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def __str__(self):
523a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        if self.type == ELEMENT_START:
533a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            return '<' + self.name_or_data + ' ...>'
543a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        if self.type == ELEMENT_END:
553a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            return '</' + self.name_or_data + '>'
563a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        if self.type == CHARACTER_DATA:
573a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            return self.name_or_data
583a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        if self.type == EOF:
593a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            return 'end of file'
603a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        assert 0
613a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
623a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
633a618da6e15a6dc4351eb933583569a1ecefc768José Fonsecaclass XmlTokenizer:
643a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    """Expat based XML tokenizer."""
653a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
663a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def __init__(self, fp, skip_ws = True):
673a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.fp = fp
683a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.tokens = []
693a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.index = 0
703a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.final = False
713a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.skip_ws = skip_ws
723a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
733a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.character_pos = 0, 0
743a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.character_data = ''
753a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
763a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.parser = xml.parsers.expat.ParserCreate()
773a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.parser.StartElementHandler  = self.handle_element_start
783a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.parser.EndElementHandler    = self.handle_element_end
793a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.parser.CharacterDataHandler = self.handle_character_data
803a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
813a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def handle_element_start(self, name, attributes):
823a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.finish_character_data()
833a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        line, column = self.pos()
843a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        token = XmlToken(ELEMENT_START, name, attributes, line, column)
853a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.tokens.append(token)
863a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
873a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def handle_element_end(self, name):
883a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.finish_character_data()
893a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        line, column = self.pos()
903a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        token = XmlToken(ELEMENT_END, name, None, line, column)
913a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.tokens.append(token)
923a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
933a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def handle_character_data(self, data):
943a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        if not self.character_data:
953a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            self.character_pos = self.pos()
963a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.character_data += data
973a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
983a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def finish_character_data(self):
993a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        if self.character_data:
1003a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            if not self.skip_ws or not self.character_data.isspace():
1013a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                line, column = self.character_pos
1023a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                token = XmlToken(CHARACTER_DATA, self.character_data, None, line, column)
1033a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                self.tokens.append(token)
1043a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            self.character_data = ''
1053a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1063a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def next(self):
1073a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        size = 16*1024
1083a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        while self.index >= len(self.tokens) and not self.final:
1093a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            self.tokens = []
1103a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            self.index = 0
1113a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            data = self.fp.read(size)
1123a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            self.final = len(data) < size
1133a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            data = data.rstrip('\0')
1143a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            try:
1153a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                self.parser.Parse(data, self.final)
1163a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            except xml.parsers.expat.ExpatError, e:
1173a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                #if e.code == xml.parsers.expat.errors.XML_ERROR_NO_ELEMENTS:
1183a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                if e.code == 3:
1193a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                    pass
1203a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                else:
1213a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                    raise e
1223a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        if self.index >= len(self.tokens):
1233a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            line, column = self.pos()
1243a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            token = XmlToken(EOF, None, None, line, column)
1253a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        else:
1263a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            token = self.tokens[self.index]
1273a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            self.index += 1
1283a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return token
1293a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1303a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def pos(self):
1313a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return self.parser.CurrentLineNumber, self.parser.CurrentColumnNumber
1323a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1333a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1343a618da6e15a6dc4351eb933583569a1ecefc768José Fonsecaclass TokenMismatch(Exception):
1353a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1363a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def __init__(self, expected, found):
1373a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.expected = expected
1383a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.found = found
1393a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1403a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def __str__(self):
1413a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return '%u:%u: %s expected, %s found' % (self.found.line, self.found.column, str(self.expected), str(self.found))
1423a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1433a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1443a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1453a618da6e15a6dc4351eb933583569a1ecefc768José Fonsecaclass XmlParser:
1463a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    """Base XML document parser."""
1473a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1483a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def __init__(self, fp):
1493a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.tokenizer = XmlTokenizer(fp)
1503a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.consume()
1513a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1523a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def consume(self):
1533a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.token = self.tokenizer.next()
1543a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1553a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def match_element_start(self, name):
1563a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return self.token.type == ELEMENT_START and self.token.name_or_data == name
1573a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1583a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def match_element_end(self, name):
1593a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return self.token.type == ELEMENT_END and self.token.name_or_data == name
1603a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1613a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def element_start(self, name):
1623a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        while self.token.type == CHARACTER_DATA:
1633a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            self.consume()
1643a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        if self.token.type != ELEMENT_START:
1653a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            raise TokenMismatch(XmlToken(ELEMENT_START, name), self.token)
1663a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        if self.token.name_or_data != name:
1673a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            raise TokenMismatch(XmlToken(ELEMENT_START, name), self.token)
1683a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        attrs = self.token.attrs
1693a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.consume()
1703a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return attrs
1713a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1723a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def element_end(self, name):
1733a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        while self.token.type == CHARACTER_DATA:
1743a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            self.consume()
1753a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        if self.token.type != ELEMENT_END:
1763a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            raise TokenMismatch(XmlToken(ELEMENT_END, name), self.token)
1773a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        if self.token.name_or_data != name:
1783a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            raise TokenMismatch(XmlToken(ELEMENT_END, name), self.token)
1793a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.consume()
1803a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1813a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def character_data(self, strip = True):
1823a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        data = ''
1833a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        while self.token.type == CHARACTER_DATA:
1843a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            data += self.token.name_or_data
1853a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            self.consume()
1863a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        if strip:
1873a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            data = data.strip()
1883a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return data
1893a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1903a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1913a618da6e15a6dc4351eb933583569a1ecefc768José Fonsecaclass TraceParser(XmlParser):
1923a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1933a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def __init__(self, fp):
1943a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        XmlParser.__init__(self, fp)
1953a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.last_call_no = 0
1963a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
1973a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def parse(self):
1983a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_start('trace')
1993a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        while self.token.type not in (ELEMENT_END, EOF):
2003a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            call = self.parse_call()
2013a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            self.handle_call(call)
2023a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        if self.token.type != EOF:
2033a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            self.element_end('trace')
2043a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
2053a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def parse_call(self):
2063a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        attrs = self.element_start('call')
2073a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        try:
2083a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            no = int(attrs['no'])
2093a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        except KeyError:
2103a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            self.last_call_no += 1
2113a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            no = self.last_call_no
2123a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        else:
2133a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            self.last_call_no = no
2143a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        klass = attrs['class']
2153a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        method = attrs['method']
2163a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        args = []
2173a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        ret = None
2183a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        while self.token.type == ELEMENT_START:
2193a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            if self.token.name_or_data == 'arg':
2203a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                arg = self.parse_arg()
2213a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                args.append(arg)
2223a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            elif self.token.name_or_data == 'ret':
2233a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                ret = self.parse_ret()
2243a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            elif self.token.name_or_data == 'call':
2253a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                # ignore nested function calls
2263a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                self.parse_call()
2273a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            else:
2283a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                raise TokenMismatch("<arg ...> or <ret ...>", self.token)
2293a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_end('call')
2303a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
2313a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return Call(no, klass, method, args, ret)
2323a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
2333a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def parse_arg(self):
2343a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        attrs = self.element_start('arg')
2353a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        name = attrs['name']
2363a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        value = self.parse_value()
2373a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_end('arg')
2383a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
2393a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return name, value
2403a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
2413a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def parse_ret(self):
2423a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        attrs = self.element_start('ret')
2433a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        value = self.parse_value()
2443a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_end('ret')
2453a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
2463a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return value
2473a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
2483a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def parse_value(self):
2493a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        expected_tokens = ('null', 'bool', 'int', 'uint', 'float', 'string', 'enum', 'array', 'struct', 'ptr', 'bytes')
2503a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        if self.token.type == ELEMENT_START:
2513a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            if self.token.name_or_data in expected_tokens:
2523a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                method = getattr(self, 'parse_' +  self.token.name_or_data)
2533a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                return method()
2543a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        raise TokenMismatch(" or " .join(expected_tokens), self.token)
2553a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
2563a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def parse_null(self):
2573a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_start('null')
2583a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_end('null')
2593a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return Literal(None)
2603a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
2613a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def parse_bool(self):
2623a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_start('bool')
2633a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        value = int(self.character_data())
2643a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_end('bool')
2653a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return Literal(value)
2663a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
2673a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def parse_int(self):
2683a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_start('int')
2693a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        value = int(self.character_data())
2703a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_end('int')
2713a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return Literal(value)
2723a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
2733a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def parse_uint(self):
2743a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_start('uint')
2753a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        value = int(self.character_data())
2763a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_end('uint')
2773a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return Literal(value)
2783a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
2793a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def parse_float(self):
2803a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_start('float')
2813a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        value = float(self.character_data())
2823a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_end('float')
2833a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return Literal(value)
2843a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
2853a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def parse_enum(self):
2863a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_start('enum')
2873a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        name = self.character_data()
2883a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_end('enum')
2893a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return NamedConstant(name)
2903a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
2913a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def parse_string(self):
2923a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_start('string')
2933a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        value = self.character_data()
2943a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_end('string')
2953a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return Literal(value)
2963a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
2973a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def parse_bytes(self):
2983a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_start('bytes')
2993a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        value = binascii.a2b_hex(self.character_data())
3003a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_end('bytes')
3013a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return Literal(value)
3023a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3033a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def parse_array(self):
3043a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_start('array')
3053a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        elems = []
3063a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        while self.token.type != ELEMENT_END:
3073a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            elems.append(self.parse_elem())
3083a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_end('array')
3093a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return Array(elems)
3103a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3113a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def parse_elem(self):
3123a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_start('elem')
3133a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        value = self.parse_value()
3143a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_end('elem')
3153a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return value
3163a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3173a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def parse_struct(self):
3183a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        attrs = self.element_start('struct')
3193a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        name = attrs['name']
3203a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        members = []
3213a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        while self.token.type != ELEMENT_END:
3223a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            members.append(self.parse_member())
3233a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_end('struct')
3243a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return Struct(name, members)
3253a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3263a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def parse_member(self):
3273a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        attrs = self.element_start('member')
3283a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        name = attrs['name']
3293a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        value = self.parse_value()
3303a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_end('member')
3313a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3323a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return name, value
3333a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3343a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def parse_ptr(self):
3353a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_start('ptr')
3363a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        address = self.character_data()
3373a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.element_end('ptr')
3383a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3393a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return Pointer(address)
3403a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3413a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def handle_call(self, call):
3423a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        pass
3433a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3443a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3453a618da6e15a6dc4351eb933583569a1ecefc768José Fonsecaclass TraceDumper(TraceParser):
3463a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3473a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def __init__(self, fp):
3483a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        TraceParser.__init__(self, fp)
3493a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.formatter = format.DefaultFormatter(sys.stdout)
3503a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.pretty_printer = PrettyPrinter(self.formatter)
3513a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3523a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def handle_call(self, call):
3533a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        call.visit(self.pretty_printer)
3543a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        self.formatter.newline()
3553a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3563a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3573a618da6e15a6dc4351eb933583569a1ecefc768José Fonsecaclass Main:
3583a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    '''Common main class for all retrace command line utilities.'''
3593a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3603a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def __init__(self):
3613a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        pass
3623a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3633a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def main(self):
3643a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        optparser = self.get_optparser()
3653a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        (options, args) = optparser.parse_args(sys.argv[1:])
3663a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3673a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        if args:
3683a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            for arg in args:
3693a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                if arg.endswith('.gz'):
3703a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                    from gzip import GzipFile
3713a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                    stream = GzipFile(arg, 'rt')
3723a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                elif arg.endswith('.bz2'):
3733a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                    from bz2 import BZ2File
374cdf56eb68d2718b5702f3d09928da404d745b8e1José Fonseca                    stream = BZ2File(arg, 'rU')
3753a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                else:
3763a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                    stream = open(arg, 'rt')
3773a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca                self.process_arg(stream, options)
3783a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        else:
3793a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            self.process_arg(stream, options)
3803a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3813a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def get_optparser(self):
3823a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        optparser = optparse.OptionParser(
3833a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca            usage="\n\t%prog [options] [traces] ...")
3843a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        return optparser
3853a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3863a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    def process_arg(self, stream, options):
3873a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        parser = TraceDumper(stream)
3883a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca        parser.parse()
3893a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3903a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca
3913a618da6e15a6dc4351eb933583569a1ecefc768José Fonsecaif __name__ == '__main__':
3923a618da6e15a6dc4351eb933583569a1ecefc768José Fonseca    Main().main()
393