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 SyntaxError(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 SyntaxError('ID or ARR expected, got %s' % tokstr[tok])
123 (tok, val, str) = tokenize(str)
125 raise SyntaxError('SP expected, got %s' % tokstr[tok])
126 (tok, val, str) = skip(str, SP, tok, val)
129 raise SyntaxError('ID expected, got %s' % tokstr[tok])
130 attr = Attr(type_name, is_array, val)
131 (tok, val, str) = skip(str, SP)
133 raise SyntaxError('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 SyntaxError('ID expected, got %s' % tokstr[tok])
144 dprint('parse_message(): msg = %s', msg)
145 (tok, val, str) = skip(str, SP)
147 raise SyntaxError('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 ##########################################################################
286 msgs = [Message('int'), Message('string')] \
287 + parse(file(args[0]).read())
290 msg = search(msgs, args[1])
292 print "can't find message with name %s in %s" % (args[1],
297 pbfile = file(args[2])
298 decode_message(pbfile.read(), msg)
301 if __name__ == '__main__':
303 sys.exit(main(*sys.argv[1:]))