]> git.cworth.org Git - apitrace/blob - apigen/cdecl.py
0ef10d34431e90da84f255b02fc369317b99b4bc
[apitrace] / apigen / cdecl.py
1 #!/usr/bin/env python
2 ##########################################################################
3 #
4 # Copyright 2011 Jose Fonseca
5 # All Rights Reserved.
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to deal
9 # in the Software without restriction, including without limitation the rights
10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 # copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 # THE SOFTWARE.
24 #
25 ##########################################################################/
26
27
28 '''Script to parse C declarations and spew API definitions.
29 '''
30
31
32 import sys
33 import re
34 import optparse
35
36
37 class Parser:
38
39     token_re = re.compile(r'(\w+|\s+|.)')
40
41     multi_comment_re = re.compile(r'/\*.*?\*/', flags = re.DOTALL)
42     single_comment_re = re.compile(r'//.*',)
43
44     def __init__(self):
45         self.tokens = []
46
47     def has_side_effects(self, name):
48         return True
49
50     def parse(self, s):
51         s = self.multi_comment_re.sub('', s)
52         s = self.single_comment_re.sub('', s)
53         self.tokens = self.token_re.split(s)
54         self.tokens = [token for token in self.tokens if self.filter_token(token)]
55
56         while self.tokens:
57             #print self.tokens[0:10]
58             self.parse_declaration()
59
60     def filter_token(self, token):
61         if not token or token.isspace():
62             return False
63         if token.startswith('AVAILABLE_') or token.startswith('DEPRECATED_'):
64             return False
65         if token in ['FAR']:
66             return False
67         return True
68
69     def parse_declaration(self):
70         if self.tokens[0] == 'mask':
71             self.parse_value('mask', 'Flags')
72         elif self.tokens[0] == 'value':
73             self.parse_value('value', 'FakeEnum')
74         elif self.tokens[0] == 'interface':
75             self.parse_interface()
76         else:
77             self.parse_prototype()
78
79     def parse_value(self, ref_token, constructor):
80         self.match(ref_token)
81         type = self.tokens.pop(0)
82         name = self.tokens.pop(0)
83         self.match('{')
84
85         print '%s = %s(%s, [' % (name, constructor, type)
86
87         while self.tokens[0] != '}':
88             self.match('#')
89             self.match('define')
90             name = self.tokens.pop(0)
91             value = self.tokens.pop(0)
92             tag = self.parse_tag()
93             #print '    "%s",\t# %s' % (name, value) 
94             print '    "%s",' % (name,) 
95         self.match('}')
96         self.match(';')
97
98         print '])'
99         print
100
101     def parse_interface(self):
102         self.match('interface')
103         name = self.tokens.pop(0)
104         self.match(':')
105         base = self.tokens.pop(0)
106         self.match('{')
107
108         print '%s = Interface("%s", %s)' % (name, name, base)
109         print '%s.methods += [' % (name,)
110
111         while self.tokens[0] != '}':
112             self.parse_prototype('Method')
113         self.match('}')
114         self.match(';')
115
116         print ']'
117         print
118
119     def parse_prototype(self, creator = 'Function'):
120         if self.tokens[0] == 'extern':
121             self.tokens.pop(0)
122
123         ret = self.parse_type()
124
125         name = self.tokens.pop(0)
126         extra = ''
127         if not self.has_side_effects(name):
128             extra += ', sideeffects=False'
129         name = name
130
131         self.match('(')
132         args = []
133         if self.tokens[0] == 'void' and self.tokens[1] == ')':
134             self.tokens.pop(0)
135         while self.tokens[0] != ')':
136             arg = self.parse_arg()
137             args.append(arg)
138             if self.tokens[0] == ',':
139                 self.tokens.pop(0)
140         self.tokens.pop(0) == ')'
141         
142         if self.tokens and self.tokens[0] == ';':
143             self.tokens.pop(0)
144
145         print '    %s(%s, "%s", [%s]%s),' % (creator, ret, name, ', '.join(args), extra)
146
147     def parse_arg(self):
148         tag = self.parse_tag()
149
150         type = self.parse_type()
151         name = self.tokens.pop(0)
152
153         arg = '(%s, "%s")' % (type, name)
154         if tag == 'out':
155             arg = 'Out' + arg
156         return arg
157
158     def parse_tag(self):
159         tag = None
160         if self.tokens[0] == '[':
161             self.tokens.pop(0)
162             tag = self.tokens.pop(0)
163             self.match(']')
164         return tag
165
166     int_tokens = ('unsigned', 'signed', 'int', 'long', 'short', 'char')
167
168     type_table = {
169         'float':    'Float',
170         'double':   'Double',
171         'int8_t':   'Int8',
172         'uint8_t':  'UInt8',
173         'int16_t':  'Int16',
174         'uint16_t': 'UInt16',
175         'int32_t':  'Int32',
176         'uint32_t': 'UInt32',
177         'int64_t' : 'Int64',
178         'uint64_t': 'UInt64',
179     }
180
181     def parse_type(self):
182         token = self.tokens.pop(0)
183         if token == 'const':
184             return 'Const(%s)' % self.parse_type()
185         if token == 'void':
186             type = 'Void'
187         elif token in self.int_tokens:
188             unsigned = False
189             signed = False
190             long = 0
191             short = 0
192             char = False
193             while token in self.int_tokens:
194                 if token == 'unsigned':
195                     unsigned = True
196                 if token == 'signed':
197                     signed = True
198                 if token == 'long':
199                     long += 1
200                 if token == 'short':
201                     short += 1
202                 if token == 'char':
203                     char = False
204                 if self.tokens[0] in self.int_tokens:
205                     token = self.tokens.pop(0)
206                 else:
207                     token = None
208             if char:
209                 type = 'Char'
210                 if signed:
211                     type = 'S' + type
212             elif short:
213                 type = 'Short'
214             elif long:
215                 type = 'Long' * long
216             else:
217                 type = 'Int'
218             if unsigned:
219                 type = 'U' + type
220         else:
221             type = self.type_table.get(token, token)
222         while self.tokens[0] == '*':
223             type = 'OpaquePointer(%s)' % type
224             self.tokens.pop(0)
225         return type
226
227     def match(self, ref_token):
228         if not self.tokens:
229             raise Exception('unexpected EOF')
230         token = self.tokens.pop(0)
231         if token != ref_token:
232             raise Exception('token mismatch', token, ref_token)
233
234
235         
236
237
238 def main():
239     parser = Parser()
240     for arg in sys.argv[1:]:
241         parser.parse(open(arg, 'rt').read())
242     
243
244 if __name__ == '__main__':
245     main()