2 # Flexible IDL framework
4 # Copyright IBM, Corp. 2010
7 # Anthony Liguori <aliguori@us.ibm.com>
9 # This work is licensed under the terms of the GNU GPL, version 2. See
10 # the COPYING file in the top-level directory.
13 from spark
import GenericScanner
, GenericParser
15 # Lexical token representation. It really just lets us associate a tag with
16 # the token value for purposes of classification.
18 def __init__(self
, kind
, value
=None):
25 def __cmp__(self
, rhs
):
26 return cmp(self
.kind
, rhs
)
29 return '[%s %s]' % (self
.kind
, self
.value
)
31 # Lexical scanner. It skips whitespace and C99 and C89 comments. It also
32 # skips cpp directives which is somewhat unusual.
34 class IdlScanner(GenericScanner
):
35 keywords
= ['const', 'struct', 'typedef', 'void',
36 '__capacity_is__', '__feature__']
39 GenericScanner
.__init
__(self
)
41 def tokenize(self
, input):
43 GenericScanner
.tokenize(self
, input)
46 def t_whitespace(self
, s
):
50 def t_c89_comment(self
, s
):
51 r
' /\*([^\*]|\n|\*[^\/])*\*/ '
54 def t_c99_comment(self
, s
):
58 def t_cpp_directive(self
, s
):
59 r
' \#(.*?\\\n)*.*?\n '
62 def t_symbol(self
, s
):
63 r
' [A-Za-z_][A-Za-z0-9_]* '
64 if s
in self
.keywords
:
65 self
.rv
.append(Token(s
))
67 self
.rv
.append(Token('symbol', s
))
69 def t_integer(self
, s
):
70 r
' \-?[1-9][0-9]+|0([Xx][0-9a-fA-F]+)? '
71 self
.rv
.append(Token('integer', s
))
79 scanner
= IdlScanner()
80 return scanner
.tokenize(input)
82 # Abstract Syntax Tree node.
84 def __init__(self
, kind
, **kwds
):
88 def __getattr__(self
, key
):
89 if self
.kwds
.has_key(key
):
91 return object.__getattr
__(self
, key
)
94 return '(%s, %s)' % (self
.kind
, self
.kwds
)
96 # Grammar implementation. This is only a subset of C. It does not support
97 # enums or unions. It also only supports single levels of pointers and only
98 # support const at the beginning of a type. It does not support static or the
101 # It's meant to support the type of C you'd find in a typical header file. It
102 # assumes that a CPP pass has not been performed.
103 class IdlParser(GenericParser
):
104 def __init__(self
, start
='statements'):
105 GenericParser
.__init
__(self
, start
)
107 def p_primitive_1(self
, args
):
111 return AST('type', value
=args
[0].value
)
113 def p_primitive_2(self
, args
):
114 ' primitive ::= structure '
117 def p_structure(self
, args
):
119 structure ::= struct symbol
120 structure ::= struct symbol { members }
121 structure ::= struct { members }
122 structure ::= struct { members } __feature__ ( symbol )
125 return AST('struct', name
=args
[1].value
)
127 return AST('struct', name
=None, members
=args
[2])
129 return AST('struct', name
=args
[1].value
, members
=args
[3])
131 return AST('struct', name
=None, members
=args
[2],
132 feature
=args
[6].value
)
134 def p_type_1(self
, args
):
135 ' type ::= const primitive * '
136 return AST('input', base
=args
[1])
138 def p_type_2(self
, args
):
139 ' type ::= primitive * '
140 return AST('output', base
=args
[0])
142 def p_type_3(self
, args
):
143 ' type ::= primitive * * '
144 return AST('output', base
=AST('array', base
=args
[0]))
146 def p_type_4(self
, args
):
147 ' type ::= primitive '
150 def p_type_5(self
, args
):
151 ' type ::= primitive * __capacity_is__ ( symbol ) '
156 def p_arg_1(self
, args
):
157 ' arg ::= type symbol'
158 return AST('arg', type=args
[0], name
=args
[1].value
)
160 def p_arg_2(self
, args
):
161 ' arg ::= type symbol [ symbol ] '
163 type=AST('array', base
=args
[0]),
167 def p_arg_3(self
, args
):
168 ' arg ::= type symbol [ integer ] '
170 type=AST('array', base
=args
[0]),
174 def p_arglist_1(self
, args
):
178 def p_arglist_2(self
, args
):
179 ' arglist ::= arglist , arg '
180 return args
[0] + [args
[2]]
182 def p_argslist_1(self
, args
):
183 ' argslist ::= arglist '
186 def p_argslist_2(self
, args
):
187 ' argslist ::= void '
190 def p_definition_1(self
, args
):
191 ' definition ::= void symbol ( argslist ) '
192 return AST('def', name
=args
[1].value
, params
=args
[3])
194 def p_definition_2(self
, args
):
195 ' definition ::= type symbol ( argslist ) '
196 return AST('def', name
=args
[1].value
, retval
=args
[0], params
=args
[3])
198 def p_members_1(self
, args
):
199 ' members ::= arg ; '
202 def p_members_2(self
, args
):
203 ' members ::= members arg ; '
204 return args
[0] + [args
[1]]
206 def p_type_definition(self
, args
):
207 ' type_definition ::= typedef type symbol '
208 return AST('typedef', alias
=args
[2].value
, base
=args
[1])
210 def p_statement_1(self
, args
):
212 statement ::= type_definition ;
213 statement ::= definition ;
217 def p_statement_2(self
, args
):
218 ' statement ::= structure ; '
219 return [AST('struct_decl', struct
=args
[0])]
221 def p_statements_1(self
, args
):
222 ' statements ::= statement '
225 def p_statements_2(self
, args
):
226 ' statements ::= statements statement '
227 return args
[0] + args
[1]
231 return parser
.parse(tokens
)
233 # Walk the AST tree. Each AST node type has a method that only knows enough
234 # to walk its children. This class should be subclassed to transform the
236 class ASTWalker(object):
240 def default(self
, node
):
242 for key
in node
.kwds
:
243 value
= getattr(node
, key
)
244 if type(value
) in [AST
, list]:
245 kwds
[key
] = self
.walk(value
)
248 return AST(node
.kind
, **kwds
)
250 def walk_node(self
, node
):
251 name
= 'n_%s' % node
.kind
252 if hasattr(self
, name
):
253 fn
= getattr(self
, name
)
256 node
= self
.default(node
)
259 def walk(self
, tree
):
260 if type(tree
) == AST
:
261 return self
.walk_node(tree
)
263 return filter(lambda x
: x
!= None, map(self
.walk_node
, tree
))
265 # Pretty print an AST
266 class PrettyWalker(ASTWalker
):
268 ASTWalker
.__init
__(self
)
270 def print_indent(self
, indent
):
271 for i
in range(indent
):
274 def default(self
, nodes
, indent
=0):
275 if type(nodes
) != list:
279 self
.print_indent(indent
)
280 print '%s:' % node
.kind
281 for key
in node
.kwds
:
282 value
= getattr(node
, key
)
283 if type(value
) == AST
or type(value
) == list:
284 self
.default(value
, indent
+ 1)
286 self
.print_indent(indent
+ 1)
287 print '%s = %s' % (key
, value
)