Clone of mesa.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. #!/usr/bin/env python
  2. #############################################################################
  3. #
  4. # Copyright 2008 Tungsten Graphics, Inc.
  5. #
  6. # This program is free software: you can redistribute it and/or modify it
  7. # under the terms of the GNU Lesser General Public License as published
  8. # by the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU Lesser General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU Lesser General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. #
  19. #############################################################################
  20. import sys
  21. import xml.parsers.expat
  22. import binascii
  23. from model import *
  24. ELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF = range(4)
  25. class XmlToken:
  26. def __init__(self, type, name_or_data, attrs = None, line = None, column = None):
  27. assert type in (ELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF)
  28. self.type = type
  29. self.name_or_data = name_or_data
  30. self.attrs = attrs
  31. self.line = line
  32. self.column = column
  33. def __str__(self):
  34. if self.type == ELEMENT_START:
  35. return '<' + self.name_or_data + ' ...>'
  36. if self.type == ELEMENT_END:
  37. return '</' + self.name_or_data + '>'
  38. if self.type == CHARACTER_DATA:
  39. return self.name_or_data
  40. if self.type == EOF:
  41. return 'end of file'
  42. assert 0
  43. class XmlTokenizer:
  44. """Expat based XML tokenizer."""
  45. def __init__(self, fp, skip_ws = True):
  46. self.fp = fp
  47. self.tokens = []
  48. self.index = 0
  49. self.final = False
  50. self.skip_ws = skip_ws
  51. self.character_pos = 0, 0
  52. self.character_data = ''
  53. self.parser = xml.parsers.expat.ParserCreate()
  54. self.parser.StartElementHandler = self.handle_element_start
  55. self.parser.EndElementHandler = self.handle_element_end
  56. self.parser.CharacterDataHandler = self.handle_character_data
  57. def handle_element_start(self, name, attributes):
  58. self.finish_character_data()
  59. line, column = self.pos()
  60. token = XmlToken(ELEMENT_START, name, attributes, line, column)
  61. self.tokens.append(token)
  62. def handle_element_end(self, name):
  63. self.finish_character_data()
  64. line, column = self.pos()
  65. token = XmlToken(ELEMENT_END, name, None, line, column)
  66. self.tokens.append(token)
  67. def handle_character_data(self, data):
  68. if not self.character_data:
  69. self.character_pos = self.pos()
  70. self.character_data += data
  71. def finish_character_data(self):
  72. if self.character_data:
  73. if not self.skip_ws or not self.character_data.isspace():
  74. line, column = self.character_pos
  75. token = XmlToken(CHARACTER_DATA, self.character_data, None, line, column)
  76. self.tokens.append(token)
  77. self.character_data = ''
  78. def next(self):
  79. size = 16*1024
  80. while self.index >= len(self.tokens) and not self.final:
  81. self.tokens = []
  82. self.index = 0
  83. data = self.fp.read(size)
  84. self.final = len(data) < size
  85. try:
  86. self.parser.Parse(data, self.final)
  87. except xml.parsers.expat.ExpatError, e:
  88. #if e.code == xml.parsers.expat.errors.XML_ERROR_NO_ELEMENTS:
  89. if e.code == 3:
  90. pass
  91. else:
  92. raise e
  93. if self.index >= len(self.tokens):
  94. line, column = self.pos()
  95. token = XmlToken(EOF, None, None, line, column)
  96. else:
  97. token = self.tokens[self.index]
  98. self.index += 1
  99. return token
  100. def pos(self):
  101. return self.parser.CurrentLineNumber, self.parser.CurrentColumnNumber
  102. class TokenMismatch(Exception):
  103. def __init__(self, expected, found):
  104. self.expected = expected
  105. self.found = found
  106. def __str__(self):
  107. return '%u:%u: %s expected, %s found' % (self.found.line, self.found.column, str(self.expected), str(self.found))
  108. class XmlParser:
  109. """Base XML document parser."""
  110. def __init__(self, fp):
  111. self.tokenizer = XmlTokenizer(fp)
  112. self.consume()
  113. def consume(self):
  114. self.token = self.tokenizer.next()
  115. def match_element_start(self, name):
  116. return self.token.type == ELEMENT_START and self.token.name_or_data == name
  117. def match_element_end(self, name):
  118. return self.token.type == ELEMENT_END and self.token.name_or_data == name
  119. def element_start(self, name):
  120. while self.token.type == CHARACTER_DATA:
  121. self.consume()
  122. if self.token.type != ELEMENT_START:
  123. raise TokenMismatch(XmlToken(ELEMENT_START, name), self.token)
  124. if self.token.name_or_data != name:
  125. raise TokenMismatch(XmlToken(ELEMENT_START, name), self.token)
  126. attrs = self.token.attrs
  127. self.consume()
  128. return attrs
  129. def element_end(self, name):
  130. while self.token.type == CHARACTER_DATA:
  131. self.consume()
  132. if self.token.type != ELEMENT_END:
  133. raise TokenMismatch(XmlToken(ELEMENT_END, name), self.token)
  134. if self.token.name_or_data != name:
  135. raise TokenMismatch(XmlToken(ELEMENT_END, name), self.token)
  136. self.consume()
  137. def character_data(self, strip = True):
  138. data = ''
  139. while self.token.type == CHARACTER_DATA:
  140. data += self.token.name_or_data
  141. self.consume()
  142. if strip:
  143. data = data.strip()
  144. return data
  145. class TraceParser(XmlParser):
  146. def parse(self):
  147. self.element_start('trace')
  148. calls = []
  149. while self.token.type not in (ELEMENT_END, EOF):
  150. calls.append(self.parse_call())
  151. if self.token.type != EOF:
  152. self.element_end('trace')
  153. return Trace(calls)
  154. def parse_call(self):
  155. attrs = self.element_start('call')
  156. klass = attrs['class']
  157. method = attrs['method']
  158. args = []
  159. ret = None
  160. while self.token.type == ELEMENT_START:
  161. if self.token.name_or_data == 'arg':
  162. arg = self.parse_arg()
  163. args.append(arg)
  164. elif self.token.name_or_data == 'ret':
  165. ret = self.parse_ret()
  166. elif self.token.name_or_data == 'call':
  167. # ignore nested function calls
  168. self.parse_call()
  169. else:
  170. raise TokenMismatch("<arg ...> or <ret ...>", self.token)
  171. self.element_end('call')
  172. return Call(klass, method, args, ret)
  173. def parse_arg(self):
  174. attrs = self.element_start('arg')
  175. name = attrs['name']
  176. value = self.parse_value()
  177. self.element_end('arg')
  178. return name, value
  179. def parse_ret(self):
  180. attrs = self.element_start('ret')
  181. value = self.parse_value()
  182. self.element_end('ret')
  183. return value
  184. def parse_value(self):
  185. expected_tokens = ('null', 'bool', 'int', 'uint', 'float', 'string', 'enum', 'array', 'struct', 'ptr', 'bytes')
  186. if self.token.type == ELEMENT_START:
  187. if self.token.name_or_data in expected_tokens:
  188. method = getattr(self, 'parse_' + self.token.name_or_data)
  189. return method()
  190. raise TokenMismatch(" or " .join(expected_tokens), self.token)
  191. def parse_null(self):
  192. self.element_start('null')
  193. self.element_end('null')
  194. return Literal(None)
  195. def parse_bool(self):
  196. self.element_start('bool')
  197. value = int(self.character_data())
  198. self.element_end('bool')
  199. return Literal(value)
  200. def parse_int(self):
  201. self.element_start('int')
  202. value = int(self.character_data())
  203. self.element_end('int')
  204. return Literal(value)
  205. def parse_uint(self):
  206. self.element_start('uint')
  207. value = int(self.character_data())
  208. self.element_end('uint')
  209. return Literal(value)
  210. def parse_float(self):
  211. self.element_start('float')
  212. value = float(self.character_data())
  213. self.element_end('float')
  214. return Literal(value)
  215. def parse_enum(self):
  216. self.element_start('enum')
  217. name = self.character_data()
  218. self.element_end('enum')
  219. return NamedConstant(name)
  220. def parse_string(self):
  221. self.element_start('string')
  222. value = self.character_data()
  223. self.element_end('string')
  224. return Literal(value)
  225. def parse_bytes(self):
  226. self.element_start('bytes')
  227. value = binascii.a2b_hex(self.character_data())
  228. self.element_end('bytes')
  229. return Literal(value)
  230. def parse_array(self):
  231. self.element_start('array')
  232. elems = []
  233. while self.token.type != ELEMENT_END:
  234. elems.append(self.parse_elem())
  235. self.element_end('array')
  236. return Array(elems)
  237. def parse_elem(self):
  238. self.element_start('elem')
  239. value = self.parse_value()
  240. self.element_end('elem')
  241. return value
  242. def parse_struct(self):
  243. attrs = self.element_start('struct')
  244. name = attrs['name']
  245. members = []
  246. while self.token.type != ELEMENT_END:
  247. members.append(self.parse_member())
  248. self.element_end('struct')
  249. return Struct(name, members)
  250. def parse_member(self):
  251. attrs = self.element_start('member')
  252. name = attrs['name']
  253. value = self.parse_value()
  254. self.element_end('member')
  255. return name, value
  256. def parse_ptr(self):
  257. self.element_start('ptr')
  258. address = self.character_data()
  259. self.element_end('ptr')
  260. address = int(address, 16)
  261. return Pointer(address)
  262. def main():
  263. for arg in sys.argv[1:]:
  264. parser = TraceParser(open(arg, 'rt'))
  265. trace = parser.parse()
  266. print trace
  267. if __name__ == '__main__':
  268. main()