pycparser 2.22__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pycparser/__init__.py ADDED
@@ -0,0 +1,93 @@
1
+ #-----------------------------------------------------------------
2
+ # pycparser: __init__.py
3
+ #
4
+ # This package file exports some convenience functions for
5
+ # interacting with pycparser
6
+ #
7
+ # Eli Bendersky [https://eli.thegreenplace.net/]
8
+ # License: BSD
9
+ #-----------------------------------------------------------------
10
+ __all__ = ['c_lexer', 'c_parser', 'c_ast']
11
+ __version__ = '2.22'
12
+
13
+ import io
14
+ from subprocess import check_output
15
+ from .c_parser import CParser
16
+
17
+
18
+ def preprocess_file(filename, cpp_path='cpp', cpp_args=''):
19
+ """ Preprocess a file using cpp.
20
+
21
+ filename:
22
+ Name of the file you want to preprocess.
23
+
24
+ cpp_path:
25
+ cpp_args:
26
+ Refer to the documentation of parse_file for the meaning of these
27
+ arguments.
28
+
29
+ When successful, returns the preprocessed file's contents.
30
+ Errors from cpp will be printed out.
31
+ """
32
+ path_list = [cpp_path]
33
+ if isinstance(cpp_args, list):
34
+ path_list += cpp_args
35
+ elif cpp_args != '':
36
+ path_list += [cpp_args]
37
+ path_list += [filename]
38
+
39
+ try:
40
+ # Note the use of universal_newlines to treat all newlines
41
+ # as \n for Python's purpose
42
+ text = check_output(path_list, universal_newlines=True)
43
+ except OSError as e:
44
+ raise RuntimeError("Unable to invoke 'cpp'. " +
45
+ 'Make sure its path was passed correctly\n' +
46
+ ('Original error: %s' % e))
47
+
48
+ return text
49
+
50
+
51
+ def parse_file(filename, use_cpp=False, cpp_path='cpp', cpp_args='',
52
+ parser=None, encoding=None):
53
+ """ Parse a C file using pycparser.
54
+
55
+ filename:
56
+ Name of the file you want to parse.
57
+
58
+ use_cpp:
59
+ Set to True if you want to execute the C pre-processor
60
+ on the file prior to parsing it.
61
+
62
+ cpp_path:
63
+ If use_cpp is True, this is the path to 'cpp' on your
64
+ system. If no path is provided, it attempts to just
65
+ execute 'cpp', so it must be in your PATH.
66
+
67
+ cpp_args:
68
+ If use_cpp is True, set this to the command line arguments strings
69
+ to cpp. Be careful with quotes - it's best to pass a raw string
70
+ (r'') here. For example:
71
+ r'-I../utils/fake_libc_include'
72
+ If several arguments are required, pass a list of strings.
73
+
74
+ encoding:
75
+ Encoding to use for the file to parse
76
+
77
+ parser:
78
+ Optional parser object to be used instead of the default CParser
79
+
80
+ When successful, an AST is returned. ParseError can be
81
+ thrown if the file doesn't parse successfully.
82
+
83
+ Errors from cpp will be printed out.
84
+ """
85
+ if use_cpp:
86
+ text = preprocess_file(filename, cpp_path, cpp_args)
87
+ else:
88
+ with io.open(filename, encoding=encoding) as f:
89
+ text = f.read()
90
+
91
+ if parser is None:
92
+ parser = CParser()
93
+ return parser.parse(text, filename)
pycparser/_ast_gen.py ADDED
@@ -0,0 +1,336 @@
1
+ #-----------------------------------------------------------------
2
+ # _ast_gen.py
3
+ #
4
+ # Generates the AST Node classes from a specification given in
5
+ # a configuration file
6
+ #
7
+ # The design of this module was inspired by astgen.py from the
8
+ # Python 2.5 code-base.
9
+ #
10
+ # Eli Bendersky [https://eli.thegreenplace.net/]
11
+ # License: BSD
12
+ #-----------------------------------------------------------------
13
+ from string import Template
14
+
15
+
16
+ class ASTCodeGenerator(object):
17
+ def __init__(self, cfg_filename='_c_ast.cfg'):
18
+ """ Initialize the code generator from a configuration
19
+ file.
20
+ """
21
+ self.cfg_filename = cfg_filename
22
+ self.node_cfg = [NodeCfg(name, contents)
23
+ for (name, contents) in self.parse_cfgfile(cfg_filename)]
24
+
25
+ def generate(self, file=None):
26
+ """ Generates the code into file, an open file buffer.
27
+ """
28
+ src = Template(_PROLOGUE_COMMENT).substitute(
29
+ cfg_filename=self.cfg_filename)
30
+
31
+ src += _PROLOGUE_CODE
32
+ for node_cfg in self.node_cfg:
33
+ src += node_cfg.generate_source() + '\n\n'
34
+
35
+ file.write(src)
36
+
37
+ def parse_cfgfile(self, filename):
38
+ """ Parse the configuration file and yield pairs of
39
+ (name, contents) for each node.
40
+ """
41
+ with open(filename, "r") as f:
42
+ for line in f:
43
+ line = line.strip()
44
+ if not line or line.startswith('#'):
45
+ continue
46
+ colon_i = line.find(':')
47
+ lbracket_i = line.find('[')
48
+ rbracket_i = line.find(']')
49
+ if colon_i < 1 or lbracket_i <= colon_i or rbracket_i <= lbracket_i:
50
+ raise RuntimeError("Invalid line in %s:\n%s\n" % (filename, line))
51
+
52
+ name = line[:colon_i]
53
+ val = line[lbracket_i + 1:rbracket_i]
54
+ vallist = [v.strip() for v in val.split(',')] if val else []
55
+ yield name, vallist
56
+
57
+
58
+ class NodeCfg(object):
59
+ """ Node configuration.
60
+
61
+ name: node name
62
+ contents: a list of contents - attributes and child nodes
63
+ See comment at the top of the configuration file for details.
64
+ """
65
+
66
+ def __init__(self, name, contents):
67
+ self.name = name
68
+ self.all_entries = []
69
+ self.attr = []
70
+ self.child = []
71
+ self.seq_child = []
72
+
73
+ for entry in contents:
74
+ clean_entry = entry.rstrip('*')
75
+ self.all_entries.append(clean_entry)
76
+
77
+ if entry.endswith('**'):
78
+ self.seq_child.append(clean_entry)
79
+ elif entry.endswith('*'):
80
+ self.child.append(clean_entry)
81
+ else:
82
+ self.attr.append(entry)
83
+
84
+ def generate_source(self):
85
+ src = self._gen_init()
86
+ src += '\n' + self._gen_children()
87
+ src += '\n' + self._gen_iter()
88
+ src += '\n' + self._gen_attr_names()
89
+ return src
90
+
91
+ def _gen_init(self):
92
+ src = "class %s(Node):\n" % self.name
93
+
94
+ if self.all_entries:
95
+ args = ', '.join(self.all_entries)
96
+ slots = ', '.join("'{0}'".format(e) for e in self.all_entries)
97
+ slots += ", 'coord', '__weakref__'"
98
+ arglist = '(self, %s, coord=None)' % args
99
+ else:
100
+ slots = "'coord', '__weakref__'"
101
+ arglist = '(self, coord=None)'
102
+
103
+ src += " __slots__ = (%s)\n" % slots
104
+ src += " def __init__%s:\n" % arglist
105
+
106
+ for name in self.all_entries + ['coord']:
107
+ src += " self.%s = %s\n" % (name, name)
108
+
109
+ return src
110
+
111
+ def _gen_children(self):
112
+ src = ' def children(self):\n'
113
+
114
+ if self.all_entries:
115
+ src += ' nodelist = []\n'
116
+
117
+ for child in self.child:
118
+ src += (
119
+ ' if self.%(child)s is not None:' +
120
+ ' nodelist.append(("%(child)s", self.%(child)s))\n') % (
121
+ dict(child=child))
122
+
123
+ for seq_child in self.seq_child:
124
+ src += (
125
+ ' for i, child in enumerate(self.%(child)s or []):\n'
126
+ ' nodelist.append(("%(child)s[%%d]" %% i, child))\n') % (
127
+ dict(child=seq_child))
128
+
129
+ src += ' return tuple(nodelist)\n'
130
+ else:
131
+ src += ' return ()\n'
132
+
133
+ return src
134
+
135
+ def _gen_iter(self):
136
+ src = ' def __iter__(self):\n'
137
+
138
+ if self.all_entries:
139
+ for child in self.child:
140
+ src += (
141
+ ' if self.%(child)s is not None:\n' +
142
+ ' yield self.%(child)s\n') % (dict(child=child))
143
+
144
+ for seq_child in self.seq_child:
145
+ src += (
146
+ ' for child in (self.%(child)s or []):\n'
147
+ ' yield child\n') % (dict(child=seq_child))
148
+
149
+ if not (self.child or self.seq_child):
150
+ # Empty generator
151
+ src += (
152
+ ' return\n' +
153
+ ' yield\n')
154
+ else:
155
+ # Empty generator
156
+ src += (
157
+ ' return\n' +
158
+ ' yield\n')
159
+
160
+ return src
161
+
162
+ def _gen_attr_names(self):
163
+ src = " attr_names = (" + ''.join("%r, " % nm for nm in self.attr) + ')'
164
+ return src
165
+
166
+
167
+ _PROLOGUE_COMMENT = \
168
+ r'''#-----------------------------------------------------------------
169
+ # ** ATTENTION **
170
+ # This code was automatically generated from the file:
171
+ # $cfg_filename
172
+ #
173
+ # Do not modify it directly. Modify the configuration file and
174
+ # run the generator again.
175
+ # ** ** *** ** **
176
+ #
177
+ # pycparser: c_ast.py
178
+ #
179
+ # AST Node classes.
180
+ #
181
+ # Eli Bendersky [https://eli.thegreenplace.net/]
182
+ # License: BSD
183
+ #-----------------------------------------------------------------
184
+
185
+ '''
186
+
187
+ _PROLOGUE_CODE = r'''
188
+ import sys
189
+
190
+ def _repr(obj):
191
+ """
192
+ Get the representation of an object, with dedicated pprint-like format for lists.
193
+ """
194
+ if isinstance(obj, list):
195
+ return '[' + (',\n '.join((_repr(e).replace('\n', '\n ') for e in obj))) + '\n]'
196
+ else:
197
+ return repr(obj)
198
+
199
+ class Node(object):
200
+ __slots__ = ()
201
+ """ Abstract base class for AST nodes.
202
+ """
203
+ def __repr__(self):
204
+ """ Generates a python representation of the current node
205
+ """
206
+ result = self.__class__.__name__ + '('
207
+
208
+ indent = ''
209
+ separator = ''
210
+ for name in self.__slots__[:-2]:
211
+ result += separator
212
+ result += indent
213
+ result += name + '=' + (_repr(getattr(self, name)).replace('\n', '\n ' + (' ' * (len(name) + len(self.__class__.__name__)))))
214
+
215
+ separator = ','
216
+ indent = '\n ' + (' ' * len(self.__class__.__name__))
217
+
218
+ result += indent + ')'
219
+
220
+ return result
221
+
222
+ def children(self):
223
+ """ A sequence of all children that are Nodes
224
+ """
225
+ pass
226
+
227
+ def show(self, buf=sys.stdout, offset=0, attrnames=False, nodenames=False, showcoord=False, _my_node_name=None):
228
+ """ Pretty print the Node and all its attributes and
229
+ children (recursively) to a buffer.
230
+
231
+ buf:
232
+ Open IO buffer into which the Node is printed.
233
+
234
+ offset:
235
+ Initial offset (amount of leading spaces)
236
+
237
+ attrnames:
238
+ True if you want to see the attribute names in
239
+ name=value pairs. False to only see the values.
240
+
241
+ nodenames:
242
+ True if you want to see the actual node names
243
+ within their parents.
244
+
245
+ showcoord:
246
+ Do you want the coordinates of each Node to be
247
+ displayed.
248
+ """
249
+ lead = ' ' * offset
250
+ if nodenames and _my_node_name is not None:
251
+ buf.write(lead + self.__class__.__name__+ ' <' + _my_node_name + '>: ')
252
+ else:
253
+ buf.write(lead + self.__class__.__name__+ ': ')
254
+
255
+ if self.attr_names:
256
+ if attrnames:
257
+ nvlist = [(n, getattr(self,n)) for n in self.attr_names]
258
+ attrstr = ', '.join('%s=%s' % nv for nv in nvlist)
259
+ else:
260
+ vlist = [getattr(self, n) for n in self.attr_names]
261
+ attrstr = ', '.join('%s' % v for v in vlist)
262
+ buf.write(attrstr)
263
+
264
+ if showcoord:
265
+ buf.write(' (at %s)' % self.coord)
266
+ buf.write('\n')
267
+
268
+ for (child_name, child) in self.children():
269
+ child.show(
270
+ buf,
271
+ offset=offset + 2,
272
+ attrnames=attrnames,
273
+ nodenames=nodenames,
274
+ showcoord=showcoord,
275
+ _my_node_name=child_name)
276
+
277
+
278
+ class NodeVisitor(object):
279
+ """ A base NodeVisitor class for visiting c_ast nodes.
280
+ Subclass it and define your own visit_XXX methods, where
281
+ XXX is the class name you want to visit with these
282
+ methods.
283
+
284
+ For example:
285
+
286
+ class ConstantVisitor(NodeVisitor):
287
+ def __init__(self):
288
+ self.values = []
289
+
290
+ def visit_Constant(self, node):
291
+ self.values.append(node.value)
292
+
293
+ Creates a list of values of all the constant nodes
294
+ encountered below the given node. To use it:
295
+
296
+ cv = ConstantVisitor()
297
+ cv.visit(node)
298
+
299
+ Notes:
300
+
301
+ * generic_visit() will be called for AST nodes for which
302
+ no visit_XXX method was defined.
303
+ * The children of nodes for which a visit_XXX was
304
+ defined will not be visited - if you need this, call
305
+ generic_visit() on the node.
306
+ You can use:
307
+ NodeVisitor.generic_visit(self, node)
308
+ * Modeled after Python's own AST visiting facilities
309
+ (the ast module of Python 3.0)
310
+ """
311
+
312
+ _method_cache = None
313
+
314
+ def visit(self, node):
315
+ """ Visit a node.
316
+ """
317
+
318
+ if self._method_cache is None:
319
+ self._method_cache = {}
320
+
321
+ visitor = self._method_cache.get(node.__class__.__name__, None)
322
+ if visitor is None:
323
+ method = 'visit_' + node.__class__.__name__
324
+ visitor = getattr(self, method, self.generic_visit)
325
+ self._method_cache[node.__class__.__name__] = visitor
326
+
327
+ return visitor(node)
328
+
329
+ def generic_visit(self, node):
330
+ """ Called if no explicit visitor function exists for a
331
+ node. Implements preorder visiting of the node.
332
+ """
333
+ for c in node:
334
+ self.visit(c)
335
+
336
+ '''
@@ -0,0 +1,40 @@
1
+ #-----------------------------------------------------------------
2
+ # pycparser: _build_tables.py
3
+ #
4
+ # A dummy for generating the lexing/parsing tables and and
5
+ # compiling them into .pyc for faster execution in optimized mode.
6
+ # Also generates AST code from the configuration file.
7
+ # Should be called from the pycparser directory.
8
+ #
9
+ # Eli Bendersky [https://eli.thegreenplace.net/]
10
+ # License: BSD
11
+ #-----------------------------------------------------------------
12
+
13
+ # Insert '.' and '..' as first entries to the search path for modules.
14
+ # Restricted environments like embeddable python do not include the
15
+ # current working directory on startup.
16
+ import importlib
17
+ import sys
18
+ sys.path[0:0] = ['.', '..']
19
+
20
+ # Generate c_ast.py
21
+ from _ast_gen import ASTCodeGenerator
22
+ ast_gen = ASTCodeGenerator('_c_ast.cfg')
23
+ ast_gen.generate(open('c_ast.py', 'w'))
24
+
25
+ from pycparser import c_parser
26
+
27
+ # Generates the tables
28
+ #
29
+ c_parser.CParser(
30
+ lex_optimize=True,
31
+ yacc_debug=False,
32
+ yacc_optimize=True)
33
+
34
+ # Load to compile into .pyc
35
+ #
36
+ importlib.invalidate_caches()
37
+
38
+ import lextab
39
+ import yacctab
40
+ import c_ast
pycparser/_c_ast.cfg ADDED
@@ -0,0 +1,195 @@
1
+ #-----------------------------------------------------------------
2
+ # pycparser: _c_ast.cfg
3
+ #
4
+ # Defines the AST Node classes used in pycparser.
5
+ #
6
+ # Each entry is a Node sub-class name, listing the attributes
7
+ # and child nodes of the class:
8
+ # <name>* - a child node
9
+ # <name>** - a sequence of child nodes
10
+ # <name> - an attribute
11
+ #
12
+ # Eli Bendersky [https://eli.thegreenplace.net/]
13
+ # License: BSD
14
+ #-----------------------------------------------------------------
15
+
16
+ # ArrayDecl is a nested declaration of an array with the given type.
17
+ # dim: the dimension (for example, constant 42)
18
+ # dim_quals: list of dimension qualifiers, to support C99's allowing 'const'
19
+ # and 'static' within the array dimension in function declarations.
20
+ ArrayDecl: [type*, dim*, dim_quals]
21
+
22
+ ArrayRef: [name*, subscript*]
23
+
24
+ # op: =, +=, /= etc.
25
+ #
26
+ Assignment: [op, lvalue*, rvalue*]
27
+
28
+ Alignas: [alignment*]
29
+
30
+ BinaryOp: [op, left*, right*]
31
+
32
+ Break: []
33
+
34
+ Case: [expr*, stmts**]
35
+
36
+ Cast: [to_type*, expr*]
37
+
38
+ # Compound statement in C99 is a list of block items (declarations or
39
+ # statements).
40
+ #
41
+ Compound: [block_items**]
42
+
43
+ # Compound literal (anonymous aggregate) for C99.
44
+ # (type-name) {initializer_list}
45
+ # type: the typename
46
+ # init: InitList for the initializer list
47
+ #
48
+ CompoundLiteral: [type*, init*]
49
+
50
+ # type: int, char, float, string, etc.
51
+ #
52
+ Constant: [type, value]
53
+
54
+ Continue: []
55
+
56
+ # name: the variable being declared
57
+ # quals: list of qualifiers (const, volatile)
58
+ # funcspec: list function specifiers (i.e. inline in C99)
59
+ # storage: list of storage specifiers (extern, register, etc.)
60
+ # type: declaration type (probably nested with all the modifiers)
61
+ # init: initialization value, or None
62
+ # bitsize: bit field size, or None
63
+ #
64
+ Decl: [name, quals, align, storage, funcspec, type*, init*, bitsize*]
65
+
66
+ DeclList: [decls**]
67
+
68
+ Default: [stmts**]
69
+
70
+ DoWhile: [cond*, stmt*]
71
+
72
+ # Represents the ellipsis (...) parameter in a function
73
+ # declaration
74
+ #
75
+ EllipsisParam: []
76
+
77
+ # An empty statement (a semicolon ';' on its own)
78
+ #
79
+ EmptyStatement: []
80
+
81
+ # Enumeration type specifier
82
+ # name: an optional ID
83
+ # values: an EnumeratorList
84
+ #
85
+ Enum: [name, values*]
86
+
87
+ # A name/value pair for enumeration values
88
+ #
89
+ Enumerator: [name, value*]
90
+
91
+ # A list of enumerators
92
+ #
93
+ EnumeratorList: [enumerators**]
94
+
95
+ # A list of expressions separated by the comma operator.
96
+ #
97
+ ExprList: [exprs**]
98
+
99
+ # This is the top of the AST, representing a single C file (a
100
+ # translation unit in K&R jargon). It contains a list of
101
+ # "external-declaration"s, which is either declarations (Decl),
102
+ # Typedef or function definitions (FuncDef).
103
+ #
104
+ FileAST: [ext**]
105
+
106
+ # for (init; cond; next) stmt
107
+ #
108
+ For: [init*, cond*, next*, stmt*]
109
+
110
+ # name: Id
111
+ # args: ExprList
112
+ #
113
+ FuncCall: [name*, args*]
114
+
115
+ # type <decl>(args)
116
+ #
117
+ FuncDecl: [args*, type*]
118
+
119
+ # Function definition: a declarator for the function name and
120
+ # a body, which is a compound statement.
121
+ # There's an optional list of parameter declarations for old
122
+ # K&R-style definitions
123
+ #
124
+ FuncDef: [decl*, param_decls**, body*]
125
+
126
+ Goto: [name]
127
+
128
+ ID: [name]
129
+
130
+ # Holder for types that are a simple identifier (e.g. the built
131
+ # ins void, char etc. and typedef-defined types)
132
+ #
133
+ IdentifierType: [names]
134
+
135
+ If: [cond*, iftrue*, iffalse*]
136
+
137
+ # An initialization list used for compound literals.
138
+ #
139
+ InitList: [exprs**]
140
+
141
+ Label: [name, stmt*]
142
+
143
+ # A named initializer for C99.
144
+ # The name of a NamedInitializer is a sequence of Nodes, because
145
+ # names can be hierarchical and contain constant expressions.
146
+ #
147
+ NamedInitializer: [name**, expr*]
148
+
149
+ # a list of comma separated function parameter declarations
150
+ #
151
+ ParamList: [params**]
152
+
153
+ PtrDecl: [quals, type*]
154
+
155
+ Return: [expr*]
156
+
157
+ StaticAssert: [cond*, message*]
158
+
159
+ # name: struct tag name
160
+ # decls: declaration of members
161
+ #
162
+ Struct: [name, decls**]
163
+
164
+ # type: . or ->
165
+ # name.field or name->field
166
+ #
167
+ StructRef: [name*, type, field*]
168
+
169
+ Switch: [cond*, stmt*]
170
+
171
+ # cond ? iftrue : iffalse
172
+ #
173
+ TernaryOp: [cond*, iftrue*, iffalse*]
174
+
175
+ # A base type declaration
176
+ #
177
+ TypeDecl: [declname, quals, align, type*]
178
+
179
+ # A typedef declaration.
180
+ # Very similar to Decl, but without some attributes
181
+ #
182
+ Typedef: [name, quals, storage, type*]
183
+
184
+ Typename: [name, quals, align, type*]
185
+
186
+ UnaryOp: [op, expr*]
187
+
188
+ # name: union tag name
189
+ # decls: declaration of members
190
+ #
191
+ Union: [name, decls**]
192
+
193
+ While: [cond*, stmt*]
194
+
195
+ Pragma: [string]