3 # This is the API builder, it parses the C sources and build the
4 # API formal description in XML.
6 # See Copyright for the status of this software.
15 raw = string.replace(raw, '&', '&')
16 raw = string.replace(raw, '<', '<')
17 raw = string.replace(raw, '>', '>')
18 raw = string.replace(raw, "'", ''')
19 raw = string.replace(raw, '"', '"')
23 def __init__(self, name, module=None, type=None, info=None, extra=None):
32 r = "%s %s:" % (self.type, self.name)
35 if self.module != None:
36 r = r + " from %s" % (self.module)
38 r = r + " " + `self.info`
39 if self.extra != None:
40 r = r + " " + `self.extra`
44 def set_module(self, module):
46 def set_type(self, type):
48 def set_info(self, info):
50 def set_extra(self, extra):
52 def set_static(self, static):
55 def update(self, module, type = None, info = None, extra=None):
56 if module != None and self.module == None:
57 self.set_module(module)
58 if type != None and self.type == None:
67 def __init__(self, name = "noname"):
79 def add(self, name, module, static, type, info=None, extra=None):
84 d = self.identifiers[name]
85 d.update(module, type, info, extra)
87 d = identifier(name, module, type, info, extra)
88 self.identifiers[name] = d
90 if d != None and static == 1:
93 if d != None and name != None and type != None:
94 if type == "function":
95 self.functions[name] = d
96 elif type == "functype":
97 self.functions[name] = d
98 elif type == "variable":
99 self.variables[name] = d
100 elif type == "include":
101 self.includes[name] = d
102 elif type == "struct":
103 self.structs[name] = d
106 elif type == "typedef":
107 self.typedefs[name] = d
108 elif type == "macro":
109 self.macros[name] = d
111 print "Unable to register type ", type
114 def merge(self, idx):
115 for id in idx.functions.keys():
117 # macro might be used to override functions or variables
120 if self.macros.has_key(id):
122 if self.functions.has_key(id):
123 print "function %s from %s redeclared in %s" % (
124 id, self.functions[id].module, idx.functions[id].module)
126 self.functions[id] = idx.functions[id]
127 self.identifiers[id] = idx.functions[id]
128 for id in idx.variables.keys():
130 # macro might be used to override functions or variables
133 if self.macros.has_key(id):
135 if self.variables.has_key(id):
136 print "variable %s from %s redeclared in %s" % (
137 id, self.variables[id].module, idx.variables[id].module)
139 self.variables[id] = idx.variables[id]
140 self.identifiers[id] = idx.variables[id]
141 for id in idx.structs.keys():
142 if self.structs.has_key(id):
143 print "struct %s from %s redeclared in %s" % (
144 id, self.structs[id].module, idx.structs[id].module)
146 self.structs[id] = idx.structs[id]
147 self.identifiers[id] = idx.structs[id]
148 for id in idx.typedefs.keys():
149 if self.typedefs.has_key(id):
150 print "typedef %s from %s redeclared in %s" % (
151 id, self.typedefs[id].module, idx.typedefs[id].module)
153 self.typedefs[id] = idx.typedefs[id]
154 self.identifiers[id] = idx.typedefs[id]
155 for id in idx.macros.keys():
157 # macro might be used to override functions or variables
160 if self.variables.has_key(id):
162 if self.functions.has_key(id):
164 if self.enums.has_key(id):
166 if self.macros.has_key(id):
167 print "macro %s from %s redeclared in %s" % (
168 id, self.macros[id].module, idx.macros[id].module)
170 self.macros[id] = idx.macros[id]
171 self.identifiers[id] = idx.macros[id]
172 for id in idx.enums.keys():
173 if self.enums.has_key(id):
174 print "enum %s from %s redeclared in %s" % (
175 id, self.enums[id].module, idx.enums[id].module)
177 self.enums[id] = idx.enums[id]
178 self.identifiers[id] = idx.enums[id]
180 def merge_public(self, idx):
181 for id in idx.functions.keys():
182 if self.functions.has_key(id):
183 up = idx.functions[id]
184 self.functions[id].update(None, up.type, up.info, up.extra)
186 # print "Function %s from %s is not declared in headers" % (
187 # id, idx.functions[id].module)
188 # TODO: do the same for variables.
190 def analyze_dict(self, type, dict):
193 for name in dict.keys():
199 print " %d %s , %d public" % (count, type, public)
201 print " %d public %s" % (count, type)
205 self.analyze_dict("functions", self.functions)
206 self.analyze_dict("variables", self.variables)
207 self.analyze_dict("structs", self.structs)
208 self.analyze_dict("typedefs", self.typedefs)
209 self.analyze_dict("macros", self.macros)
212 # C parser analysis code
215 "trio": "too many non standard macros",
216 "trio.c": "too many non standard macros",
217 "trionan.c": "too many non standard macros",
218 "triostr.c": "too many non standard macros",
219 "acconfig.h": "generated portability layer",
220 "config.h": "generated portability layer",
221 "libxml.h": "internal only",
225 "WINAPI": (0, "Windows keyword"),
226 "LIBXML_DLL_IMPORT": (0, "Special macro to flag external keywords"),
227 "__declspec": (3, "Windows keyword"),
228 "ATTRIBUTE_UNUSED": (0, "macro keyword"),
229 "LIBEXSLT_PUBLIC": (0, "macro keyword"),
230 "X_IN_Y": (5, "macro function builder"),
234 """A lexer for the C language, tokenize the input by reading and
235 analyzing it line by line"""
236 def __init__(self, input):
245 line = self.input.readline()
248 self.lineno = self.lineno + 1
249 line = string.lstrip(line)
250 line = string.rstrip(line)
253 while line[-1] == '\\':
255 n = self.input.readline()
256 self.lineno = self.lineno + 1
268 def push(self, token):
269 self.tokens.insert(0, token);
272 print "Last token: ", self.last
273 print "Token queue: ", self.tokens
274 print "Line %d end: " % (self.lineno), self.line
277 while self.tokens == []:
279 line = self.getline()
287 self.tokens = map((lambda x: ('preproc', x)),
291 if line[0] == '"' or line[0] == "'":
301 self.line = line[i+1:]
311 line = self.getline()
314 self.last = ('string', tok)
317 if l >= 2 and line[0] == '/' and line[1] == '*':
325 if line[i] == '*' and i+1 < l and line[i+1] == '/':
326 self.line = line[i+2:]
336 line = self.getline()
339 self.last = ('comment', tok)
341 if l >= 2 and line[0] == '/' and line[1] == '/':
343 self.last = ('comment', line)
347 if line[i] == '/' and i+1 < l and line[i+1] == '/':
351 if line[i] == '/' and i+1 < l and line[i+1] == '*':
355 if line[i] == '"' or line[i] == "'":
363 if line[i] == ' ' or line[i] == '\t':
367 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
368 (o >= 48 and o <= 57):
372 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
373 (o >= 48 and o <= 57) or string.find(
374 " \t(){}:;,+-*/%&!|[]=><", line[i]) == -1:
378 self.tokens.append(('name', line[s:i]))
380 if string.find("(){}:;,[]", line[i]) != -1:
381 # if line[i] == '(' or line[i] == ')' or line[i] == '{' or \
382 # line[i] == '}' or line[i] == ':' or line[i] == ';' or \
383 # line[i] == ',' or line[i] == '[' or line[i] == ']':
384 self.tokens.append(('sep', line[i]))
387 if string.find("+-*><=/%&!|.", line[i]) != -1:
388 # if line[i] == '+' or line[i] == '-' or line[i] == '*' or \
389 # line[i] == '>' or line[i] == '<' or line[i] == '=' or \
390 # line[i] == '/' or line[i] == '%' or line[i] == '&' or \
391 # line[i] == '!' or line[i] == '|' or line[i] == '.':
392 if line[i] == '.' and i + 2 < l and \
393 line[i+1] == '.' and line[i+2] == '.':
394 self.tokens.append(('name', '...'))
400 string.find("+-*><=/%&!|", line[j]) != -1):
401 # line[j] == '+' or line[j] == '-' or line[j] == '*' or \
402 # line[j] == '>' or line[j] == '<' or line[j] == '=' or \
403 # line[j] == '/' or line[j] == '%' or line[j] == '&' or \
404 # line[j] == '!' or line[j] == '|'):
405 self.tokens.append(('op', line[i:j+1]))
408 self.tokens.append(('op', line[i]))
414 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
415 (o >= 48 and o <= 57) or (
416 string.find(" \t(){}:;,+-*/%&!|[]=><", line[i]) == -1):
417 # line[i] != ' ' and line[i] != '\t' and
418 # line[i] != '(' and line[i] != ')' and
419 # line[i] != '{' and line[i] != '}' and
420 # line[i] != ':' and line[i] != ';' and
421 # line[i] != ',' and line[i] != '+' and
422 # line[i] != '-' and line[i] != '*' and
423 # line[i] != '/' and line[i] != '%' and
424 # line[i] != '&' and line[i] != '!' and
425 # line[i] != '|' and line[i] != '[' and
426 # line[i] != ']' and line[i] != '=' and
427 # line[i] != '*' and line[i] != '>' and
432 self.tokens.append(('name', line[s:i]))
435 self.tokens = self.tokens[1:]
440 """The C module parser"""
441 def __init__(self, filename, idx = None):
442 self.filename = filename
443 if len(filename) > 2 and filename[-2:] == '.h':
447 self.input = open(filename)
448 self.lexer = CLexer(self.input)
453 self.top_comment = ""
454 self.last_comment = ""
458 return self.lexer.getlineno()
460 def error(self, msg, token=-1):
461 print "Parse Error: " + msg
463 print "Got token ", token
467 def debug(self, msg, token=-1):
468 print "Debug: " + msg
470 print "Got token ", token
473 def parseComment(self, token):
474 if self.top_comment == "":
475 self.top_comment = token[1]
476 if self.comment == None or token[1][0] == '*':
477 self.comment = token[1];
479 self.comment = self.comment + token[1]
480 token = self.lexer.token()
484 # Parse a comment block associate to a macro
486 def parseMacroComment(self, name, quiet = 0):
487 if name[0:2] == '__':
493 if self.comment == None:
495 print "Missing comment for macro %s" % (name)
497 if self.comment[0] != '*':
499 print "Missing * in macro comment for %s" % (name)
501 lines = string.split(self.comment, '\n')
504 if lines[0] != "* %s:" % (name):
506 print "Misformatted macro comment for %s" % (name)
507 print " Expecting '* %s:' got '%s'" % (name, lines[0])
510 while lines[0] == '*':
512 while len(lines) > 0 and lines[0][0:3] == '* @':
515 (arg, desc) = string.split(l, ':', 1)
516 desc=string.strip(desc)
517 arg=string.strip(arg)
520 print "Misformatted macro comment for %s" % (name)
521 print " problem with '%s'" % (lines[0])
525 l = string.strip(lines[0])
526 while len(l) > 2 and l[0:3] != '* @':
529 desc = desc + ' ' + string.strip(l)
534 args.append((arg, desc))
535 while len(lines) > 0 and lines[0] == '*':
538 while len(lines) > 0:
540 while len(l) > 0 and l[0] == '*':
543 desc = desc + " " + l
546 desc = string.strip(desc)
550 print "Macro comment for %s lack description of the macro" % (name)
555 # Parse a comment block and merge the informations found in the
556 # parameters descriptions, finally returns a block as complete
559 def mergeFunctionComment(self, name, description, quiet = 0):
562 if name[0:2] == '__':
565 (ret, args) = description
569 if self.comment == None:
571 print "Missing comment for function %s" % (name)
572 return(((ret[0], retdesc), args, desc))
573 if self.comment[0] != '*':
575 print "Missing * in function comment for %s" % (name)
576 return(((ret[0], retdesc), args, desc))
577 lines = string.split(self.comment, '\n')
580 if lines[0] != "* %s:" % (name):
582 print "Misformatted function comment for %s" % (name)
583 print " Expecting '* %s:' got '%s'" % (name, lines[0])
584 return(((ret[0], retdesc), args, desc))
586 while lines[0] == '*':
589 while len(lines) > 0 and lines[0][0:3] == '* @':
592 (arg, desc) = string.split(l, ':', 1)
593 desc=string.strip(desc)
594 arg=string.strip(arg)
597 print "Misformatted function comment for %s" % (name)
598 print " problem with '%s'" % (lines[0])
602 l = string.strip(lines[0])
603 while len(l) > 2 and l[0:3] != '* @':
606 desc = desc + ' ' + string.strip(l)
613 if args[i][1] == arg:
614 args[i] = (args[i][0], arg, desc)
619 print "Uname to find arg %s from function comment for %s" % (
621 while len(lines) > 0 and lines[0] == '*':
624 while len(lines) > 0:
626 while len(l) > 0 and l[0] == '*':
629 if len(l) >= 6 and l[0:6] == "return" or l[0:6] == "Return":
631 l = string.split(l, ' ', 1)[1]
634 retdesc = string.strip(l)
636 while len(lines) > 0:
638 while len(l) > 0 and l[0] == '*':
641 retdesc = retdesc + " " + l
644 desc = desc + " " + l
647 retdesc = string.strip(retdesc)
648 desc = string.strip(desc)
652 # report missing comments
656 if args[i][2] == None and args[i][0] != "void" and args[i][1] != None:
657 print "Function comment for %s lack description of arg %s" % (name, args[i][1])
659 if retdesc == "" and ret[0] != "void":
660 print "Function comment for %s lack description of return value" % (name)
662 print "Function comment for %s lack description of the function" % (name)
665 return(((ret[0], retdesc), args, desc))
667 def parsePreproc(self, token):
669 if name == "#include":
670 token = self.lexer.token()
673 if token[0] == 'preproc':
674 self.index.add(token[1], self.filename, not self.is_header,
676 return self.lexer.token()
678 if name == "#define":
679 token = self.lexer.token()
682 if token[0] == 'preproc':
683 # TODO macros with arguments
686 token = self.lexer.token()
687 while token != None and token[0] == 'preproc' and \
690 token = self.lexer.token()
692 name = string.split(name, '(') [0]
695 info = self.parseMacroComment(name, not self.is_header)
696 self.index.add(name, self.filename, not self.is_header,
699 token = self.lexer.token()
700 while token != None and token[0] == 'preproc' and \
702 token = self.lexer.token()
706 # token acquisition on top of the lexer, it handle internally
707 # preprocessor and comments since they are logically not part of
708 # the program structure.
713 token = self.lexer.token()
715 if token[0] == 'comment':
716 token = self.parseComment(token)
718 elif token[0] == 'preproc':
719 token = self.parsePreproc(token)
721 elif token[0] == "name" and ignored_words.has_key(token[1]):
722 (n, info) = ignored_words[token[1]]
725 token = self.lexer.token()
727 token = self.lexer.token()
735 # Parse a typedef, it records the type and its name.
737 def parseTypedef(self, token):
740 token = self.parseType(token)
742 self.error("parsing typedef")
744 base_type = self.type
746 #self.debug("end typedef type", token)
748 if token[0] == "name":
750 signature = self.signature
751 if signature != None:
752 type = string.split(type, '(')[0]
753 d = self.mergeFunctionComment(name,
754 ((type, None), signature), 1)
755 self.index.add(name, self.filename, not self.is_header,
758 if base_type == "struct":
759 self.index.add(name, self.filename, not self.is_header,
761 base_type = "struct " + name
763 self.index.add(name, self.filename, not self.is_header,
767 self.error("parsing typedef: expecting a name")
769 #self.debug("end typedef", token)
770 if token != None and token[0] == 'sep' and token[1] == ',':
773 while token != None and token[0] == "op":
774 type = type + token[1]
776 elif token != None and token[0] == 'sep' and token[1] == ';':
778 elif token != None and token[0] == 'name':
782 self.error("parsing typedef: expecting ';'", token)
788 # Parse a C code block, used for functions it parse till
789 # the balancing } included
791 def parseBlock(self, token):
793 if token[0] == "sep" and token[1] == "{":
795 token = self.parseBlock(token)
796 elif token[0] == "sep" and token[1] == "}":
805 # Parse a C struct definition till the balancing }
807 def parseStruct(self, token):
809 #self.debug("start parseStruct", token)
811 if token[0] == "sep" and token[1] == "{":
813 token = self.parseTypeBlock(token)
814 elif token[0] == "sep" and token[1] == "}":
815 self.struct_fields = fields
816 #self.debug("end parseStruct", token)
821 base_type = self.type
822 #self.debug("before parseType", token)
823 token = self.parseType(token)
824 #self.debug("after parseType", token)
825 if token != None and token[0] == "name":
828 if token[0] == "sep" and token[1] == ";":
831 fields.append((self.type, fname, self.comment))
834 self.error("parseStruct: expecting ;", token)
835 elif token != None and token[0] == "sep" and token[1] == "{":
837 token = self.parseTypeBlock(token)
838 if token != None and token[0] == "name":
840 if token != None and token[0] == "sep" and token[1] == ";":
843 self.error("parseStruct: expecting ;", token)
845 self.error("parseStruct: name", token)
847 self.type = base_type;
848 self.struct_fields = fields
849 #self.debug("end parseStruct", token)
854 # Parse a C enum block, parse till the balancing }
856 def parseEnumBlock(self, token):
863 if token[0] == "sep" and token[1] == "{":
865 token = self.parseTypeBlock(token)
866 elif token[0] == "sep" and token[1] == "}":
868 if self.comment != None:
869 comment = self.comment
871 self.enums.append((name, value, comment))
874 elif token[0] == "name":
876 if self.comment != None:
877 comment = string.strip(self.comment)
879 self.enums.append((name, value, comment))
883 if token[0] == "op" and token[1][0] == "=":
885 if len(token[1]) > 1:
888 while token[0] != "sep" or (token[1] != ',' and
890 value = value + token[1]
894 value = "%d" % (int(value) + 1)
896 print "Failed to compute value of enum %s" % (name)
898 if token[0] == "sep" and token[1] == ",":
905 # Parse a C definition block, used for structs it parse till
908 def parseTypeBlock(self, token):
910 if token[0] == "sep" and token[1] == "{":
912 token = self.parseTypeBlock(token)
913 elif token[0] == "sep" and token[1] == "}":
921 # Parse a type: the fact that the type name can either occur after
922 # the definition or within the definition makes it a little harder
923 # if inside, the name token is pushed back before returning
925 def parseType(self, token):
927 self.struct_fields = []
928 self.signature = None
932 while token[0] == "name" and (
933 token[1] == "const" or token[1] == "unsigned"):
937 self.type = self.type + " " + token[1]
940 if token[0] == "name" and (token[1] == "long" or token[1] == "short"):
944 self.type = self.type + " " + token[1]
945 if token[0] == "name" and token[1] == "int":
949 self.type = self.type + " " + tmp[1]
951 elif token[0] == "name" and token[1] == "struct":
955 self.type = self.type + " " + token[1]
958 if token[0] == "name":
961 if token != None and token[0] == "sep" and token[1] == "{":
963 token = self.parseStruct(token)
964 elif token != None and token[0] == "op" and token[1] == "*":
965 self.type = self.type + " " + nametok[1] + " *"
967 while token != None and token[0] == "op" and token[1] == "*":
968 self.type = self.type + " *"
970 if token[0] == "name":
974 self.error("struct : expecting name", token)
976 elif token != None and token[0] == "name" and nametok != None:
977 self.type = self.type + " " + nametok[1]
981 self.lexer.push(token)
985 elif token[0] == "name" and token[1] == "enum":
989 self.type = self.type + " " + token[1]
992 if token != None and token[0] == "sep" and token[1] == "{":
994 token = self.parseEnumBlock(token)
996 self.error("parsing enum: expecting '{'", token)
998 if token != None and token[0] != "name":
999 self.lexer.push(token)
1000 token = ("name", "enum")
1002 enum_type = token[1]
1003 for enum in self.enums:
1004 self.index.add(enum[0], self.filename,
1005 not self.is_header, "enum",
1006 (enum[1], enum[2], enum_type))
1009 elif token[0] == "name":
1011 self.type = token[1]
1013 self.type = self.type + " " + token[1]
1015 self.error("parsing type %s: expecting a name" % (self.type),
1018 token = self.token()
1019 while token != None and (token[0] == "op" or
1020 token[0] == "name" and token[1] == "const"):
1021 self.type = self.type + " " + token[1]
1022 token = self.token()
1025 # if there is a parenthesis here, this means a function type
1027 if token != None and token[0] == "sep" and token[1] == '(':
1028 self.type = self.type + token[1]
1029 token = self.token()
1030 while token != None and token[0] == "op" and token[1] == '*':
1031 self.type = self.type + token[1]
1032 token = self.token()
1033 if token == None or token[0] != "name" :
1034 self.error("parsing function type, name expected", token);
1036 self.type = self.type + token[1]
1038 token = self.token()
1039 if token != None and token[0] == "sep" and token[1] == ')':
1040 self.type = self.type + token[1]
1041 token = self.token()
1042 if token != None and token[0] == "sep" and token[1] == '(':
1043 token = self.token()
1045 token = self.parseSignature(token);
1048 self.error("parsing function type, '(' expected", token);
1051 self.error("parsing function type, ')' expected", token);
1053 self.lexer.push(token)
1058 # do some lookahead for arrays
1060 if token != None and token[0] == "name":
1062 token = self.token()
1063 if token != None and token[0] == "sep" and token[1] == '[':
1064 self.type = self.type + nametok[1]
1065 while token != None and token[0] == "sep" and token[1] == '[':
1066 self.type = self.type + token[1]
1067 token = self.token()
1068 while token != None and token[0] != 'sep' and \
1069 token[1] != ']' and token[1] != ';':
1070 self.type = self.type + token[1]
1071 token = self.token()
1072 if token != None and token[0] == 'sep' and token[1] == ']':
1073 self.type = self.type + token[1]
1074 token = self.token()
1076 self.error("parsing array type, ']' expected", token);
1078 elif token != None and token[0] == "sep" and token[1] == ':':
1079 # remove :12 in case it's a limited int size
1080 token = self.token()
1081 token = self.token()
1082 self.lexer.push(token)
1088 # Parse a signature: '(' has been parsed and we scan the type definition
1089 # up to the ')' included
1090 def parseSignature(self, token):
1092 if token != None and token[0] == "sep" and token[1] == ')':
1094 token = self.token()
1096 while token != None:
1097 token = self.parseType(token)
1098 if token != None and token[0] == "name":
1099 signature.append((self.type, token[1], None))
1100 token = self.token()
1101 elif token != None and token[0] == "sep" and token[1] == ',':
1102 token = self.token()
1104 elif token != None and token[0] == "sep" and token[1] == ')':
1105 # only the type was provided
1106 if self.type == "...":
1107 signature.append((self.type, "...", None))
1109 signature.append((self.type, None, None))
1110 if token != None and token[0] == "sep":
1112 token = self.token()
1114 elif token[1] == ')':
1115 token = self.token()
1117 self.signature = signature
1121 # Parse a global definition, be it a type, variable or function
1122 # the extern "C" blocks are a bit nasty and require it to recurse.
1124 def parseGlobal(self, token):
1126 if token[1] == 'extern':
1127 token = self.token()
1130 if token[0] == 'string':
1132 token = self.token()
1135 if token[0] == 'sep' and token[1] == "{":
1136 token = self.token()
1137 # print 'Entering extern "C line ', self.lineno()
1138 while token != None and (token[0] != 'sep' or
1140 if token[0] == 'name':
1141 token = self.parseGlobal(token)
1144 "token %s %s unexpected at the top level" % (
1145 token[0], token[1]))
1146 token = self.parseGlobal(token)
1147 # print 'Exiting extern "C" line', self.lineno()
1148 token = self.token()
1152 elif token[1] == 'static':
1154 token = self.token()
1155 if token == None or token[0] != 'name':
1158 if token[1] == 'typedef':
1159 token = self.token()
1160 return self.parseTypedef(token)
1162 token = self.parseType(token)
1163 type_orig = self.type
1164 if token == None or token[0] != "name":
1167 self.name = token[1]
1168 token = self.token()
1169 while token != None and (token[0] == "sep" or token[0] == "op"):
1170 if token[0] == "sep":
1172 type = type + token[1]
1173 token = self.token()
1174 while token != None and (token[0] != "sep" or \
1176 type = type + token[1]
1177 token = self.token()
1179 if token != None and token[0] == "op" and token[1] == "=":
1181 # Skip the initialization of the variable
1183 token = self.token()
1184 if token[0] == 'sep' and token[1] == '{':
1185 token = self.token()
1186 token = self.parseBlock(token)
1189 while token != None and (token[0] != "sep" or \
1190 (token[1] != ';' and token[1] != ',')):
1191 token = self.token()
1193 if token == None or token[0] != "sep" or (token[1] != ';' and
1195 self.error("missing ';' or ',' after value")
1197 if token != None and token[0] == "sep":
1200 token = self.token()
1201 if type == "struct":
1202 self.index.add(self.name, self.filename,
1203 not self.is_header, "struct", self.struct_fields)
1205 self.index.add(self.name, self.filename,
1206 not self.is_header, "variable", type)
1208 elif token[1] == "(":
1209 token = self.token()
1210 token = self.parseSignature(token)
1213 if token[0] == "sep" and token[1] == ";":
1214 d = self.mergeFunctionComment(self.name,
1215 ((type, None), self.signature), 1)
1216 self.index.add(self.name, self.filename, static,
1218 token = self.token()
1219 elif token[0] == "sep" and token[1] == "{":
1220 d = self.mergeFunctionComment(self.name,
1221 ((type, None), self.signature), static)
1222 self.index.add(self.name, self.filename, static,
1224 token = self.token()
1225 token = self.parseBlock(token);
1226 elif token[1] == ',':
1228 self.index.add(self.name, self.filename, static,
1231 token = self.token()
1232 while token != None and token[0] == "sep":
1233 type = type + token[1]
1234 token = self.token()
1235 if token != None and token[0] == "name":
1236 self.name = token[1]
1237 token = self.token()
1244 print "Parsing %s" % (self.filename)
1245 token = self.token()
1246 while token != None:
1247 if token[0] == 'name':
1248 token = self.parseGlobal(token)
1250 self.error("token %s %s unexpected at the top level" % (
1251 token[0], token[1]))
1252 token = self.parseGlobal(token)
1258 """A documentation builder"""
1259 def __init__(self, name, directories=['.'], excludes=[]):
1261 self.directories = directories
1262 self.excludes = excludes + ignored_files.keys()
1268 print "Project %s : %d headers, %d modules" % (self.name, len(self.headers.keys()), len(self.modules.keys()))
1271 def scanHeaders(self):
1272 for header in self.headers.keys():
1273 parser = CParser(header)
1274 idx = parser.parse()
1275 self.headers[header] = idx;
1278 def scanModules(self):
1279 for module in self.modules.keys():
1280 parser = CParser(module)
1281 idx = parser.parse()
1283 self.modules[module] = idx
1284 self.idx.merge_public(idx)
1287 for directory in self.directories:
1288 files = glob.glob(directory + "/*.c")
1291 for excl in self.excludes:
1292 if string.find(file, excl) != -1:
1296 self.modules[file] = None;
1297 files = glob.glob(directory + "/*.h")
1300 for excl in self.excludes:
1301 if string.find(file, excl) != -1:
1305 self.headers[file] = None;
1309 def modulename_file(self, file):
1310 module = os.path.basename(file)
1311 if module[-2:] == '.h':
1312 module = module[:-2]
1315 def serialize_enum(self, output, name):
1316 id = self.idx.enums[name]
1317 output.write(" <enum name='%s' file='%s'" % (name,
1318 self.modulename_file(id.module)))
1321 if info[0] != None and info[0] != '':
1322 output.write(" value='%s'" % info[0]);
1323 if info[2] != None and info[2] != '':
1324 output.write(" type='%s'" % info[2]);
1325 if info[1] != None and info[1] != '':
1326 output.write(" info='%s'" % escape(info[1]));
1327 output.write("/>\n")
1329 def serialize_macro(self, output, name):
1330 id = self.idx.macros[name]
1331 output.write(" <macro name='%s' file='%s'>\n" % (name,
1332 self.modulename_file(id.module)))
1335 (args, desc) = id.info
1336 if desc != None and desc != "":
1337 output.write(" <info>%s</info>\n" % (escape(desc)))
1340 if desc != None and desc != "":
1341 output.write(" <arg name='%s' info='%s'/>\n" % (
1342 name, escape(desc)))
1344 output.write(" <arg name='%s'/>\n" % (name))
1347 output.write(" </macro>\n")
1349 def serialize_typedef(self, output, name):
1350 id = self.idx.typedefs[name]
1351 if id.info[0:7] == 'struct ':
1352 output.write(" <struct name='%s' file='%s' type='%s'" % (
1353 name, self.modulename_file(id.module), id.info))
1355 if self.idx.structs.has_key(name) and ( \
1356 type(self.idx.structs[name].info) == type(()) or
1357 type(self.idx.structs[name].info) == type([])):
1358 output.write(">\n");
1360 for field in self.idx.structs[name].info:
1366 output.write(" <field name='%s' type='%s' info='%s'/>\n" % (field[1] , field[0], desc))
1368 print "Failed to serialize struct %s" % (name)
1369 output.write(" </struct>\n")
1371 output.write("/>\n");
1373 output.write(" <typedef name='%s' file='%s' type='%s'/>\n" % (
1374 name, self.modulename_file(id.module), id.info))
1376 def serialize_variable(self, output, name):
1377 id = self.idx.variables[name]
1379 output.write(" <variable name='%s' file='%s' type='%s'/>\n" % (
1380 name, self.modulename_file(id.module), id.info))
1382 output.write(" <variable name='%s' file='%s'/>\n" % (
1383 name, self.modulename_file(id.module)))
1385 def serialize_function(self, output, name):
1386 id = self.idx.functions[name]
1387 output.write(" <%s name='%s' file='%s'>\n" % (id.type, name,
1388 self.modulename_file(id.module)))
1390 (ret, params, desc) = id.info
1391 output.write(" <info>%s</info>\n" % (escape(desc)))
1393 if ret[0] == "void":
1394 output.write(" <return type='void'/>\n")
1396 output.write(" <return type='%s' info='%s'/>\n" % (
1397 ret[0], escape(ret[1])))
1398 for param in params:
1399 if param[0] == 'void':
1401 if param[2] == None:
1402 output.write(" <arg name='%s' type='%s' info=''/>\n" % (param[1], param[0]))
1404 output.write(" <arg name='%s' type='%s' info='%s'/>\n" % (param[1], param[0], escape(param[2])))
1406 print "Failed to save function %s info: " % name, `id.info`
1407 output.write(" </%s>\n" % (id.type))
1409 def serialize_exports(self, output, file):
1410 module = self.modulename_file(file)
1411 output.write(" <file name='%s'>\n" % (module))
1412 dict = self.headers[file]
1413 ids = dict.functions.keys() + dict.variables.keys() + \
1414 dict.macros.keys() + dict.typedefs.keys() + \
1415 dict.structs.keys() + dict.enums.keys()
1418 output.write(" <exports symbol='%s'/>\n" % (id))
1419 output.write(" </file>\n")
1422 def serialize(self, filename = None):
1423 if filename == None:
1424 filename = "%s-api.xml" % self.name
1425 print "Saving XML description %s" % (filename)
1426 output = open(filename, "w")
1427 output.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
1428 output.write("<api name='%s'>\n" % self.name)
1429 output.write(" <files>\n")
1430 for file in self.headers.keys():
1431 self.serialize_exports(output, file)
1432 output.write(" </files>\n")
1433 output.write(" <symbols>\n")
1434 macros = self.idx.macros.keys()
1436 for macro in macros:
1437 self.serialize_macro(output, macro)
1438 enums = self.idx.enums.keys()
1441 self.serialize_enum(output, enum)
1442 typedefs = self.idx.typedefs.keys()
1444 for typedef in typedefs:
1445 self.serialize_typedef(output, typedef)
1446 variables = self.idx.variables.keys()
1448 for variable in variables:
1449 self.serialize_variable(output, variable)
1450 functions = self.idx.functions.keys()
1452 for function in functions:
1453 self.serialize_function(output, function)
1454 output.write(" </symbols>\n")
1455 output.write("</api>\n")
1461 if glob.glob("../parser.c") != [] :
1462 print "Rebuilding API description for libxml2"
1463 builder = docBuilder("libxml2", ["..", "../include/libxml"],
1464 ["xmlwin32version.h", "tst.c",
1465 "schemasInternals.h", "xmlschemas" ])
1466 elif glob.glob("../libxslt/transform.c") != [] :
1467 print "Rebuilding API description for libxslt"
1468 builder = docBuilder("libxslt", ["../libxslt"],
1469 ["win32config.h", "libxslt.h", "tst.c"])
1471 print "rebuild() failed, unable to guess the module"
1476 if glob.glob("../libexslt/exslt.c") != [] :
1477 extra = docBuilder("libexslt", ["../libexslt"], ["libexslt.h"])
1484 # for debugging the parser
1486 def parse(filename):
1487 parser = CParser(filename)
1488 idx = parser.parse()
1491 if __name__ == "__main__":