aboutsummaryrefslogtreecommitdiff
path: root/pycparser/_ast_gen.py
diff options
context:
space:
mode:
Diffstat (limited to 'pycparser/_ast_gen.py')
-rw-r--r--pycparser/_ast_gen.py495
1 files changed, 255 insertions, 240 deletions
diff --git a/pycparser/_ast_gen.py b/pycparser/_ast_gen.py
index 68904d1..2bef0fb 100644
--- a/pycparser/_ast_gen.py
+++ b/pycparser/_ast_gen.py
@@ -1,249 +1,264 @@
-#-----------------------------------------------------------------
-# _ast_gen.py
-#
-# Generates the AST Node classes from a specification given in
-# a .yaml file
-#
-# The design of this module was inspired by astgen.py from the
-# Python 2.5 code-base.
-#
-# Copyright (C) 2008-2010, Eli Bendersky
-# License: LGPL
-#-----------------------------------------------------------------
-
-import pprint
-from string import Template
-
-import yaml
-
-
+#-----------------------------------------------------------------
+# _ast_gen.py
+#
+# Generates the AST Node classes from a specification given in
+# a .yaml file
+#
+# The design of this module was inspired by astgen.py from the
+# Python 2.5 code-base.
+#
+# Copyright (C) 2008-2010, Eli Bendersky
+# License: LGPL
+#-----------------------------------------------------------------
+import pprint
+from string import Template
+
+
class ASTCodeGenerator(object):
- def __init__(self, cfg_filename='_c_ast.yaml'):
- """ Initialize the code generator from a configuration
+ def __init__(self, cfg_filename='_c_ast.cfg'):
+ """ Initialize the code generator from a configuration
file.
- """
- self.cfg_filename = cfg_filename
- cfg = yaml.load(open(cfg_filename).read())
- self.node_cfg = [NodeCfg(name, cfg[name]) for name in cfg]
-
- #~ pprint.pprint(self.node_cfg)
- #~ print ''
-
- def generate(self, file=None):
- """ Generates the code into file, an open file buffer.
- """
- src = Template(_PROLOGUE_COMMENT).substitute(
- cfg_filename=self.cfg_filename)
-
- src += _PROLOGUE_CODE
- for node_cfg in self.node_cfg:
- src += node_cfg.generate_source() + '\n\n'
-
+ """
+ self.cfg_filename = cfg_filename
+ self.node_cfg = [NodeCfg(name, contents) for (name, contents) in self.parse_cfgfile(cfg_filename)]
+
+ def generate(self, file=None):
+ """ Generates the code into file, an open file buffer.
+ """
+ src = Template(_PROLOGUE_COMMENT).substitute(
+ cfg_filename=self.cfg_filename)
+
+ src += _PROLOGUE_CODE
+ for node_cfg in self.node_cfg:
+ src += node_cfg.generate_source() + '\n\n'
+
file.write(src)
-
-
+
+ def parse_cfgfile(self, filename):
+ """ Parse the configuration file and yield pairs of
+ (name, contents) for each node.
+ """
+ with open(filename, "r") as f:
+ for line in f:
+ line = line.strip()
+ if not line or line.startswith('#'):
+ continue
+ colon_i = line.find(':')
+ lbracket_i = line.find('[')
+ rbracket_i = line.find(']')
+ if colon_i < 1 or lbracket_i <= colon_i or rbracket_i <= lbracket_i:
+ raise RuntimeError("Invalid line in %s:\n%s\n" % (filename, line))
+
+ name = line[:colon_i]
+ val = line[lbracket_i + 1:rbracket_i]
+ vallist = [v.strip() for v in val.split(',')] if val else []
+ yield name, vallist
+
+
class NodeCfg(object):
- def __init__(self, name, contents):
- self.name = name
- self.all_entries = []
- self.attr = []
- self.child = []
- self.seq_child = []
-
- for entry in contents:
- clean_entry = entry.rstrip('*')
- self.all_entries.append(clean_entry)
-
- if entry.endswith('**'):
- self.seq_child.append(clean_entry)
- elif entry.endswith('*'):
- self.child.append(clean_entry)
- else:
+ """ Node configuration.
+
+ name: node name
+ contents: a list of contents - attributes and child nodes
+ See comment at the top of the configuration file for details.
+ """
+ def __init__(self, name, contents):
+ self.name = name
+ self.all_entries = []
+ self.attr = []
+ self.child = []
+ self.seq_child = []
+
+ for entry in contents:
+ clean_entry = entry.rstrip('*')
+ self.all_entries.append(clean_entry)
+
+ if entry.endswith('**'):
+ self.seq_child.append(clean_entry)
+ elif entry.endswith('*'):
+ self.child.append(clean_entry)
+ else:
self.attr.append(entry)
-
+
def generate_source(self):
- src = self._gen_init()
- src += '\n' + self._gen_children()
- src += '\n' + self._gen_show()
- return src
-
+ src = self._gen_init()
+ src += '\n' + self._gen_children()
+ src += '\n' + self._gen_show()
+ return src
+
def _gen_init(self):
- src = "class %s(Node):\n" % self.name
-
- if self.all_entries:
- args = ', '.join(self.all_entries)
- arglist = '(self, %s, coord=None)' % args
- else:
- arglist = '(self, coord=None)'
-
- src += " def __init__%s:\n" % arglist
-
- for name in self.all_entries + ['coord']:
- src += " self.%s = %s\n" % (name, name)
-
- return src
-
+ src = "class %s(Node):\n" % self.name
+
+ if self.all_entries:
+ args = ', '.join(self.all_entries)
+ arglist = '(self, %s, coord=None)' % args
+ else:
+ arglist = '(self, coord=None)'
+
+ src += " def __init__%s:\n" % arglist
+
+ for name in self.all_entries + ['coord']:
+ src += " self.%s = %s\n" % (name, name)
+
+ return src
+
def _gen_children(self):
- src = ' def children(self):\n'
-
- if self.all_entries:
- src += ' nodelist = []\n'
-
- template = ('' +
- ' if self.%s is not None:' +
- ' nodelist.%s(self.%s)\n')
-
- for child in self.child:
- src += template % (
- child, 'append', child)
-
- for seq_child in self.seq_child:
- src += template % (
- seq_child, 'extend', seq_child)
-
- src += ' return tuple(nodelist)\n'
- else:
- src += ' return ()\n'
-
- return src
-
+ src = ' def children(self):\n'
+
+ if self.all_entries:
+ src += ' nodelist = []\n'
+
+ template = ('' +
+ ' if self.%s is not None:' +
+ ' nodelist.%s(self.%s)\n')
+
+ for child in self.child:
+ src += template % (
+ child, 'append', child)
+
+ for seq_child in self.seq_child:
+ src += template % (
+ seq_child, 'extend', seq_child)
+
+ src += ' return tuple(nodelist)\n'
+ else:
+ src += ' return ()\n'
+
+ return src
+
def _gen_show(self):
- src = ' def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):\n'
- src += " lead = ' ' * offset\n"
-
- src += " buf.write(lead + '%s: ')\n\n" % self.name
-
- if self.attr:
- src += " if attrnames:\n"
- src += " attrstr = ', '.join('%s=%s' % nv for nv in ["
- src += ', '.join('("%s", repr(%s))' % (nv, 'self.%s' % nv) for nv in self.attr)
- src += '])\n'
- src += " else:\n"
- src += " attrstr = ', '.join('%s' % v for v in ["
- src += ', '.join('self.%s' % v for v in self.attr)
- src += '])\n'
- src += " buf.write(attrstr)\n\n"
-
- src += " if showcoord:\n"
- src += " buf.write(' (at %s)' % self.coord)\n"
- src += " buf.write('\\n')\n\n"
-
- src += " for c in self.children():\n"
- src += " c.show(buf, offset + 2, attrnames, showcoord)\n"
-
- return src
-
-
-_PROLOGUE_COMMENT = \
-r'''#-----------------------------------------------------------------
-# ** ATTENTION **
-# This code was automatically generated from the file:
-# $cfg_filename
-#
-# Do not modify it directly. Modify the configuration file and
-# run the generator again.
-# ** ** *** ** **
-#
-# pycparser: c_ast.py
-#
-# AST Node classes.
-#
-# Copyright (C) 2008, Eli Bendersky
-# License: LGPL
-#-----------------------------------------------------------------
-
-'''
-
-_PROLOGUE_CODE = r'''
-import sys
-
-
-class Node(object):
- """ Abstract base class for AST nodes.
- """
- def children(self):
- """ A sequence of all children that are Nodes
- """
- pass
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- """ Pretty print the Node and all its attributes and
- children (recursively) to a buffer.
-
- file:
- Open IO buffer into which the Node is printed.
-
- offset:
- Initial offset (amount of leading spaces)
-
- attrnames:
- True if you want to see the attribute names in
- name=value pairs. False to only see the values.
-
- showcoord:
- Do you want the coordinates of each Node to be
- displayed.
- """
- pass
-
-
-class NodeVisitor(object):
- """ A base NodeVisitor class for visiting c_ast nodes.
- Subclass it and define your own visit_XXX methods, where
- XXX is the class name you want to visit with these
- methods.
-
- For example:
-
- class ConstantVisitor(NodeVisitor):
- def __init__(self):
- self.values = []
-
- def visit_Constant(self, node):
- self.values.append(node.value)
-
- Creates a list of values of all the constant nodes
- encountered below the given node. To use it:
-
- cv = ConstantVisitor()
- cv.visit(node)
-
- Notes:
-
- * generic_visit() will be called for AST nodes for which
- no visit_XXX method was defined.
- * The children of nodes for which a visit_XXX was
- defined will not be visited - if you need this, call
- generic_visit() on the node.
- You can use:
- NodeVisitor.generic_visit(self, node)
- * Modeled after Python's own AST visiting facilities
- (the ast module of Python 3.0)
- """
- def visit(self, node):
- """ Visit a node.
- """
- method = 'visit_' + node.__class__.__name__
- visitor = getattr(self, method, self.generic_visit)
- return visitor(node)
-
- def generic_visit(self, node):
- """ Called if no explicit visitor function exists for a
- node. Implements preorder visiting of the node.
- """
- for c in node.children():
- self.visit(c)
-
-
-'''
-
-
-
-if __name__ == "__main__":
- import sys
-
- ast_gen = ASTCodeGenerator('_c_ast.yaml')
- ast_gen.generate(open('c_ast.py', 'w'))
-
-
-
+ src = ' def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):\n'
+ src += " lead = ' ' * offset\n"
+
+ src += " buf.write(lead + '%s: ')\n\n" % self.name
+
+ if self.attr:
+ src += " if attrnames:\n"
+ src += " attrstr = ', '.join('%s=%s' % nv for nv in ["
+ src += ', '.join('("%s", repr(%s))' % (nv, 'self.%s' % nv) for nv in self.attr)
+ src += '])\n'
+ src += " else:\n"
+ src += " attrstr = ', '.join('%s' % v for v in ["
+ src += ', '.join('self.%s' % v for v in self.attr)
+ src += '])\n'
+ src += " buf.write(attrstr)\n\n"
+
+ src += " if showcoord:\n"
+ src += " buf.write(' (at %s)' % self.coord)\n"
+ src += " buf.write('\\n')\n\n"
+
+ src += " for c in self.children():\n"
+ src += " c.show(buf, offset + 2, attrnames, showcoord)\n"
+
+ return src
+
+
+_PROLOGUE_COMMENT = \
+r'''#-----------------------------------------------------------------
+# ** ATTENTION **
+# This code was automatically generated from the file:
+# $cfg_filename
+#
+# Do not modify it directly. Modify the configuration file and
+# run the generator again.
+# ** ** *** ** **
+#
+# pycparser: c_ast.py
+#
+# AST Node classes.
+#
+# Copyright (C) 2008-2010, Eli Bendersky
+# License: LGPL
+#-----------------------------------------------------------------
+
+'''
+
+_PROLOGUE_CODE = r'''
+import sys
+
+
+class Node(object):
+ """ Abstract base class for AST nodes.
+ """
+ def children(self):
+ """ A sequence of all children that are Nodes
+ """
+ pass
+
+ def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+ """ Pretty print the Node and all its attributes and
+ children (recursively) to a buffer.
+
+ file:
+ Open IO buffer into which the Node is printed.
+
+ offset:
+ Initial offset (amount of leading spaces)
+
+ attrnames:
+ True if you want to see the attribute names in
+ name=value pairs. False to only see the values.
+
+ showcoord:
+ Do you want the coordinates of each Node to be
+ displayed.
+ """
+ pass
+
+
+class NodeVisitor(object):
+ """ A base NodeVisitor class for visiting c_ast nodes.
+ Subclass it and define your own visit_XXX methods, where
+ XXX is the class name you want to visit with these
+ methods.
+
+ For example:
+
+ class ConstantVisitor(NodeVisitor):
+ def __init__(self):
+ self.values = []
+
+ def visit_Constant(self, node):
+ self.values.append(node.value)
+
+ Creates a list of values of all the constant nodes
+ encountered below the given node. To use it:
+
+ cv = ConstantVisitor()
+ cv.visit(node)
+
+ Notes:
+
+ * generic_visit() will be called for AST nodes for which
+ no visit_XXX method was defined.
+ * The children of nodes for which a visit_XXX was
+ defined will not be visited - if you need this, call
+ generic_visit() on the node.
+ You can use:
+ NodeVisitor.generic_visit(self, node)
+ * Modeled after Python's own AST visiting facilities
+ (the ast module of Python 3.0)
+ """
+ def visit(self, node):
+ """ Visit a node.
+ """
+ method = 'visit_' + node.__class__.__name__
+ visitor = getattr(self, method, self.generic_visit)
+ return visitor(node)
+
+ def generic_visit(self, node):
+ """ Called if no explicit visitor function exists for a
+ node. Implements preorder visiting of the node.
+ """
+ for c in node.children():
+ self.visit(c)
+
+
+'''
+
+
+if __name__ == "__main__":
+ import sys
+ ast_gen = ASTCodeGenerator('_c_ast.cfg')
+ ast_gen.generate(open('c_ast.py', 'w'))
+