blob: f06904b5bf58586a826870ff36890d0c2427059a [file] [log] [blame]
Rich Lanea06d0c32013-03-25 08:52:03 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
28##
29# @brief Utilities related to parsing C files
30#
31import re
32import sys
33import os
34import of_g
35
36def type_dec_to_count_base(m_type):
37 """
38 Resolve a type declaration like uint8_t[4] to a count (4) and base_type
39 (uint8_t)
40
41 @param m_type The string type declaration to process
42 """
43 count = 1
44 chk_ar = m_type.split('[')
45 if len(chk_ar) > 1:
46 count_str = chk_ar[1].split(']')[0]
47 if count_str in of_g.ofp_constants:
48 count = of_g.ofp_constants[count_str]
49 else:
50 count = int(count_str)
51 base_type = chk_ar[0]
52 else:
53 base_type = m_type
54 return count, base_type
55
56def comment_remover(text):
57 """
58 Remove C and C++ comments from text
59 @param text Possibly multiline string of C code.
60
61 http://stackoverflow.com/questions/241327/python-snippet-to-remove-c-and-c-comments
62 """
63
64 def replacer(match):
65 s = match.group(0)
66 if s.startswith('/'):
67 return ""
68 else:
69 return s
70 pattern = re.compile(
71 r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
72 re.DOTALL | re.MULTILINE
73 )
74 return re.sub(pattern, replacer, text)
75
76
77def clean_up_input(text):
78 text = comment_remover(text)
79 text_lines = text.splitlines()
80 all_lines = []
81 for line in text_lines:
82 line = re.sub("\t", " ", line) # get rid of tabs
83 line = re.sub(" +$", "", line) # Strip trailing blanks
84 if len(line):
85 all_lines.append(line)
86 text = "\n".join(all_lines)
87 return text
88
89def extract_structs(contents):
90 """
91 Extract the structures from raw C code input
92 @param contents The text of the original C code
93 """
94 contents = clean_up_input(contents)
95 struct_list = re.findall("struct .* \{[^}]+\};", contents)
96 return struct_list
97
98def extract_enums(contents):
99 """
100 Extract the enums from raw C code input
101 @param contents The text of the original C code
102 @return An array where each entry is an (unparsed) enum instance
103 """
104 contents = clean_up_input(contents)
105 enum_list = re.findall("enum .* \{[^}]+\};", contents)
106 return enum_list
107
108def extract_enum_vals(enum):
109 """
110 From a C enum, return a pair (name, values)
111 @param enum The C syntax enumeration
112 @returns (name, values), see below
113
114 name is the enum name
115 values is a list pairs (<ident>, <value>) where ident is the
116 identifier and value is the associated value.
117
118 The values are integers when possible, otherwise strings
119 """
120
121 rv_list = []
122 name = re.search("enum +(\w+)", enum).group(1)
123 lines = " ".join(enum.split("\n"))
124 body = re.search("\{(.+)\}", lines).group(1)
125 entries = body.split(",")
126 previous_value = -1
127 for m in entries:
128 if re.match(" *$", m): # Empty line
129 continue
130 # Parse with = first
131 search_obj = re.match(" +(\w+) *= *(.*) *", m)
132 if search_obj: # Okay, had =
133 e_name = search_obj.group(1)
134 e_value = search_obj.group(2)
135 else: # No equals
136 search_obj = re.match(" +(\w+)", m)
137 if not search_obj:
138 sys.stderr.write("\nError extracting enum for %s, member %s\n"
139 % (name, m))
140 sys.exit(1)
141 e_name = search_obj.group(1)
142 e_value = previous_value + 1
143 rv_list.append([e_name, e_value])
144
145 if type(e_value) is type(0):
146 previous_value = e_value
147 else:
148 try:
149 previous_value = int(e_value, 0)
150 except ValueError:
151 pass
152 return (name, rv_list)
153
154def extract_defines(contents):
155 """
156 Returns a list of pairs (<identifier>, <value>) where
157 #define <ident> <value> appears in the file
158 """
159 rv_list = []
160 contents = clean_up_input(contents)
161 define_list = re.findall("\#define +[^ ]+ .*\n", contents, re.M)
162 for entry in define_list:
163 match_obj = re.match("#define +([^ ]+) +(.+)$", entry)
164 rv_list.append([match_obj.group(1),match_obj.group(2)])
165 return rv_list
166