7 option_ptrsize
= struct
.calcsize("P")
8 option_intsize
= struct
.calcsize("l")
9 option_floatsize
= struct
.calcsize("f")
10 option_inttype
= "long"
11 option_floattype
= "float"
24 def debug_print(self
, level
):
25 print (" "*level
) + " ".join(self
.values
),
26 if len(self
.children
):
28 for c
in self
.children
:
29 c
.debug_print(level
+1)
35 for c
in self
.children
:
38 # TODO: should return list of items in the tree,
39 def gather(self
, str):
40 def recurse(parts
, path
, node
):
43 path
= path
+ "." + node
.values
[0]
49 for c
in node
.children
:
50 if parts
[0] == "*" or c
.values
[0] == parts
[0]:
53 l
+= recurse(parts
[1:], path
+"."+node
.values
[0], c
)
55 l
+= recurse(parts
[1:], node
.values
[0], c
)
57 l
+= recurse(parts
[1:], path
, c
)
60 parts
= str.split(".")
61 return recurse(parts
, "", self
)
63 def find_node(self
, str):
64 parts
= str.split(".")
73 for c
in node
.children
:
74 if part
== c
.values
[0]:
83 def get_single(self
, str):
84 parts
= str.split("@")
91 node
= self
.find_node(parts
[0])
94 print "failed to get", str
98 return node
.get_path()[1:]
99 return node
.values
[index
]
104 return self
.parent
.get_path() + "." + self
.values
[0]
106 def get_single_name(self
, str):
107 return self
.get_path()[1:] + "." + str
112 def parse_node(self
, this_node
):
113 while len(self
.lines
):
114 line
= self
.lines
.pop(0) # grab line
116 fields
= line
.strip().split() # TODO: improve this to handle strings with spaces
120 if fields
[-1] == '{':
122 new_node
.parent
= this_node
123 new_node
.values
= fields
[:-1]
124 this_node
.children
+= [new_node
]
125 self
.parse_node(new_node
)
126 elif fields
[-1] == '}':
130 new_node
.parent
= this_node
131 new_node
.values
= fields
132 this_node
.children
+= [new_node
]
134 def parse_file(self
, filename
):
135 self
.lines
= file(filename
).readlines()
140 def parse_file(filename
):
141 return parser().parse_file(filename
)
144 def __init__(self
, index
, target
):
148 class data_constructor
:
156 def get_type(self
, s
):
157 return self
.trans
.types
[s
]
159 def allocate(self
, size
):
160 index
= len(self
.data
)
161 self
.data
+= "\0"*size
164 def add_pointer(self
, index
, target
):
165 self
.pointers
+= [pointer(index
, target
)]
167 def add_enum(self
, name
, value
):
168 self
.enums
[name
] = value
170 def get_enum_value(self
, name
):
171 if not name
in self
.enums
:
172 print "ERROR: couldn't find enum '%s'" % (name
)
173 return self
.enums
[name
]
175 def add_target(self
, target
, index
):
176 # TODO: warn about duplicates
177 #print "add_target(target='%s' index=%d)" % (target, index)
178 self
.targets
[target
] = index
180 def write(self
, index
, size
, data
):
182 self
.data
= self
.data
[:index
] + data
+ self
.data
[index
+size
:]
185 print "\tself.data =", self
.data
186 print "\tdata =", data
188 def patch_pointers(self
):
189 for p
in self
.pointers
:
190 if p
.target
in self
.targets
:
191 i
= self
.targets
[p
.target
]
192 #print "ptr @ %d -> %s -> %d" % (p.index, p.target, i)
193 data
= struct
.pack("P", i
)
194 self
.write(p
.index
, len(data
), data
)
196 print "ERROR: couldn't find target '%s' for pointer at %d" % (p
.target
, p
.index
)
212 for m
in self
.members
:
216 def emit_header_code(self
, out
):
217 print >>out
, "struct", self
.name
219 for m
in self
.members
:
220 for l
in m
.get_code():
221 print >>out
, "\t" + l
225 def emit_source_code(self
, out
):
226 print >>out
, "static void patch_ptr_%s(%s *self, char *base)" % (self
.name
, self
.name
)
228 for m
in self
.members
:
229 for l
in m
.get_patch_code("self", "base"):
230 print >>out
, "\t" + l
234 def emit_data(self
, cons
, index
, src_data
):
237 for m
in self
.members
:
239 m
.emit_data(cons
, member_index
, src_data
)
240 member_index
+= m
.size()
251 def get_patch_code(self
, ptrname
, basename
):
254 def emit_data(self
, cons
, index
, src_data
):
257 class variable_int(variable
):
259 return ["%s %s;" % (option_inttype
, self
.name
)]
261 return option_intsize
262 def emit_data(self
, cons
, index
, src_data
):
264 value
= int(self
.expr
)
266 value
= int(src_data
.get_single(self
.expr
))
267 #print "int", self.name, "=", value, "@", index
268 data
= struct
.pack("l", value
)
269 cons
.write(index
, len(data
), data
)
271 class variable_float(variable
):
273 return ["%s %s;" % (option_floattype
, self
.name
)]
275 return option_floatsize
276 def emit_data(self
, cons
, index
, src_data
):
278 value
= float(self
.expr
)
280 value
= float(src_data
.get_single(self
.expr
))
281 #print "int", self.name, "=", value, "@", index
282 data
= struct
.pack("f", value
)
283 cons
.write(index
, len(data
), data
)
285 class variable_string(variable
):
287 return ["char *%s;" % (self
.name
)]
288 def get_patch_code(self
, ptrname
, basename
):
289 return ["patch_ptr((char **)&(%s->%s), %s);" % (ptrname
, self
.name
, basename
)]
291 return option_ptrsize
292 def emit_data(self
, cons
, index
, src_data
):
293 string
= src_data
.get_single(self
.expr
)
294 string
= string
.strip()[1:-1] # skip " and "
296 string_index
= cons
.allocate(len(string
)+1)
297 cons
.write(string_index
, len(string
), string
)
299 data
= struct
.pack("P", string_index
) # TODO: solve this
300 cons
.write(index
, len(data
), data
)
302 class variable_ptr(variable
):
304 return ["%s *%s;" % (self
.subtype
, self
.name
)]
305 def get_patch_code(self
, ptrname
, basename
):
306 return ["patch_ptr((char**)&(%s->%s), %s);" % (ptrname
, self
.name
, basename
)]
308 return option_ptrsize
309 def emit_data(self
, cons
, index
, src_data
):
310 target
= src_data
.get_single(self
.expr
)
311 cons
.add_pointer(index
, target
)
313 class variable_enum(variable
):
315 return ["long *%s;" % (self
.name
)]
317 return option_intsize
318 def emit_data(self
, cons
, index
, src_data
):
319 target
= src_data
.get_single(self
.expr
)
320 data
= struct
.pack("l", cons
.get_enum_value(target
))
321 cons
.write(index
, len(data
), data
)
323 class variable_instance(variable
):
325 return ["%s %s;" % (self
.subtype
, self
.name
)]
326 def get_patch_code(self
, ptrname
, basename
):
327 return ["patch_ptr_%s(&(%s->%s), %s);" % (self
.subtype
, ptrname
, self
.name
, basename
)]
329 return self
.translator
.types
[self
.subtype
].size()
330 def emit_data(self
, cons
, index
, src_data
):
331 target
= src_data
.find_node(self
.expr
)
332 translator
.types
[self
.subtype
].emit_data(cons
, index
, target
)
334 #cons.add_pointer(index, target)
336 class variable_array(variable
):
338 return ["long num_%s;" % self
.name
,
339 "%s *%s;" % (self
.subtype
, self
.name
)]
340 def get_patch_code(self
, ptrname
, baseptr
):
342 code
+= ["patch_ptr((char**)&(%s->%s), %s);" % (ptrname
, self
.name
, baseptr
)]
343 code
+= ["for(int i = 0; i < %s->num_%s; i++)" % (ptrname
, self
.name
)]
344 code
+= ["\tpatch_ptr_%s(%s->%s+i, %s);" % (self
.subtype
, ptrname
, self
.name
, baseptr
)]
346 def emit_data(self
, cons
, index
, src_data
):
347 array_data
= src_data
.gather(self
.expr
)
348 array_type
= cons
.get_type(self
.subtype
)
349 size
= array_type
.size()*len(array_data
)
351 #print "packing array", self.name
352 #print "\ttype =", array_type.name
353 #print "\tsize =", array_type.size()
354 array_index
= cons
.allocate(size
)
355 data
= struct
.pack("lP", len(array_data
), array_index
) # TODO: solve this
356 cons
.write(index
, len(data
), data
)
358 member_index
= array_index
359 for node
in array_data
:
360 cons
.add_target(node
.get_path()[1:], member_index
)
361 array_type
.emit_data(cons
, member_index
, node
)
362 member_index
+= array_type
.size()
363 #print "array", member_index
366 return option_ptrsize
+option_intsize
368 class const_arrayint
:
373 def emit_header_code(self
, out
):
376 for i
in xrange(0, len(self
.values
)):
377 print >>out
, "\t%s_%s = %d," % (self
.name
.upper(), self
.values
[i
].upper(), i
)
379 print >>out
, "\tNUM_%sS = %d" % (self
.name
.upper(), len(self
.values
))
391 self
.types
["int"] = variable_int()
392 self
.types
["float"] = variable_float()
393 self
.types
["string"] = variable_string()
394 self
.types
["ptr"] = variable_ptr()
395 self
.types
["array"] = variable_array()
397 def parse_variable(self
, node
):
398 if len(node
.values
) != 4:
400 raise "error parsing variable"
402 type = node
.values
[0]
408 elif type == "float":
410 elif type == "string":
411 v
= variable_string()
414 parts
= type.split(":")
416 raise "can't emit code for variable %s of type %s" % (self
.name
, self
.type)
417 elif parts
[0] == "ptr":
420 elif parts
[0] == "instance":
422 v
= variable_instance()
423 elif parts
[0] == "array":
427 raise "can't emit code for variable %s of type %s" % (self
.name
, self
.type)
430 v
.type = node
.values
[0]
432 v
.name
= node
.values
[1]
433 assignment
= node
.values
[2]
434 v
.expr
= node
.values
[3]
435 if assignment
!= "=":
436 raise "error parsing variable. expected ="
439 def parse_struct(self
, node
):
440 if len(node
.values
) != 2:
441 raise "error parsing struct"
443 s
.name
= node
.values
[1]
445 for statement
in node
.children
:
446 s
.members
+= [self
.parse_variable(statement
)]
449 def parse_constant(self
, node
):
450 if len(node
.values
) != 5:
452 raise "error parsing constant"
454 type = node
.values
[1]
455 name
= node
.values
[2]
456 assignment
= node
.values
[3]
457 expression
= node
.values
[4]
459 if assignment
!= "=":
461 raise "error parsing constant"
463 ints
= const_arrayint()
466 items
= self
.srcdata
.gather(expression
)
468 ints
.values
+= [c
.name()]
469 self
.constants
+= [ints
]
471 def parse(self
, script
, srcdata
):
472 self
.srcdata
= srcdata
473 for statement
in script
.children
:
474 if statement
.values
[0] == "struct":
475 s
= self
.parse_struct(statement
)
477 self
.types
[s
.name
] = s
478 elif statement
.values
[0] == "const":
479 self
.parse_constant(statement
)
481 raise "unknown statement:" + statement
483 def emit_header_code(self
, out
):
484 for c
in self
.constants
:
485 c
.emit_header_code(out
)
487 for s
in self
.structs
:
488 s
.emit_header_code(out
)
490 print >>out
, "struct data_container *load_data_from_file(const char *filename);"
491 print >>out
, "struct data_container *load_data_from_memory(unsigned char *filename);"
495 def emit_source_code(self
, out
, header_filename
):
502 static void patch_ptr(char **ptr, char *base)
504 *ptr = base+(size_t)(*ptr);
506 ''' % header_filename
508 for s
in self
.structs
:
509 s
.emit_source_code(out
)
512 data_container *load_data_from_memory(unsigned char *mem)
514 if(mem[0] != sizeof(void*))
516 if(mem[1] != sizeof(long))
518 if(mem[2] != sizeof(float))
521 /* patch all pointers */
522 data_container *con = (data_container*)(mem + 4);
523 patch_ptr_data_container(con, (char *)con);
527 data_container *load_data_from_file(const char *filename)
529 unsigned char *data = 0;
533 FILE *f = fopen(filename, "rb");
536 fseek(f, 0, SEEK_END);
538 fseek(f, 0, SEEK_SET);
540 /* allocate, read data and close file */
541 data = (unsigned char *)malloc(size);
542 fread(data, 1, size, f);
545 return load_data_from_memory(data);
551 for s
in self
.structs
:
552 if s
.name
== "data_container":
553 #print "found data_container"
554 cons
= data_constructor()
556 i
= cons
.allocate(s
.size())
557 s
.emit_data(cons
, i
, self
.srcdata
)
558 cons
.patch_pointers()
559 header
= struct
.pack("bbbb", option_ptrsize
, option_intsize
, option_floatsize
, 0)
560 return header
+ cons
.data
562 def create_translator(script
, srcdata
):
564 t
.parse(script
, srcdata
)
567 def validate(script
, validator
):
568 def validate_values(values
, check
):
569 if not len(check
) or check
[0] == "*":
570 print "too many values"
572 p
= check
[0].split(":")
576 # TODO: check type and stuff
581 print "unexpected value"
582 validate_values(values
[1:], check
[1:])
584 if len(check
) > 1 and check
[1] != "*":
585 print "to few values"
587 if len(script
.values
):
588 validate_values(script
.values
, validator
.values
)
590 for child
in script
.children
:
591 tag
= child
.values
[0]
592 n
= validator
.find_node("tag:"+tag
)
595 for vc
in validator
.children
:
596 if "ident:" in vc
.values
[0]:
603 print "error:", tag
, "not found"
608 input_filename
= sys
.argv
[1]
609 script_filename
= sys
.argv
[2]
617 if sys
.argv
[3] == '-h':
618 header_filename
= sys
.argv
[4]
619 elif sys
.argv
[3] == '-s':
620 source_filename
= sys
.argv
[4]
621 sheader_filename
= sys
.argv
[5]
622 elif sys
.argv
[3] == '-d':
623 output_filename
= sys
.argv
[4]
624 elif sys
.argv
[3] == '-c':
625 coutput_filename
= sys
.argv
[4]
627 srcdata
= parse_file(input_filename
)
628 script
= parse_file(script_filename
)
630 translator
= create_translator(script
, srcdata
)
633 translator
.emit_header_code(file(header_filename
, "w"))
635 translator
.emit_source_code(file(source_filename
, "w"), os
.path
.basename(sheader_filename
))
638 rawdata
= translator
.emit_data()
639 file(output_filename
, "wb").write(rawdata
)
642 rawdata
= translator
.emit_data()
643 f
= file(coutput_filename
, "w")
645 print >>f
,"unsigned char internal_data[] = {"
646 print >>f
,str(ord(rawdata
[0])),
647 for d
in rawdata
[1:]: