2 # vim: set encoding=utf8 :
5 ##########################################################################
9 def dprint(msg, *args):
15 ##########################################################################
31 class LexicError(Exception):
36 dprint('tokenize: %s', tokstr[EOF])
64 raise LexicError("unexpected '%s'" % c)
65 dprint('tokenize: %r', (tokstr[tok], val, str[:20]))
66 return (tok, val, str)
70 ##########################################################################
75 def __init__(self, type_name, is_array, name):
76 self.type_name = type_name
77 self.is_array = is_array
79 self.type = None # lo rellena el análisis semántico
83 type_name = self.type.name
86 return 'Attr(%s, %s)' % (type_name, self.name)
89 def __init__(self, name):
95 return 'Message(%s, %s)' % (self.name, self.attrs)
99 class ParserError(Exception):
102 def skip(str, to_skip, current=None, val=''):
105 dprint('skip(%r, %s, %s)', str[:20], tokstr[to_skip], tokstr[current])
106 while to_skip == current:
107 (current, val, str) = tokenize(str)
108 return (current, val, str)
111 (tok, val, str) = tokenize(str)
112 if tok == EOL: # fin de mensaje
114 (tok, val, str) = skip(str, SP, tok, val)
115 if tok != ID and tok != ARR:
116 raise ParserError('ID or ARR expected, got %s' % tokstr[tok])
123 (tok, val, str) = tokenize(str)
125 raise ParserError('SP expected, got %s' % tokstr[tok])
126 (tok, val, str) = skip(str, SP, tok, val)
129 raise ParserError('ID expected, got %s' % tokstr[tok])
130 attr = Attr(type_name, is_array, val)
131 (tok, val, str) = skip(str, SP)
133 raise ParserError('EOL expected, got %s' % tokstr[tok])
136 def parse_message(str):
137 (tok, val, str) = skip(str, EOL)
138 (tok, val, str) = skip(str, SP, tok, val)
142 raise ParserError('ID expected, got %s' % tokstr[tok])
144 dprint('parse_message(): msg = %s', msg)
145 (tok, val, str) = skip(str, SP)
147 raise ParserError('EOL expected, got %s' % tokstr[tok])
148 # ya tengo EOL, vienen atributos (o fin de mensaje)
149 (attr, str) = parse_attr(str)
151 msg.attrs.append(attr)
152 (attr, str) = parse_attr(str)
156 dprint('parse(): str = %r...', str[:20])
158 (msg, str) = parse_message(str)
161 (msg, str) = parse_message(str)
162 dprint('parse(): msg = %s', msg)
163 dprint('parse(): str = %r...', str[:20])
168 ##########################################################################
170 class SemanticError(Exception):
173 def search(msgs, type_name):
175 if msg.name == type_name:
179 def check_types(msgs):
181 for attr in msg.attrs:
182 m = search(msgs, attr.type_name)
184 raise SemanticError('attribute %s in ' \
185 'message %s has an ' \
187 (attr.name, msg.name,
193 ##########################################################################
198 valid_wire_types = (VARINT, LENDEL)
207 class DecodeError(Exception):
210 def decode_varint(str):
214 while c & 0x80: # sigue
216 raise DecodeError('unexpected end of stream when '
219 n += (c & 0x7F) << (7 * i)
224 (key, str) = decode_varint(str)
225 wire_type = key & 0x0000000000000003
227 return (tag, wire_type, str)
229 def check_wire_type(msg, attr, wire_type, expected_type):
230 if wire_type != expected_type:
231 raise DecodeError('expected wire_type %s for attribute %s of '
232 'message %s, got %s' % (wirestr[expected_type],
233 attr.name, msg.name, wirestr[wire_type]))
235 def decode_attribute(str, msg, indent_level, index=0):
236 (tag, wire_type, str) = decode_key(str)
237 if wire_type not in valid_wire_types:
238 raise DecodeError('unknown wire type %d' % wire_type)
239 if tag > len(msg.attrs):
240 raise DecodeError('unknown tag %d for message %s'
242 attr = msg.attrs[tag-1]
243 if not attr.is_array:
244 print "%s%s:" % (indent_level * indentation, attr.name),
245 if attr.is_array and not index:
246 print "%s%s: array" % (indent_level * indentation, attr.name)
248 print "%s%s: %s" % ((indent_level + 1) * indentation, index,
251 if attr.type.name == 'int':
252 check_wire_type(msg, attr, wire_type, VARINT)
253 (val, str) = decode_varint(str)
256 check_wire_type(msg, attr, wire_type, LENDEL)
257 (length, str) = decode_varint(str)
260 if attr.type.name == 'string': # submessage
261 val = val.replace('\\', '\\\\').replace('"', '\\"')
265 decode_array(val, attr.type, indent_level + 1)
267 decode_message(val, attr.type, indent_level + 1)
270 def decode_array(str, msg, indent_level=1):
273 (str, index) = decode_attribute(str, msg, indent_level+1, index)
275 def decode_message(str, msg, indent_level=1):
276 print '%s' % msg.name
279 (str, index) = decode_attribute(str, msg, indent_level, index)
283 ##########################################################################
285 class MessageNotFoundError(Exception):
288 def main(schmfile, pbfile, msgname):
289 msgs = [Message('int'), Message('string')] \
290 + parse(schmfile.read())
293 msg = search(msgs, msgname)
295 raise MessageNotFoundError("can't find message %s" % msgname)
296 decode_message(pbfile.read(), msg)
298 if __name__ == '__main__':
301 schmfile = sys.argv[1]
302 msgname = sys.argv[2]
307 schmfile = file(args[0])
309 print "can't open schema file %s" % schmfile
312 if len(sys.argv) > 3:
314 pbfile = file(sys.argv[3])
316 print "can't open pb file %s" % sys.argv[3]
319 main(schmfile, pbfile, msgname)
320 except LexicError, e:
323 except ParserError, e:
326 except SemanticError, e:
329 except MessageNotFoundError, e:
332 except DecodeError, e: