13 sys.stderr.write("%s:%d: %s\n" % (file_name, line_number, msg))
25 line = input_file.readline()
26 line = re.sub('#.*', '\n', line)
32 fatal("syntax error expecting %s" % type)
49 if token == ('id', id_):
57 return c.isalnum() or c in '-_'
66 if token == ('eof', ):
67 fatal("unexpected end of input")
80 if line.startswith('=>'):
83 elif line[0] in '[]()?|*+=:':
86 elif is_idchar(line[0]):
88 while n < len(line) and is_idchar(line[n]):
94 fatal("unknown character %c" % line[0])
99 argv0 = os.path.basename(sys.argv[0])
101 %(argv0)s, parser generator for SPV XML members
102 usage: %(argv0)s GRAMMAR header PREFIX
103 %(argv0)s GRAMMAR code PREFIX HEADER_NAME
104 where GRAMMAR contains grammar definitions\
105 ''' % {"argv0": argv0})
111 sub = parse_alternation()
115 member_name, nonterminal_name = parse_name()
116 if member_name.isupper():
117 fatal('%s; unknown terminal' % member_name)
119 return {'type': 'nonterminal',
120 'nonterminal_name': nonterminal_name,
121 'member_name': member_name}
124 def parse_quantified():
126 if token[0] in ['*', '+', '?']:
127 item = {'type': token[0], 'item': item}
132 def parse_sequence():
133 if match_id('EMPTY'):
134 return {'type': 'empty'}
137 sub = parse_quantified()
138 if sub['type'] == 'sequence':
139 items.extend(sub[1:])
142 if token[0] in ('|', ';', ')', 'eof'):
144 return {'type': 'sequence', 'items': items} if len(items) > 1 else items[0]
147 def parse_alternation():
148 items = [parse_sequence()]
150 items.append(parse_sequence())
152 return {'type': '|', 'items': items}
158 # The name used in XML for the attribute or element always comes
164 # If a different name is needed to disambiguate when the same name
165 # is used in different contexts in XML, it comes later, in
169 unique_name = token[1]
173 unique_name = xml_name
175 return unique_name, xml_name
179 def parse_production():
180 unique_name, xml_name = parse_name()
182 attr_xml_names = set()
185 attr_unique_name, attr_xml_name = parse_name()
189 while not match(')'):
191 attr_value.add(token[1])
196 if attr_unique_name not in enums:
197 enums[attr_unique_name] = attr_value
198 elif enums[attr_unique_name] != attr_value:
199 sys.stderr.write('%s: different enums with same name\n'
202 elif match_id('bool'):
203 attr_value = set(('true', 'false'))
204 elif match_id('dimension'):
205 attr_value = 'dimension'
206 elif match_id('real'):
208 elif match_id('int'):
210 elif match_id('color'):
212 elif match_id('ref'):
215 attr_value = ('ref', ref_type)
219 while not match(')'):
221 ref_types.add(token[1])
224 attr_value = ('ref', ref_types)
226 attr_value = ('ref', None)
228 fatal("unknown attribute value type")
230 attr_value = 'string'
231 attr_required = not match('?')
233 if attr_xml_name == 'id':
234 if attr_value != 'string':
235 fatal("id attribute must have string type")
238 if attr_unique_name in attributes:
239 fatal("production %s has two attributes %s" % (unique_name,
241 if attr_xml_name in attr_xml_names:
242 fatal("production %s has two attributes %s" % (unique_name,
244 attr_xml_names.add(attr_xml_name)
245 attributes[attr_unique_name] = (attr_xml_name,
246 attr_value, attr_required)
247 if 'id' not in attributes:
248 attributes["id"] = ('id', 'id', False)
253 rhs = {'type': 'text'}
254 elif match_id('ETC'):
255 rhs = {'type': 'etc'}
257 rhs = parse_alternation()
260 for a in rhs['items'] if rhs['type'] == '|' else (rhs,):
261 for term in a['items'] if a['type'] == 'sequence' else (a,):
262 if term['type'] == 'empty':
264 elif term['type'] == 'nonterminal':
266 elif term['type'] == '?' and term['item']['type'] == 'nonterminal':
268 elif (term['type'] in ('*', '+')
269 and term['item']['type'] == 'nonterminal'):
273 term['seq_name'] = 'seq' if n == 1 else 'seq%d' % n
275 return unique_name, xml_name, attributes, rhs
279 def print_members(attributes, rhs, indent):
282 for unique_name, (xml_name, value, required) in attributes.items():
283 c_name = name_to_id(unique_name)
284 if type(value) is set:
287 attrs += [('bool %s_present;' % c_name,
288 'True if attribute present')]
289 elif value == set(('true', 'false')):
291 attrs += [('bool %s;' % c_name, None)]
293 attrs += [('int %s;' % c_name,
294 '-1 if not present, otherwise 0 or 1')]
296 attrs += [('enum %s%s %s;' % (prefix, c_name, c_name),
297 'Always nonzero' if required else
298 'Zero if not present')]
301 if unique_name not in used_enums:
302 new_enums.add(unique_name)
303 elif value == 'dimension' or value == 'real':
304 attrs += [('double %s;' % c_name,
305 'In inches. ' + ('Always present' if required else
306 'DBL_MAX if not present'))]
308 attrs += [('int %s;' % c_name,
309 'Always present' if required
310 else 'INT_MIN if not present')]
311 elif value == 'color':
312 attrs += [('int %s;' % c_name,
313 'Always present' if required
314 else '-1 if not present')]
315 elif value == 'string':
316 attrs += [('char *%s;' % c_name,
317 'Always nonnull' if required else 'Possibly null')]
318 elif value[0] == 'ref':
319 struct = ('spvxml_node'
320 if value[1] is None or type(value[1]) is set
321 else '%s%s' % (prefix, name_to_id(value[1])))
322 attrs += [('struct %s *%s;' % (struct, c_name),
323 'Always nonnull' if required else 'Possibly null')]
329 for enum_name in new_enums:
330 used_enums.add(enum_name)
331 c_name = name_to_id(enum_name)
332 print '\nenum %s%s {' % (prefix, c_name)
334 for value in sorted(enums[enum_name]):
335 print ' %s%s_%s%s,' % (prefix.upper(),
337 name_to_id(value).upper(),
338 ' = 1' if i == 0 else '')
341 print 'const char *%s%s_to_string (enum %s%s);' % (
342 prefix, c_name, prefix, c_name)
344 print '\nstruct %s%s {' % (prefix, name_to_id(name))
345 print '%sstruct spvxml_node node_;' % indent
348 print '\n%s/* Attributes. */' % indent
349 for decl, comment in attrs:
350 line = '%s%s' % (indent, decl)
352 n_spaces = max(35 - len(line), 1)
353 line += '%s/* %s. */' % (' ' * n_spaces, comment)
356 if rhs['type'] == 'etc' or rhs['type'] == 'empty':
359 print '\n%s/* Content. */' % indent
360 if rhs['type'] == 'text':
361 print '%schar *text; /* Always nonnull. */' % indent
364 for a in rhs['items'] if rhs['type'] == '|' else (rhs,):
365 for term in a['items'] if a['type'] == 'sequence' else (a,):
366 if term['type'] == 'empty':
368 elif term['type'] == 'nonterminal':
369 nt_name = name_to_id(term['nonterminal_name'])
370 member_name = name_to_id(term['member_name'])
371 print '%sstruct %s%s *%s; /* Always nonnull. */' % (
372 indent, prefix, nt_name, member_name)
373 elif term['type'] == '?' and term['item']['type'] == 'nonterminal':
374 nt_name = name_to_id(term['item']['nonterminal_name'])
375 member_name = name_to_id(term['item']['member_name'])
376 print '%sstruct %s%s *%s; /* Possibly null. */' % (
377 indent, prefix, nt_name, member_name)
378 elif (term['type'] in ('*', '+')
379 and term['item']['type'] == 'nonterminal'):
380 nt_name = name_to_id(term['item']['nonterminal_name'])
381 member_name = name_to_id(term['item']['member_name'])
382 print '%sstruct %s%s **%s;' % (indent, prefix,
383 nt_name, member_name)
384 print '%ssize_t n_%s;' % (indent, member_name)
386 seq_name = term['seq_name']
387 print '%sstruct spvxml_node **%s;' % (indent, seq_name)
388 print '%ssize_t n_%s;' % (indent, seq_name)
392 return ''.join(['"'] + ["\\x%02x" % ord(x) for x in s] + ['"'])
395 class Parser_Context(object):
396 def __init__(self, function_name, productions):
399 self.need_error_handler = False
401 self.parser_index = 0
402 self.productions = productions
404 self.function_name = function_name
406 def gen_name(self, prefix):
407 n = self.suffixes.get(prefix, 0) + 1
408 self.suffixes[prefix] = n
409 return '%s%d' % (prefix, n) if n > 1 else prefix
410 def new_function(self, type_name):
411 f = Function('%s_%d' % (self.function_name, len(self.functions) + 1),
413 self.functions += [f]
417 def print_attribute_decls(name, attributes):
420 for unique_name, (xml_name, value, required) in sorted(attributes.items()):
421 c_name = name_to_id(unique_name)
422 print(' ATTR_%s,' % c_name.upper())
424 print(' struct spvxml_attribute attrs[] = {')
425 for unique_name, (xml_name, value, required) in sorted(attributes.items()):
426 c_name = name_to_id(unique_name)
427 print(' [ATTR_%s] = { "%s", %s, NULL },'
428 % (c_name.upper(), xml_name, 'true' if required else 'false'))
430 print(' enum { N_ATTRS = sizeof attrs / sizeof *attrs };')
433 def print_parser_for_attributes(name, attributes):
434 print(' /* Parse attributes. */')
435 print(' spvxml_parse_attributes (&nctx);')
440 for unique_name, (xml_name, value, required) in sorted(attributes.items()):
441 c_name = name_to_id(unique_name)
442 params = '&nctx, &attrs[ATTR_%s]' % c_name.upper()
443 if type(value) is set:
446 print(' spvxml_attr_parse_fixed (%s, "%s");'
447 % (params, tuple(value)[0]))
449 print(' p->%s_present = spvxml_attr_parse_fixed (\n'
451 % (c_name, params, tuple(value)[0]))
452 elif value == set(('true', 'false')):
453 print(' p->%s = spvxml_attr_parse_bool (%s);'
456 map_name = '%s%s_map' % (prefix, c_name)
457 print(' p->%s = spvxml_attr_parse_enum (\n'
459 % (c_name, params, map_name))
460 elif value in ('real', 'dimension', 'int', 'color'):
461 print(' p->%s = spvxml_attr_parse_%s (%s);'
462 % (c_name, value, params))
463 elif value == 'string':
464 print(' p->%s = attrs[ATTR_%s].value;\n'
465 ' attrs[ATTR_%s].value = NULL;'
466 % (c_name, c_name.upper(),
469 print(' p->node_.id = attrs[ATTR_%s].value;\n'
470 ' attrs[ATTR_%s].value = NULL;'
471 % (c_name.upper(), c_name.upper()))
472 elif value[0] == 'ref':
478 spvxml_node_context_uninit (&nctx);
479 ctx->hard_error = true;
483 % (prefix, name_to_id(name)))
485 class Function(object):
486 def __init__(self, function_name, type_name):
487 self.function_name = function_name
488 self.type_name = type_name
491 def gen_name(self, prefix):
492 n = self.suffixes.get(prefix, 0) + 1
493 self.suffixes[prefix] = n
494 return '%s%d' % (prefix, n) if n > 1 else prefix
498 %s (struct spvxml_node_context *nctx, xmlNode **input, struct %s *p)
500 % (self.function_name, self.type_name))
501 while self.code and self.code[0] == '':
502 self.code = self.code[1:]
503 for line in self.code:
504 print(' %s' % line if line else '')
505 print(' return true;')
509 STATE_ALTERNATION = 1
515 def generate_content_parser(nonterminal, rhs, function, ctx, state, seq_name):
516 seq_name = seq_name if seq_name else rhs.get('seq_name')
517 ctx.parser_index += 1
519 if rhs['type'] == 'etc':
520 function.code += ['spvxml_content_parse_etc (input);']
521 elif rhs['type'] == 'text':
522 function.code += ['if (!spvxml_content_parse_text (nctx, input, &p->text))',
524 elif rhs['type'] == '|':
525 for i in range(len(rhs['items'])):
526 choice = rhs['items'][i]
527 subfunc = ctx.new_function(function.type_name)
528 generate_content_parser(nonterminal, choice, subfunc, ctx,
530 if state == STATE_START
531 else STATE_GENERAL, seq_name)
532 function.code += ['%(start)s!%(tryfunc)s (nctx, input, p, %(subfunc)s)%(end)s'
533 % {'start': 'if (' if i == 0 else ' && ',
534 'subfunc': subfunc.function_name,
535 'tryfunc': '%stry_parse_%s'
536 % (prefix, name_to_id(nonterminal)),
537 'end': ')' if i == len(rhs['items']) - 1 else ''}]
538 function.code += [' {',
539 ' spvxml_content_error (nctx, *input, "Syntax error.");',
542 elif rhs['type'] == 'sequence':
543 for element in rhs['items']:
544 generate_content_parser(nonterminal, element, function, ctx,
546 if state in (STATE_START,
548 else STATE_GENERAL, seq_name)
549 elif rhs['type'] == 'empty':
550 function.code += ['(void) nctx;']
551 function.code += ['(void) input;']
552 function.code += ['(void) p;']
553 elif rhs['type'] in ('*', '+', '?'):
554 subfunc = ctx.new_function(function.type_name)
555 generate_content_parser(nonterminal, rhs['item'], subfunc, ctx,
557 if rhs['type'] == '?'
558 else STATE_REPETITION)
559 if state in (STATE_START,
562 else STATE_GENERAL, seq_name)
563 next_name = function.gen_name('next')
564 args = {'subfunc': subfunc.function_name,
565 'tryfunc': '%stry_parse_%s' % (prefix,
566 name_to_id (nonterminal))}
567 if rhs['type'] == '?':
569 '%(tryfunc)s (nctx, input, p, %(subfunc)s);' % args]
571 if rhs['type'] == '+':
572 function.code += ['if (!%(subfunc)s (nctx, input, p))' % args,
575 'while (%(tryfunc)s (nctx, input, p, %(subfunc)s))' % args,
577 elif rhs['type'] == 'nonterminal':
578 node_name = function.gen_name('node')
581 'xmlNode *%s;' % node_name,
582 'if (!spvxml_content_parse_element (nctx, input, "%s", &%s))'
583 % (ctx.productions[rhs['nonterminal_name']][0], node_name),
585 if state in (STATE_START,
589 target = '&p->%s' % name_to_id(rhs['member_name'])
591 assert state in (STATE_REPETITION, STATE_GENERAL)
592 member = name_to_id(rhs['member_name']) if state == STATE_REPETITION else seq_name
593 function.code += ['struct %s%s *%s;' % (
594 prefix, name_to_id(rhs['nonterminal_name']), member)]
595 target = '&%s' % member
597 'if (!%sparse_%s (nctx->up, %s, %s))'
598 % (prefix, name_to_id(rhs['nonterminal_name']), node_name, target),
600 if state in (STATE_REPETITION, STATE_GENERAL):
602 'p->%s = xrealloc (p->%s, sizeof *p->%s * (p->n_%s + 1));'
603 % (member, member, member, member),
604 'p->%s[p->n_%s++] = %s;' % (member, member,
605 '&%s->node_' % member
606 if state == STATE_GENERAL
611 def print_parser(name, production, productions, indent):
612 xml_name, attributes, rhs = production
616 %(prefix)stry_parse_%(name)s (
617 struct spvxml_node_context *nctx, xmlNode **input,
618 struct %(prefix)s%(name)s *p,
619 bool (*sub) (struct spvxml_node_context *,
621 struct %(prefix)s%(name)s *))
623 xmlNode *next = *input;
624 bool ok = sub (nctx, &next, p);
627 else if (!nctx->up->hard_error) {
628 free (nctx->up->error);
629 nctx->up->error = NULL;
634 'name': name_to_id(name)})
636 ctx = Parser_Context('%sparse_%s' % (prefix, name_to_id(name)),
638 if rhs['type'] not in ('empty', 'etc'):
639 function = ctx.new_function('%s%s' % (prefix, name_to_id(name)))
640 generate_content_parser(name, rhs, function, ctx, 0, None)
641 for f in reversed(ctx.functions):
646 %(prefix)sparse_%(name)s (
647 struct spvxml_context *ctx, xmlNode *input,
648 struct %(prefix)s%(name)s **p_)
651 'name': name_to_id(name)})
653 print_attribute_decls(name, attributes)
655 print(' struct spvxml_node_context nctx = {')
657 print(' .parent = input,')
658 print(' .attrs = attrs,')
659 print(' .n_attrs = N_ATTRS,')
662 print(' *p_ = NULL;')
663 print(' struct %(prefix)s%(name)s *p = xzalloc (sizeof *p);'
665 'name': name_to_id(name)})
666 print(' p->node_.raw = input;')
667 print(' p->node_.class_ = &%(prefix)s%(name)s_class;'
669 'name': name_to_id(name)})
672 print_parser_for_attributes(name, attributes)
674 if rhs['type'] == 'empty':
677 if (!spvxml_content_parse_end (&nctx, input->children)) {
678 ctx->hard_error = true;
679 spvxml_node_context_uninit (&nctx);
683 % (prefix, name_to_id(name)))
684 elif rhs['type'] == 'etc':
686 /* Ignore content. */
691 input = input->children;
692 if (!%s (&nctx, &input, p)
693 || !spvxml_content_parse_end (&nctx, input)) {
694 ctx->hard_error = true;
695 spvxml_node_context_uninit (&nctx);
699 % (function.function_name,
700 prefix, name_to_id(name)))
703 spvxml_node_context_uninit (&nctx);
710 def print_free_members(attributes, rhs, indent):
711 for unique_name, (xml_name, value, required) in attributes.items():
712 c_name = name_to_id(unique_name)
713 if (type(value) is set
714 or value in ('dimension', 'real', 'int', 'color', 'id')
715 or value[0] == 'ref'):
717 elif value == 'string':
718 print(' free (p->%s);' % c_name);
722 if rhs['type'] in ('etc', 'empty'):
724 elif rhs['type'] == 'text':
725 print(' free (p->text);')
728 for a in rhs['items'] if rhs['type'] == '|' else (rhs,):
729 for term in a['items'] if a['type'] == 'sequence' else (a,):
730 if term['type'] == 'empty':
732 elif (term['type'] == 'nonterminal'
733 or (term['type'] == '?'
734 and term['item']['type'] == 'nonterminal')):
735 if term['type'] == '?':
737 nt_name = name_to_id(term['nonterminal_name'])
738 member_name = name_to_id(term['member_name'])
739 print(' %sfree_%s (p->%s);' % (prefix, nt_name,
741 elif (term['type'] in ('*', '+')
742 and term['item']['type'] == 'nonterminal'):
743 nt_name = name_to_id(term['item']['nonterminal_name'])
744 member_name = name_to_id(term['item']['member_name'])
746 for (size_t i = 0; i < p->n_%s; i++)
747 %sfree_%s (p->%s[i]);
750 prefix, nt_name, member_name,
754 seq_name = 'seq' if n == 1 else 'seq%d' % n
756 for (size_t i = 0; i < p->n_%s; i++)
757 p->%s[i]->class_->spvxml_node_free (p->%s[i]);
762 print(' free (p->node_.id);')
766 def print_free(name, production, indent):
767 xml_name, attributes, rhs = production
771 %(prefix)sfree_%(name)s (struct %(prefix)s%(name)s *p)
775 ''' % {'prefix': prefix,
776 'name': name_to_id(name)}
778 print_free_members(attributes, rhs, ' ' * 4)
783 return s[0].lower() + ''.join(['_%c' % x.lower() if x.isupper() else x
784 for x in s[1:]]).replace('-', '_')
787 def print_recurse_members(attributes, rhs, function):
788 if rhs['type'] == 'etc' or rhs['type'] == 'empty':
790 elif rhs['type'] == 'text':
794 for a in rhs['items'] if rhs['type'] == '|' else (rhs,):
795 for term in a['items'] if a['type'] == 'sequence' else (a,):
796 if term['type'] == 'empty':
798 elif (term['type'] == 'nonterminal'
799 or (term['type'] == '?'
800 and term['item']['type'] == 'nonterminal')):
801 if term['type'] == '?':
803 nt_name = name_to_id(term['nonterminal_name'])
804 member_name = name_to_id(term['member_name'])
805 print(' %s%s_%s (ctx, p->%s);'
806 % (prefix, function, nt_name, member_name))
807 elif (term['type'] in ('*', '+')
808 and term['item']['type'] == 'nonterminal'):
809 nt_name = name_to_id(term['item']['nonterminal_name'])
810 member_name = name_to_id(term['item']['member_name'])
812 for (size_t i = 0; i < p->n_%s; i++)
813 %s%s_%s (ctx, p->%s[i]);'''
815 prefix, function, nt_name, member_name))
818 seq_name = 'seq' if n == 1 else 'seq%d' % n
820 for (size_t i = 0; i < p->n_%s; i++)
821 p->%s[i]->class_->spvxml_node_%s (ctx, p->%s[i]);'''
823 seq_name, function, seq_name))
826 def print_collect_ids(name, production):
827 xml_name, attributes, rhs = production
831 %(prefix)scollect_ids_%(name)s (struct spvxml_context *ctx, struct %(prefix)s%(name)s *p)
836 spvxml_node_collect_id (ctx, &p->node_);
837 ''' % {'prefix': prefix,
838 'name': name_to_id(name)}
840 print_recurse_members(attributes, rhs, 'collect_ids')
845 def print_resolve_refs(name, production):
846 xml_name, attributes, rhs = production
850 %(prefix)sis_%(name)s (const struct spvxml_node *node)
852 return node->class_ == &%(prefix)s%(name)s_class;
855 struct %(prefix)s%(name)s *
856 %(prefix)scast_%(name)s (const struct spvxml_node *node)
858 return (node && %(prefix)sis_%(name)s (node)
859 ? UP_CAST (node, struct %(prefix)s%(name)s, node_)
864 %(prefix)sresolve_refs_%(name)s (struct spvxml_context *ctx UNUSED, struct %(prefix)s%(name)s *p UNUSED)
868 ''' % {'prefix': prefix,
869 'name': name_to_id(name)}
872 for unique_name, (xml_name, value, required) in sorted(attributes.items()):
873 c_name = name_to_id(unique_name)
874 if type(value) is set or value[0] != 'ref':
878 print(' p->%s = spvxml_node_resolve_ref (ctx, p->node_.raw, \"%s\", NULL, 0);'
879 % (c_name, xml_name))
885 if type(value[1]) is set:
886 print(' static const struct spvxml_node_class *const %s[] = {' % name)
887 for ref_type in value[1]:
888 print(' &%(prefix)s%(ref_type)s_class,'
890 'ref_type': name_to_id(ref_type)})
892 print(' const size_t n_%s = sizeof %s / sizeof *%s;'
893 % (name, name, name))
894 print(' p->%(member)s = spvxml_node_resolve_ref (ctx, p->node_.raw, \"%(attr)s\", %(name)s, n_%(name)s);'
901 print(' static const struct spvxml_node_class *const %s' % name)
902 print(' = &%(prefix)s%(ref_type)s_class;'
904 'ref_type': name_to_id(value[1])})
905 print(' p->%(member)s = %(prefix)scast_%(ref_type)s (spvxml_node_resolve_ref (ctx, p->node_.raw, \"%(attr)s\", &%(name)s, 1));'
910 'ref_type': name_to_id(value[1])})
913 print_recurse_members(attributes, rhs, 'resolve_refs')
919 return s[0].lower() + ''.join(['_%c' % x.lower() if x.isupper() else x
920 for x in s[1:]]).replace('-', '_')
923 if __name__ == "__main__":
926 options, args = getopt.gnu_getopt(sys.argv[1:], 'h', ['help'])
927 except getopt.GetoptError as e:
928 sys.stderr.write("%s: %s\n" % (argv0, e.msg))
931 for key, value in options:
932 if key in ['-h', '--help']:
938 sys.stderr.write("%s: bad usage (use --help for help)\n" % argv0)
943 file_name, output_type, prefix = args[:3]
944 input_file = open(file_name)
946 prefix = '%s_' % prefix
961 if token[0] == 'eof':
964 name, xml_name, attributes, rhs = parse_production()
965 if name in productions:
966 fatal("%s: duplicate production" % name)
967 productions[name] = (xml_name, attributes, rhs)
969 print '/* Generated automatically -- do not modify! -*- buffer-read-only: t -*- */'
970 if output_type == 'code' and len(args) == 4:
971 header_name = args[3]
979 #include "libpspp/cast.h"
980 #include "libpspp/str.h"
981 #include "gl/xalloc.h"
984 for enum_name, values in sorted(enums.items()):
988 c_name = name_to_id(enum_name)
989 print('\nstatic const struct spvxml_enum %s%s_map[] = {'
991 for value in sorted(values):
992 print(' { "%s", %s%s_%s },' % (value, prefix.upper(),
994 name_to_id(value).upper()))
995 print(' { NULL, 0 },')
997 print('\nconst char *')
998 print('%s%s_to_string (enum %s%s %s)'
999 % (prefix, c_name, prefix, c_name, c_name))
1001 print(' switch (%s) {' % c_name)
1002 for value in sorted(values):
1003 print(' case %s%s_%s: return "%s";'
1004 % (prefix.upper(), c_name.upper(),
1005 name_to_id(value).upper(), value))
1006 print(' default: return NULL;')
1010 for name, (xml_name, attributes, rhs) in sorted(productions.items()):
1011 print('static void %(prefix)scollect_ids_%(name)s (struct spvxml_context *, struct %(prefix)s%(name)s *);\n'
1012 'static void %(prefix)sresolve_refs_%(name)s (struct spvxml_context *ctx UNUSED, struct %(prefix)s%(name)s *p UNUSED);\n'
1013 % {'prefix': prefix,
1014 'name': name_to_id(name)})
1015 for name, production in sorted(productions.items()):
1016 print_parser(name, production, productions, ' ' * 4)
1017 print_free(name, production, ' ' * 4)
1018 print_collect_ids(name, production)
1019 print_resolve_refs(name, production)
1022 %(prefix)sdo_free_%(name)s (struct spvxml_node *node)
1024 %(prefix)sfree_%(name)s (UP_CAST (node, struct %(prefix)s%(name)s, node_));
1028 %(prefix)sdo_collect_ids_%(name)s (struct spvxml_context *ctx, struct spvxml_node *node)
1030 %(prefix)scollect_ids_%(name)s (ctx, UP_CAST (node, struct %(prefix)s%(name)s, node_));
1034 %(prefix)sdo_resolve_refs_%(name)s (struct spvxml_context *ctx, struct spvxml_node *node)
1036 %(prefix)sresolve_refs_%(name)s (ctx, UP_CAST (node, struct %(prefix)s%(name)s, node_));
1039 struct spvxml_node_class %(prefix)s%(name)s_class = {
1041 %(prefix)sdo_free_%(name)s,
1042 %(prefix)sdo_collect_ids_%(name)s,
1043 %(prefix)sdo_resolve_refs_%(name)s,
1046 % {'prefix': prefix,
1047 'name': name_to_id(name),
1048 'class': (name if name == production[0]
1049 else '%s (%s)' % (name, production[0]))})
1050 elif output_type == 'header' and len(args) == 3:
1052 #ifndef %(PREFIX)sPARSER_H
1053 #define %(PREFIX)sPARSER_H
1057 #include <stdbool.h>
1058 #include "output/spv/spvxml-helpers.h"\
1059 """ % {'PREFIX': prefix.upper()}
1060 for name, (xml_name, attributes, rhs) in sorted(productions.items()):
1061 print_members(attributes, rhs, ' ' * 4)
1064 extern struct spvxml_node_class %(prefix)s%(name)s_class;
1066 bool %(prefix)sparse_%(name)s (struct spvxml_context *, xmlNode *input, struct %(prefix)s%(name)s **);
1067 void %(prefix)sfree_%(name)s (struct %(prefix)s%(name)s *);
1068 bool %(prefix)sis_%(name)s (const struct spvxml_node *);
1069 struct %(prefix)s%(name)s *%(prefix)scast_%(name)s (const struct spvxml_node *);'''
1070 % {'prefix': prefix,
1071 'name': name_to_id(name)})
1074 #endif /* %(PREFIX)sPARSER_H */""" % {'PREFIX': prefix.upper()}
1076 sys.stderr.write("%s: bad usage (use --help for help)" % argv0)