• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1
2# (C) Copyright IBM Corporation 2005
3# All Rights Reserved.
4#
5# Permission is hereby granted, free of charge, to any person obtaining a
6# copy of this software and associated documentation files (the "Software"),
7# to deal in the Software without restriction, including without limitation
8# on the rights to use, copy, modify, merge, publish, distribute, sub
9# license, and/or sell copies of the Software, and to permit persons to whom
10# the Software is furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice (including the next
13# paragraph) shall be included in all copies or substantial portions of the
14# Software.
15#
16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
19# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22# IN THE SOFTWARE.
23#
24# Authors:
25#    Ian Romanick <idr@us.ibm.com>
26
27from __future__ import print_function
28
29import copy
30
31class type_node(object):
32    def __init__(self):
33        self.pointer = 0  # bool
34        self.const = 0    # bool
35        self.signed = 1   # bool
36        self.integer = 1  # bool
37
38        # If elements is set to non-zero, then field is an array.
39        self.elements = 0
40
41        self.name = None
42        self.size = 0     # type's size in bytes
43        return
44
45
46    def string(self):
47        """Return string representation of this type_node."""
48        s = ""
49
50        if self.pointer:
51            s = "* "
52
53        if self.const:
54            s += "const "
55
56        if not self.pointer:
57            if self.integer:
58                if self.signed:
59                    s += "signed "
60                else:
61                    s += "unsigned "
62
63            if self.name:
64                s += "%s " % (self.name)
65
66        return s
67
68
69class type_table(object):
70    def __init__(self):
71        self.types_by_name = {}
72        return
73
74
75    def add_type(self, type_expr):
76        self.types_by_name[ type_expr.get_base_name() ] = type_expr
77        return
78
79
80    def find_type(self, name):
81        if name in self.types_by_name:
82            return self.types_by_name[ name ]
83        else:
84            return None
85
86
87def create_initial_types():
88    tt = type_table()
89
90    basic_types = [
91            ("char",   1, 1),
92            ("short",  2, 1),
93            ("int",    4, 1),
94            ("long",   4, 1),
95            ("float",  4, 0),
96            ("double", 8, 0),
97            ("enum",   4, 1)
98    ]
99
100    for (type_name, type_size, integer) in basic_types:
101        te = type_expression(None)
102        tn = type_node()
103        tn.name = type_name
104        tn.size = type_size
105        tn.integer = integer
106        te.expr.append(tn)
107        tt.add_type( te )
108
109    type_expression.built_in_types = tt
110    return
111
112
113class type_expression(object):
114    built_in_types = None
115
116    def __init__(self, type_string, extra_types = None):
117        self.expr = []
118
119        if not type_string:
120            return
121
122        self.original_string = type_string
123
124        if not type_expression.built_in_types:
125            raise RuntimeError("create_initial_types must be called before creating type_expression objects.")
126
127        # Replace '*' with ' * ' in type_string.  Then, split the string
128        # into tokens, separated by spaces.
129        tokens = type_string.replace("*", " * ").split()
130
131        const = 0
132        t = None
133        signed = 0
134        unsigned = 0
135
136        for i in tokens:
137            if i == "const":
138                if t and t.pointer:
139                    t.const = 1
140                else:
141                    const = 1
142            elif i == "signed":
143                signed = 1
144            elif i == "unsigned":
145                unsigned = 1
146            elif i == "*":
147                # This is a quirky special-case because of the
148                # way the C works for types.  If 'unsigned' is
149                # specified all by itself, it is treated the
150                # same as "unsigned int".
151
152                if unsigned:
153                    self.set_base_type( "int", signed, unsigned, const, extra_types )
154                    const = 0
155                    signed = 0
156                    unsigned = 0
157
158                if not self.expr:
159                    raise RuntimeError("Invalid type expression (dangling pointer)")
160
161                if signed:
162                    raise RuntimeError("Invalid type expression (signed / unsigned applied to pointer)")
163
164                t = type_node()
165                t.pointer = 1
166                self.expr.append( t )
167            else:
168                if self.expr:
169                    raise RuntimeError('Invalid type expression (garbage after pointer qualifier -> "%s")' % (self.original_string))
170
171                self.set_base_type( i, signed, unsigned, const, extra_types )
172                const = 0
173                signed = 0
174                unsigned = 0
175
176            if signed and unsigned:
177                raise RuntimeError("Invalid type expression (both signed and unsigned specified)")
178
179
180        if const:
181            raise RuntimeError("Invalid type expression (dangling const)")
182
183        if unsigned:
184            raise RuntimeError("Invalid type expression (dangling signed)")
185
186        if signed:
187            raise RuntimeError("Invalid type expression (dangling unsigned)")
188
189        return
190
191
192    def set_base_type(self, type_name, signed, unsigned, const, extra_types):
193        te = type_expression.built_in_types.find_type( type_name )
194        if not te:
195            te = extra_types.find_type( type_name )
196
197        if not te:
198            raise RuntimeError('Unknown base type "%s".' % (type_name))
199
200        self.expr = copy.deepcopy(te.expr)
201
202        t = self.expr[ len(self.expr) - 1 ]
203        t.const = const
204        if signed:
205            t.signed = 1
206        elif unsigned:
207            t.signed = 0
208
209
210    def set_base_type_node(self, tn):
211        self.expr = [tn]
212        return
213
214
215    def set_elements(self, count):
216        tn = self.expr[0]
217
218        tn.elements = count
219        return
220
221
222    def string(self):
223        s = ""
224        for t in self.expr:
225            s += t.string()
226
227        return s
228
229
230    def get_base_type_node(self):
231        return self.expr[0]
232
233
234    def get_base_name(self):
235        if len(self.expr):
236            return self.expr[0].name
237        else:
238            return None
239
240
241    def get_element_size(self):
242        tn = self.expr[0]
243
244        if tn.elements:
245            return tn.elements * tn.size
246        else:
247            return tn.size
248
249
250    def get_element_count(self):
251        tn = self.expr[0]
252        return tn.elements
253
254
255    def get_stack_size(self):
256        tn = self.expr[ -1 ]
257
258        if tn.elements or tn.pointer:
259            return 4
260        elif not tn.integer:
261            return tn.size
262        else:
263            return 4
264
265
266    def is_pointer(self):
267        tn = self.expr[ -1 ]
268        return tn.pointer
269
270
271    def format_string(self):
272        tn = self.expr[ -1 ]
273        if tn.pointer:
274            return "%p"
275        elif not tn.integer:
276            return "%f"
277        else:
278            return "%d"
279
280
281
282if __name__ == '__main__':
283
284    types_to_try = [ "int", "int *", "const int *", "int * const", "const int * const", \
285                     "unsigned * const *", \
286                     "float", "const double", "double * const"]
287
288    create_initial_types()
289
290    for t in types_to_try:
291        print('Trying "%s"...' % (t))
292        te = type_expression( t )
293        print('Got "%s" (%u, %u).' % (te.string(), te.get_stack_size(), te.get_element_size()))
294