blob: 2d67206d8bfc9f5a4cbc078df1fb7cb868059d22 [file] [log] [blame]
Dan Talaycof75360a2010-02-05 22:22:54 -08001"""This module parse and store a C/C++ header file.
2
3Date June 2009
4Created by ykk
5"""
6import re
7from config import *
8
9class textfile:
10 """Class to handle text file.
11
12 Date June 2009
13 Created by ykk
14 """
15 def __init__(self, filename):
16 """Initialize filename with no content.
17 """
18 ##Filename
19 if (isinstance(filename, str)):
20 self.filename = []
21 self.filename.append(filename)
22 else:
23 self.filename = filename
24 ##Content
25 self.content = []
26
27 def read(self):
28 """Read file
29 """
30 for filename in self.filename:
31 fileRef = open(filename, "r")
32 for line in fileRef:
33 self.content.append(line)
34 fileRef.close()
35
36class ctype:
37 """Class to represent types in C
38 """
39 def __init__(self,typename, name=None, expanded=False):
40 """Initialize
41 """
42 ##Name
43 self.name = name
44 ##Type of primitive
45 self.typename = typename
46 ##Expanded
47 self.expanded = expanded
48
49 def expand(self, cheader):
50 """Expand type if applicable
51 """
52 raise NotImplementedError()
53
54 def get_names(self):
55 """Return name of variables
56 """
57 raise NotImplementedError()
58
59class cprimitive(ctype):
60 """Class to represent C primitive
61
62 Date October 2009
63 Created by ykk
64 """
65 def __init__(self,typename, name=None):
66 """Initialize and store primitive
67 """
68 ctype.__init__(self, typename, name, True)
69
70 def __str__(self):
71 """Return string representation
72 """
73 if (self.name == None):
74 return self.typename
75 else:
76 return self.typename+" "+str(self.name)
77
78 def expand(self, cheader):
79 """Expand type if applicable
80 """
81 pass
82
83 def get_names(self):
84 """Return name of variables
85 """
86 namelist = []
87 namelist.append(self.name)
88 return namelist
89
90class cstruct(ctype):
91 """Class to represent C struct
92
93 Date October 2009
94 Created by ykk
95 """
96 def __init__(self, typename, name=None):
97 """Initialize struct
98 """
99 ctype.__init__(self, typename, name)
100 ##List of members in struct
101 self.members = []
102
103 def __str__(self):
104 """Return string representation
105 """
106 string = "struct "+self.typename
107 if (self.name != None):
108 string += " "+self.name
109 if (len(self.members) == 0):
110 return string
111 #Add members
112 string +=" {\n"
113 for member in self.members:
114 string += "\t"+str(member)
115 if (not isinstance(member, cstruct)):
116 string += ";"
117 string += "\n"
118 string +="};"
119 return string
120
121 def expand(self, cheader):
122 """Expand struct
123 """
124 self.expanded = True
125 #Expanded each member
126 for member in self.members:
127 if (isinstance(member, cstruct) and
128 (not member.expanded)):
129 try:
130 if (not cheader.structs[member.typename].expanded):
131 cheader.structs[member.typename].expand(cheader)
132 member.members=cheader.structs[member.typename].members[:]
133 member.expanded = True
134 except KeyError:
135 self.expanded=False
136 else:
137 member.expand(cheader)
138
139 def get_names(self):
140 """Return name of variables
141 """
142 namelist = []
143 for member in self.members:
144 if (isinstance(member, cstruct)):
145 tmplist = member.get_names()
146 for item in tmplist:
147 namelist.append(member.name+"."+item)
148 else:
149 namelist.extend(member.get_names())
150 return namelist
151
152
153class carray(ctype):
154 """Class to represent C array
155
156 Date October 2009
157 Created by ykk
158 """
159 def __init__(self, typename, name, isPrimitive, size):
160 """Initialize array of object.
161 """
162 ctype.__init__(self, typename, name,
163 (isinstance(size, int) and isPrimitive))
164 ##Object reference
165 if (isPrimitive):
166 self.object = cprimitive(typename, name)
167 else:
168 self.object = cstruct(typename, name)
169 ##Size of array
170 self.size = size
171
172 def __str__(self):
173 """Return string representation
174 """
175 return str(self.object)+"["+str(self.size)+"]"
176
177 def expand(self, cheader):
178 """Expand array
179 """
180 self.expanded = True
181 if (not self.object.expanded):
182 if (isinstance(self.object, cstruct)):
183 cheader.structs[self.object.typename].expand(cheader)
184 self.object.members=cheader.structs[self.object.typename].members[:]
185 else:
186 self.object.expand(cheader)
187
188 if (not isinstance(self.size, int)):
189 val = cheader.get_value(self.size)
190 if (val == None):
191 self.expanded = False
192 else:
193 try:
194 self.size = int(val)
195 except ValueError:
196 self.size = val
197 self.expanded = False
198
199 def get_names(self):
200 """Return name of variables
201 """
202 namelist = []
203 for i in range(0,self.size):
204 namelist.append(self.object.name)
205 return namelist
206
207class ctype_parser:
208 """Class to check c types
209
210 Date October 2009
211 Created by ykk
212 """
213 def __init__(self):
214 """Initialize
215 """
216 self.CPrimitives = ["char","signed char","unsigned char",
217 "short","unsigned short",
218 "int","unsigned int",
219 "long","unsigned long",
220 "long long","unsigned long long",
221 "float","double",
222 "uint8_t","uint16_t","uint32_t","uint64_t"]
223
224 def is_primitive(self,type):
225 """Check type given is primitive.
226
227 Return true if valid, and false otherwise
228 """
229 if (type in self.CPrimitives):
230 return True
231 else:
232 return False
233
234 def is_array(self, string):
235 """Check if string declares an array
236 """
237 parts=string.strip().split()
238 if (len(parts) <= 1):
239 return False
240 else:
241 pattern = re.compile("\[.*?\]", re.MULTILINE)
242 values = pattern.findall(string)
243 if (len(values) == 1):
244 return True
245 else:
246 return False
247
248 def parse_array(self, string):
249 """Parse array from string.
250 Return occurrence and name.
251 """
252 pattern = re.compile("\[.*?\]", re.MULTILINE)
253 namepattern = re.compile(".*?\[", re.MULTILINE)
254 values = pattern.findall(string)
255 if (len(values) != 1):
256 return (1,string)
257 else:
258 val = values[0][1:-1]
259 try:
260 sizeval = int(val)
261 except ValueError:
262 if (val==""):
263 sizeval = 0
264 else:
265 sizeval = val
266 return (sizeval,
267 namepattern.findall(string)[0].strip()[0:-1])
268
269 def parse_type(self, string):
270 """Parse string and return cstruct or cprimitive.
271 Else return None
272 """
273 parts=string.strip().split()
274 if (len(parts) >= 2):
275 if (parts[0].strip() == "struct"):
276 typename = " ".join(parts[1:-1])
277 else:
278 typename = " ".join(parts[:-1])
279 (size, name) = self.parse_array(parts[-1])
280 if IGNORE_ZERO_ARRAYS and size == 0:
281 return None
282 #Create appropriate type
283 if (size != 1):
284 #Array
285 return carray(typename, name,
286 self.is_primitive(typename),size)
287 else:
288 #Not array
Rich Laneb73808c2013-03-11 15:22:23 -0700289 if typename == "ofp_header":
290 return "ofp_header"
Dan Talaycof75360a2010-02-05 22:22:54 -0800291 if (self.is_primitive(typename)):
292 return cprimitive(typename, name)
293 else:
294 return cstruct(typename, name)
295 else:
296 return None
297
298class cheaderfile(textfile):
299 """Class to handle C header file.
300
301 Date June 2009
302 Created by ykk
303 """
304 def __init__(self, filename):
305 """Initialize filename and read from file
306 """
307 textfile.__init__(self,filename)
308 self.read()
309 self.__remove_comments()
310 ##Dictionary of macros
311 self.macros = {}
312 self.__get_macros()
313 ##Dictionary of enumerations
314 self.enums = {}
315 self.enum_values = {}
316 self.__get_enum()
317 self.__get_enum_values()
318 ##Dictionary of structs
319 self.structs = {}
320 self.__get_struct()
321
322 def get_enum_name(self, enum, value):
323 """Return name of variable in enum
324 """
325 for e in self.enums[enum]:
326 if (self.enum_values[e] == value):
327 return e
328
329 def eval_value(self, value):
330 """Evaluate value string
331 """
332 try:
333 return eval(value, self.enum_values)
334 except:
335 return value.strip()
336
337 def get_value(self, name):
338 """Get value for variable name,
339 searching through enum and macros.
340 Else return None
341 """
342 try:
343 return self.enum_values[name]
344 except KeyError:
345 try:
346 return self.macros[name]
347 except KeyError:
348 return None
349
350 def __remove_comments(self):
351 """Remove all comments
352 """
353 fileStr = "".join(self.content)
354 pattern = re.compile("\\\.*?\n", re.MULTILINE)
355 fileStr = pattern.sub("",fileStr)
356 pattern = re.compile(r"/\*.*?\*/", re.MULTILINE|re.DOTALL)
357 fileStr = pattern.sub("",fileStr)
358 pattern = re.compile("//.*$", re.MULTILINE)
359 fileStr = pattern.sub("",fileStr)
360 self.content = fileStr.split('\n')
361
362 def __get_struct(self):
363 """Get all structs
364 """
365 typeparser = ctype_parser()
366 fileStr = "".join(self.content)
367 #Remove attribute
368 attrpattern = re.compile("} __attribute__ \(\((.+?)\)\);", re.MULTILINE)
369 attrmatches = attrpattern.findall(fileStr)
370 for amatch in attrmatches:
371 fileStr=fileStr.replace(" __attribute__ (("+amatch+"));",";")
372 #Find all structs
373 pattern = re.compile("struct[\w\s]*?{.*?};", re.MULTILINE)
374 matches = pattern.findall(fileStr)
375 #Process each struct
376 namepattern = re.compile("struct(.+?)[ {]", re.MULTILINE)
377 pattern = re.compile("{(.+?)};", re.MULTILINE)
378 for match in matches:
379 structname = namepattern.findall(match)[0].strip()
380 if (len(structname) != 0):
381 values = pattern.findall(match)[0].strip().split(";")
382 cstru = cstruct(structname)
383 for val in values:
384 presult = typeparser.parse_type(val)
Rich Laneb73808c2013-03-11 15:22:23 -0700385 if presult == "ofp_header":
386 cstru.members.append(cprimitive("uint8_t", "version"))
387 cstru.members.append(cprimitive("uint8_t", "type"))
388 cstru.members.append(cprimitive("uint16_t", "length"))
389 cstru.members.append(cprimitive("uint32_t", "xid"))
390 elif (presult != None):
Dan Talaycof75360a2010-02-05 22:22:54 -0800391 cstru.members.append(presult)
392 self.structs[structname] = cstru
393 #Expand all structs
394 for (structname, struct) in self.structs.items():
395 struct.expand(self)
396
397 def __get_enum(self):
398 """Get all enumeration
399 """
400 fileStr = "".join(self.content)
401 #Find all enumerations
402 pattern = re.compile("enum[\w\s]*?{.*?}", re.MULTILINE)
403 matches = pattern.findall(fileStr)
404 #Process each enumeration
405 namepattern = re.compile("enum(.+?){", re.MULTILINE)
406 pattern = re.compile("{(.+?)}", re.MULTILINE)
407 for match in matches:
408 values = pattern.findall(match)[0].strip().split(",")
409 #Process each value in enumeration
410 enumList = []
411 value = 0
412 for val in values:
413 if not (val.strip() == ""):
414 valList=val.strip().split("=")
415 enumList.append(valList[0].strip())
416 if (len(valList) == 1):
417 self.enum_values[valList[0].strip()] = value
418 value += 1
419 else:
420 self.enum_values[valList[0].strip()] = self.eval_value(valList[1].strip())
421 self.enums[namepattern.findall(match)[0].strip()] = enumList
422
423 def __get_enum_values(self):
424 """Patch unresolved enum values
425 """
426 for name,enumval in self.enum_values.items():
427 if isinstance(enumval,str):
428 self.enum_values[name] = self.eval_value(enumval)
429
430 def __get_macros(self):
431 """Extract macros
432 """
433 for line in self.content:
434 if (line[0:8] == "#define "):
435 lineList = line[8:].split()
436 if (len(lineList) >= 2):
437 self.macros[lineList[0]] = self.eval_value("".join(lineList[1:]))
438 else:
439 self.macros[lineList[0]] = ""