update windows build to Python 3.7

This commit is contained in:
j 2019-01-20 16:05:31 +05:30
commit ddc59ab92d
5761 changed files with 750298 additions and 213405 deletions

View file

@ -4,13 +4,14 @@
# This package file exports some convenience functions for
# interacting with pycparser
#
# Copyright (C) 2008-2015, Eli Bendersky
# Eli Bendersky [https://eli.thegreenplace.net/]
# License: BSD
#-----------------------------------------------------------------
__all__ = ['c_lexer', 'c_parser', 'c_ast']
__version__ = '2.14'
__version__ = '2.19'
from subprocess import Popen, PIPE
import io
from subprocess import check_output
from .c_parser import CParser
@ -38,11 +39,7 @@ def preprocess_file(filename, cpp_path='cpp', cpp_args=''):
try:
# Note the use of universal_newlines to treat all newlines
# as \n for Python's purpose
#
pipe = Popen( path_list,
stdout=PIPE,
universal_newlines=True)
text = pipe.communicate()[0]
text = check_output(path_list, universal_newlines=True)
except OSError as e:
raise RuntimeError("Unable to invoke 'cpp'. " +
'Make sure its path was passed correctly\n' +
@ -85,7 +82,7 @@ def parse_file(filename, use_cpp=False, cpp_path='cpp', cpp_args='',
if use_cpp:
text = preprocess_file(filename, cpp_path, cpp_args)
else:
with open(filename, 'rU') as f:
with io.open(filename) as f:
text = f.read()
if parser is None:

View file

@ -7,7 +7,7 @@
# The design of this module was inspired by astgen.py from the
# Python 2.5 code-base.
#
# Copyright (C) 2008-2015, Eli Bendersky
# Eli Bendersky [https://eli.thegreenplace.net/]
# License: BSD
#-----------------------------------------------------------------
import pprint
@ -63,6 +63,7 @@ class NodeCfg(object):
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 = []
@ -84,6 +85,8 @@ class NodeCfg(object):
def generate_source(self):
src = self._gen_init()
src += '\n' + self._gen_children()
src += '\n' + self._gen_iter()
src += '\n' + self._gen_attr_names()
return src
@ -131,6 +134,33 @@ class NodeCfg(object):
return src
def _gen_iter(self):
src = ' def __iter__(self):\n'
if self.all_entries:
for child in self.child:
src += (
' if self.%(child)s is not None:\n' +
' yield self.%(child)s\n') % (dict(child=child))
for seq_child in self.seq_child:
src += (
' for child in (self.%(child)s or []):\n'
' yield child\n') % (dict(child=seq_child))
if not (self.child or self.seq_child):
# Empty generator
src += (
' return\n' +
' yield\n')
else:
# Empty generator
src += (
' return\n' +
' yield\n')
return src
def _gen_attr_names(self):
src = " attr_names = (" + ''.join("%r, " % nm for nm in self.attr) + ')'
return src
@ -150,7 +180,7 @@ r'''#-----------------------------------------------------------------
#
# AST Node classes.
#
# Copyright (C) 2008-2015, Eli Bendersky
# Eli Bendersky [https://eli.thegreenplace.net/]
# License: BSD
#-----------------------------------------------------------------
@ -159,11 +189,38 @@ r'''#-----------------------------------------------------------------
_PROLOGUE_CODE = r'''
import sys
def _repr(obj):
"""
Get the representation of an object, with dedicated pprint-like format for lists.
"""
if isinstance(obj, list):
return '[' + (',\n '.join((_repr(e).replace('\n', '\n ') for e in obj))) + '\n]'
else:
return repr(obj)
class Node(object):
__slots__ = ()
""" Abstract base class for AST nodes.
"""
def __repr__(self):
""" Generates a python representation of the current node
"""
result = self.__class__.__name__ + '('
indent = ''
separator = ''
for name in self.__slots__[:-2]:
result += separator
result += indent
result += name + '=' + (_repr(getattr(self, name)).replace('\n', '\n ' + (' ' * (len(name) + len(self.__class__.__name__)))))
separator = ','
indent = '\n ' + (' ' * len(self.__class__.__name__))
result += indent + ')'
return result
def children(self):
""" A sequence of all children that are Nodes
"""
@ -253,26 +310,29 @@ class NodeVisitor(object):
* Modeled after Python's own AST visiting facilities
(the ast module of Python 3.0)
"""
_method_cache = None
def visit(self, node):
""" Visit a node.
"""
method = 'visit_' + node.__class__.__name__
visitor = getattr(self, method, self.generic_visit)
if self._method_cache is None:
self._method_cache = {}
visitor = self._method_cache.get(node.__class__.__name__, None)
if visitor is None:
method = 'visit_' + node.__class__.__name__
visitor = getattr(self, method, self.generic_visit)
self._method_cache[node.__class__.__name__] = visitor
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_name, c in node.children():
for c in node:
self.visit(c)
'''
if __name__ == "__main__":
import sys
ast_gen = ASTCodeGenerator('_c_ast.cfg')
ast_gen.generate(open('c_ast.py', 'w'))

View file

@ -6,7 +6,7 @@
# Also generates AST code from the configuration file.
# Should be called from the pycparser directory.
#
# Copyright (C) 2008-2015, Eli Bendersky
# Eli Bendersky [https://eli.thegreenplace.net/]
# License: BSD
#-----------------------------------------------------------------

View file

@ -9,7 +9,7 @@
# <name>** - a sequence of child nodes
# <name> - an attribute
#
# Copyright (C) 2008-2015, Eli Bendersky
# Eli Bendersky [https://eli.thegreenplace.net/]
# License: BSD
#-----------------------------------------------------------------
@ -187,3 +187,5 @@ UnaryOp: [op, expr*]
Union: [name, decls**]
While: [cond*, stmt*]
Pragma: [string]

View file

@ -3,7 +3,7 @@
#
# Some utilities used by the parser to create a friendlier AST.
#
# Copyright (C) 2008-2015, Eli Bendersky
# Eli Bendersky [https://eli.thegreenplace.net/]
# License: BSD
#------------------------------------------------------------------------------
@ -43,7 +43,7 @@ def fix_switch_cases(switch_node):
Default:
break
The goal of this transform it to fix this mess, turning it into the
The goal of this transform is to fix this mess, turning it into the
following:
Switch

View file

@ -11,18 +11,45 @@
#
# AST Node classes.
#
# Copyright (C) 2008-2015, Eli Bendersky
# Eli Bendersky [https://eli.thegreenplace.net/]
# License: BSD
#-----------------------------------------------------------------
import sys
def _repr(obj):
"""
Get the representation of an object, with dedicated pprint-like format for lists.
"""
if isinstance(obj, list):
return '[' + (',\n '.join((_repr(e).replace('\n', '\n ') for e in obj))) + '\n]'
else:
return repr(obj)
class Node(object):
__slots__ = ()
""" Abstract base class for AST nodes.
"""
def __repr__(self):
""" Generates a python representation of the current node
"""
result = self.__class__.__name__ + '('
indent = ''
separator = ''
for name in self.__slots__[:-2]:
result += separator
result += indent
result += name + '=' + (_repr(getattr(self, name)).replace('\n', '\n ' + (' ' * (len(name) + len(self.__class__.__name__)))))
separator = ','
indent = '\n ' + (' ' * len(self.__class__.__name__))
result += indent + ')'
return result
def children(self):
""" A sequence of all children that are Nodes
"""
@ -112,21 +139,31 @@ class NodeVisitor(object):
* Modeled after Python's own AST visiting facilities
(the ast module of Python 3.0)
"""
_method_cache = None
def visit(self, node):
""" Visit a node.
"""
method = 'visit_' + node.__class__.__name__
visitor = getattr(self, method, self.generic_visit)
if self._method_cache is None:
self._method_cache = {}
visitor = self._method_cache.get(node.__class__.__name__, None)
if visitor is None:
method = 'visit_' + node.__class__.__name__
visitor = getattr(self, method, self.generic_visit)
self._method_cache[node.__class__.__name__] = visitor
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_name, c in node.children():
for c in node:
self.visit(c)
class ArrayDecl(Node):
__slots__ = ('type', 'dim', 'dim_quals', 'coord', '__weakref__')
def __init__(self, type, dim, dim_quals, coord=None):
@ -141,6 +178,12 @@ class ArrayDecl(Node):
if self.dim is not None: nodelist.append(("dim", self.dim))
return tuple(nodelist)
def __iter__(self):
if self.type is not None:
yield self.type
if self.dim is not None:
yield self.dim
attr_names = ('dim_quals', )
class ArrayRef(Node):
@ -156,6 +199,12 @@ class ArrayRef(Node):
if self.subscript is not None: nodelist.append(("subscript", self.subscript))
return tuple(nodelist)
def __iter__(self):
if self.name is not None:
yield self.name
if self.subscript is not None:
yield self.subscript
attr_names = ()
class Assignment(Node):
@ -172,6 +221,12 @@ class Assignment(Node):
if self.rvalue is not None: nodelist.append(("rvalue", self.rvalue))
return tuple(nodelist)
def __iter__(self):
if self.lvalue is not None:
yield self.lvalue
if self.rvalue is not None:
yield self.rvalue
attr_names = ('op', )
class BinaryOp(Node):
@ -188,6 +243,12 @@ class BinaryOp(Node):
if self.right is not None: nodelist.append(("right", self.right))
return tuple(nodelist)
def __iter__(self):
if self.left is not None:
yield self.left
if self.right is not None:
yield self.right
attr_names = ('op', )
class Break(Node):
@ -198,6 +259,10 @@ class Break(Node):
def children(self):
return ()
def __iter__(self):
return
yield
attr_names = ()
class Case(Node):
@ -214,6 +279,12 @@ class Case(Node):
nodelist.append(("stmts[%d]" % i, child))
return tuple(nodelist)
def __iter__(self):
if self.expr is not None:
yield self.expr
for child in (self.stmts or []):
yield child
attr_names = ()
class Cast(Node):
@ -229,6 +300,12 @@ class Cast(Node):
if self.expr is not None: nodelist.append(("expr", self.expr))
return tuple(nodelist)
def __iter__(self):
if self.to_type is not None:
yield self.to_type
if self.expr is not None:
yield self.expr
attr_names = ()
class Compound(Node):
@ -243,6 +320,10 @@ class Compound(Node):
nodelist.append(("block_items[%d]" % i, child))
return tuple(nodelist)
def __iter__(self):
for child in (self.block_items or []):
yield child
attr_names = ()
class CompoundLiteral(Node):
@ -258,6 +339,12 @@ class CompoundLiteral(Node):
if self.init is not None: nodelist.append(("init", self.init))
return tuple(nodelist)
def __iter__(self):
if self.type is not None:
yield self.type
if self.init is not None:
yield self.init
attr_names = ()
class Constant(Node):
@ -271,6 +358,10 @@ class Constant(Node):
nodelist = []
return tuple(nodelist)
def __iter__(self):
return
yield
attr_names = ('type', 'value', )
class Continue(Node):
@ -281,6 +372,10 @@ class Continue(Node):
def children(self):
return ()
def __iter__(self):
return
yield
attr_names = ()
class Decl(Node):
@ -302,6 +397,14 @@ class Decl(Node):
if self.bitsize is not None: nodelist.append(("bitsize", self.bitsize))
return tuple(nodelist)
def __iter__(self):
if self.type is not None:
yield self.type
if self.init is not None:
yield self.init
if self.bitsize is not None:
yield self.bitsize
attr_names = ('name', 'quals', 'storage', 'funcspec', )
class DeclList(Node):
@ -316,6 +419,10 @@ class DeclList(Node):
nodelist.append(("decls[%d]" % i, child))
return tuple(nodelist)
def __iter__(self):
for child in (self.decls or []):
yield child
attr_names = ()
class Default(Node):
@ -330,6 +437,10 @@ class Default(Node):
nodelist.append(("stmts[%d]" % i, child))
return tuple(nodelist)
def __iter__(self):
for child in (self.stmts or []):
yield child
attr_names = ()
class DoWhile(Node):
@ -345,6 +456,12 @@ class DoWhile(Node):
if self.stmt is not None: nodelist.append(("stmt", self.stmt))
return tuple(nodelist)
def __iter__(self):
if self.cond is not None:
yield self.cond
if self.stmt is not None:
yield self.stmt
attr_names = ()
class EllipsisParam(Node):
@ -355,6 +472,10 @@ class EllipsisParam(Node):
def children(self):
return ()
def __iter__(self):
return
yield
attr_names = ()
class EmptyStatement(Node):
@ -365,6 +486,10 @@ class EmptyStatement(Node):
def children(self):
return ()
def __iter__(self):
return
yield
attr_names = ()
class Enum(Node):
@ -379,6 +504,10 @@ class Enum(Node):
if self.values is not None: nodelist.append(("values", self.values))
return tuple(nodelist)
def __iter__(self):
if self.values is not None:
yield self.values
attr_names = ('name', )
class Enumerator(Node):
@ -393,6 +522,10 @@ class Enumerator(Node):
if self.value is not None: nodelist.append(("value", self.value))
return tuple(nodelist)
def __iter__(self):
if self.value is not None:
yield self.value
attr_names = ('name', )
class EnumeratorList(Node):
@ -407,6 +540,10 @@ class EnumeratorList(Node):
nodelist.append(("enumerators[%d]" % i, child))
return tuple(nodelist)
def __iter__(self):
for child in (self.enumerators or []):
yield child
attr_names = ()
class ExprList(Node):
@ -421,6 +558,10 @@ class ExprList(Node):
nodelist.append(("exprs[%d]" % i, child))
return tuple(nodelist)
def __iter__(self):
for child in (self.exprs or []):
yield child
attr_names = ()
class FileAST(Node):
@ -435,6 +576,10 @@ class FileAST(Node):
nodelist.append(("ext[%d]" % i, child))
return tuple(nodelist)
def __iter__(self):
for child in (self.ext or []):
yield child
attr_names = ()
class For(Node):
@ -454,6 +599,16 @@ class For(Node):
if self.stmt is not None: nodelist.append(("stmt", self.stmt))
return tuple(nodelist)
def __iter__(self):
if self.init is not None:
yield self.init
if self.cond is not None:
yield self.cond
if self.next is not None:
yield self.next
if self.stmt is not None:
yield self.stmt
attr_names = ()
class FuncCall(Node):
@ -469,6 +624,12 @@ class FuncCall(Node):
if self.args is not None: nodelist.append(("args", self.args))
return tuple(nodelist)
def __iter__(self):
if self.name is not None:
yield self.name
if self.args is not None:
yield self.args
attr_names = ()
class FuncDecl(Node):
@ -484,6 +645,12 @@ class FuncDecl(Node):
if self.type is not None: nodelist.append(("type", self.type))
return tuple(nodelist)
def __iter__(self):
if self.args is not None:
yield self.args
if self.type is not None:
yield self.type
attr_names = ()
class FuncDef(Node):
@ -502,6 +669,14 @@ class FuncDef(Node):
nodelist.append(("param_decls[%d]" % i, child))
return tuple(nodelist)
def __iter__(self):
if self.decl is not None:
yield self.decl
if self.body is not None:
yield self.body
for child in (self.param_decls or []):
yield child
attr_names = ()
class Goto(Node):
@ -514,6 +689,10 @@ class Goto(Node):
nodelist = []
return tuple(nodelist)
def __iter__(self):
return
yield
attr_names = ('name', )
class ID(Node):
@ -526,6 +705,10 @@ class ID(Node):
nodelist = []
return tuple(nodelist)
def __iter__(self):
return
yield
attr_names = ('name', )
class IdentifierType(Node):
@ -538,6 +721,10 @@ class IdentifierType(Node):
nodelist = []
return tuple(nodelist)
def __iter__(self):
return
yield
attr_names = ('names', )
class If(Node):
@ -555,6 +742,14 @@ class If(Node):
if self.iffalse is not None: nodelist.append(("iffalse", self.iffalse))
return tuple(nodelist)
def __iter__(self):
if self.cond is not None:
yield self.cond
if self.iftrue is not None:
yield self.iftrue
if self.iffalse is not None:
yield self.iffalse
attr_names = ()
class InitList(Node):
@ -569,6 +764,10 @@ class InitList(Node):
nodelist.append(("exprs[%d]" % i, child))
return tuple(nodelist)
def __iter__(self):
for child in (self.exprs or []):
yield child
attr_names = ()
class Label(Node):
@ -583,6 +782,10 @@ class Label(Node):
if self.stmt is not None: nodelist.append(("stmt", self.stmt))
return tuple(nodelist)
def __iter__(self):
if self.stmt is not None:
yield self.stmt
attr_names = ('name', )
class NamedInitializer(Node):
@ -599,6 +802,12 @@ class NamedInitializer(Node):
nodelist.append(("name[%d]" % i, child))
return tuple(nodelist)
def __iter__(self):
if self.expr is not None:
yield self.expr
for child in (self.name or []):
yield child
attr_names = ()
class ParamList(Node):
@ -613,6 +822,10 @@ class ParamList(Node):
nodelist.append(("params[%d]" % i, child))
return tuple(nodelist)
def __iter__(self):
for child in (self.params or []):
yield child
attr_names = ()
class PtrDecl(Node):
@ -627,6 +840,10 @@ class PtrDecl(Node):
if self.type is not None: nodelist.append(("type", self.type))
return tuple(nodelist)
def __iter__(self):
if self.type is not None:
yield self.type
attr_names = ('quals', )
class Return(Node):
@ -640,6 +857,10 @@ class Return(Node):
if self.expr is not None: nodelist.append(("expr", self.expr))
return tuple(nodelist)
def __iter__(self):
if self.expr is not None:
yield self.expr
attr_names = ()
class Struct(Node):
@ -655,6 +876,10 @@ class Struct(Node):
nodelist.append(("decls[%d]" % i, child))
return tuple(nodelist)
def __iter__(self):
for child in (self.decls or []):
yield child
attr_names = ('name', )
class StructRef(Node):
@ -671,6 +896,12 @@ class StructRef(Node):
if self.field is not None: nodelist.append(("field", self.field))
return tuple(nodelist)
def __iter__(self):
if self.name is not None:
yield self.name
if self.field is not None:
yield self.field
attr_names = ('type', )
class Switch(Node):
@ -686,6 +917,12 @@ class Switch(Node):
if self.stmt is not None: nodelist.append(("stmt", self.stmt))
return tuple(nodelist)
def __iter__(self):
if self.cond is not None:
yield self.cond
if self.stmt is not None:
yield self.stmt
attr_names = ()
class TernaryOp(Node):
@ -703,6 +940,14 @@ class TernaryOp(Node):
if self.iffalse is not None: nodelist.append(("iffalse", self.iffalse))
return tuple(nodelist)
def __iter__(self):
if self.cond is not None:
yield self.cond
if self.iftrue is not None:
yield self.iftrue
if self.iffalse is not None:
yield self.iffalse
attr_names = ()
class TypeDecl(Node):
@ -718,6 +963,10 @@ class TypeDecl(Node):
if self.type is not None: nodelist.append(("type", self.type))
return tuple(nodelist)
def __iter__(self):
if self.type is not None:
yield self.type
attr_names = ('declname', 'quals', )
class Typedef(Node):
@ -734,6 +983,10 @@ class Typedef(Node):
if self.type is not None: nodelist.append(("type", self.type))
return tuple(nodelist)
def __iter__(self):
if self.type is not None:
yield self.type
attr_names = ('name', 'quals', 'storage', )
class Typename(Node):
@ -749,6 +1002,10 @@ class Typename(Node):
if self.type is not None: nodelist.append(("type", self.type))
return tuple(nodelist)
def __iter__(self):
if self.type is not None:
yield self.type
attr_names = ('name', 'quals', )
class UnaryOp(Node):
@ -763,6 +1020,10 @@ class UnaryOp(Node):
if self.expr is not None: nodelist.append(("expr", self.expr))
return tuple(nodelist)
def __iter__(self):
if self.expr is not None:
yield self.expr
attr_names = ('op', )
class Union(Node):
@ -778,6 +1039,10 @@ class Union(Node):
nodelist.append(("decls[%d]" % i, child))
return tuple(nodelist)
def __iter__(self):
for child in (self.decls or []):
yield child
attr_names = ('name', )
class While(Node):
@ -793,5 +1058,27 @@ class While(Node):
if self.stmt is not None: nodelist.append(("stmt", self.stmt))
return tuple(nodelist)
def __iter__(self):
if self.cond is not None:
yield self.cond
if self.stmt is not None:
yield self.stmt
attr_names = ()
class Pragma(Node):
__slots__ = ('string', 'coord', '__weakref__')
def __init__(self, string, coord=None):
self.string = string
self.coord = coord
def children(self):
nodelist = []
return tuple(nodelist)
def __iter__(self):
return
yield
attr_names = ('string', )

View file

@ -3,7 +3,7 @@
#
# C code generator from pycparser AST nodes.
#
# Copyright (C) 2008-2015, Eli Bendersky
# Eli Bendersky [https://eli.thegreenplace.net/]
# License: BSD
#------------------------------------------------------------------------------
from . import c_ast
@ -40,6 +40,12 @@ class CGenerator(object):
def visit_ID(self, n):
return n.name
def visit_Pragma(self, n):
ret = '#pragma'
if n.string:
ret += ' ' + n.string
return ret
def visit_ArrayRef(self, n):
arrref = self._parenthesize_unless_simple(n.name)
return arrref + '[' + self.visit(n.subscript) + ']'
@ -129,18 +135,20 @@ class CGenerator(object):
return ', '.join(visited_subexprs)
def visit_Enum(self, n):
s = 'enum'
if n.name: s += ' ' + n.name
if n.values:
s += ' {'
for i, enumerator in enumerate(n.values.enumerators):
s += enumerator.name
if enumerator.value:
s += ' = ' + self.visit(enumerator.value)
if i != len(n.values.enumerators) - 1:
s += ', '
s += '}'
return s
return self._generate_struct_union_enum(n, name='enum')
def visit_Enumerator(self, n):
if not n.value:
return '{indent}{name},\n'.format(
indent=self._make_indent(),
name=n.name,
)
else:
return '{indent}{name} = {value},\n'.format(
indent=self._make_indent(),
name=n.name,
value=self.visit(n.value),
)
def visit_FuncDef(self, n):
decl = self.visit(n.decl)
@ -157,6 +165,8 @@ class CGenerator(object):
for ext in n.ext:
if isinstance(ext, c_ast.FuncDef):
s += self.visit(ext)
elif isinstance(ext, c_ast.Pragma):
s += self.visit(ext) + '\n'
else:
s += self.visit(ext) + ';\n'
return s
@ -170,6 +180,10 @@ class CGenerator(object):
s += self._make_indent() + '}\n'
return s
def visit_CompoundLiteral(self, n):
return '(' + self.visit(n.type) + '){' + self.visit(n.init) + '}'
def visit_EmptyStatement(self, n):
return ';'
@ -188,9 +202,9 @@ class CGenerator(object):
return 'continue;'
def visit_TernaryOp(self, n):
s = self._visit_expr(n.cond) + ' ? '
s += self._visit_expr(n.iftrue) + ' : '
s += self._visit_expr(n.iffalse)
s = '(' + self._visit_expr(n.cond) + ') ? '
s += '(' + self._visit_expr(n.iftrue) + ') : '
s += '(' + self._visit_expr(n.iffalse) + ')'
return s
def visit_If(self, n):
@ -256,43 +270,58 @@ class CGenerator(object):
return '...'
def visit_Struct(self, n):
return self._generate_struct_union(n, 'struct')
return self._generate_struct_union_enum(n, 'struct')
def visit_Typename(self, n):
return self._generate_type(n.type)
def visit_Union(self, n):
return self._generate_struct_union(n, 'union')
return self._generate_struct_union_enum(n, 'union')
def visit_NamedInitializer(self, n):
s = ''
for name in n.name:
if isinstance(name, c_ast.ID):
s += '.' + name.name
elif isinstance(name, c_ast.Constant):
s += '[' + name.value + ']'
s += ' = ' + self.visit(n.expr)
else:
s += '[' + self.visit(name) + ']'
s += ' = ' + self._visit_expr(n.expr)
return s
def visit_FuncDecl(self, n):
return self._generate_type(n)
def _generate_struct_union(self, n, name):
""" Generates code for structs and unions. name should be either
'struct' or union.
def _generate_struct_union_enum(self, n, name):
""" Generates code for structs, unions, and enums. name should be
'struct', 'union', or 'enum'.
"""
if name in ('struct', 'union'):
members = n.decls
body_function = self._generate_struct_union_body
else:
assert name == 'enum'
members = None if n.values is None else n.values.enumerators
body_function = self._generate_enum_body
s = name + ' ' + (n.name or '')
if n.decls:
if members is not None:
# None means no members
# Empty sequence means an empty list of members
s += '\n'
s += self._make_indent()
self.indent_level += 2
s += '{\n'
for decl in n.decls:
s += self._generate_stmt(decl)
s += body_function(members)
self.indent_level -= 2
s += self._make_indent() + '}'
return s
def _generate_struct_union_body(self, members):
return ''.join(self._generate_stmt(decl) for decl in members)
def _generate_enum_body(self, members):
# `[:-2] + '\n'` removes the final `,` from the enumerator list
return ''.join(self.visit(value) for value in members)[:-2] + '\n'
def _generate_stmt(self, n, add_indent=False):
""" Generation from a statement node. This method exists as a wrapper
for individual visit_* methods to handle different treatment of
@ -395,5 +424,5 @@ class CGenerator(object):
""" Returns True for nodes that are "simple" - i.e. nodes that always
have higher precedence than operators.
"""
return isinstance(n,( c_ast.Constant, c_ast.ID, c_ast.ArrayRef,
c_ast.StructRef, c_ast.FuncCall))
return isinstance(n, (c_ast.Constant, c_ast.ID, c_ast.ArrayRef,
c_ast.StructRef, c_ast.FuncCall))

View file

@ -3,7 +3,7 @@
#
# CLexer class: lexer for the C language
#
# Copyright (C) 2008-2015, Eli Bendersky
# Eli Bendersky [https://eli.thegreenplace.net/]
# License: BSD
#------------------------------------------------------------------------------
import re
@ -52,8 +52,8 @@ class CLexer(object):
# Allow either "# line" or "# <num>" to support GCC's
# cpp output
#
self.line_pattern = re.compile('([ \t]*line\W)|([ \t]*\d+)')
self.pragma_pattern = re.compile('[ \t]*pragma\W')
self.line_pattern = re.compile(r'([ \t]*line\W)|([ \t]*\d+)')
self.pragma_pattern = re.compile(r'[ \t]*pragma\W')
def build(self, **kwargs):
""" Builds the lexer from the specification. Must be
@ -102,11 +102,11 @@ class CLexer(object):
keywords = (
'_BOOL', '_COMPLEX', 'AUTO', 'BREAK', 'CASE', 'CHAR', 'CONST',
'CONTINUE', 'DEFAULT', 'DO', 'DOUBLE', 'ELSE', 'ENUM', 'EXTERN',
'FLOAT', 'FOR', 'GOTO', 'IF', 'INLINE', 'INT', 'LONG',
'FLOAT', 'FOR', 'GOTO', 'IF', 'INLINE', 'INT', 'LONG',
'REGISTER', 'OFFSETOF',
'RESTRICT', 'RETURN', 'SHORT', 'SIGNED', 'SIZEOF', 'STATIC', 'STRUCT',
'SWITCH', 'TYPEDEF', 'UNION', 'UNSIGNED', 'VOID',
'VOLATILE', 'WHILE',
'VOLATILE', 'WHILE', '__INT128',
)
keyword_map = {}
@ -171,7 +171,9 @@ class CLexer(object):
'ELLIPSIS',
# pre-processor
'PPHASH', # '#'
'PPHASH', # '#'
'PPPRAGMA', # 'pragma'
'PPPRAGMASTR',
)
##
@ -219,7 +221,7 @@ class CLexer(object):
string_char = r"""([^"\\\n]|"""+escape_sequence+')'
string_literal = '"'+string_char+'*"'
wstring_literal = 'L'+string_literal
bad_string_literal = '"'+string_char+'*'+bad_escape+string_char+'*"'
bad_string_literal = '"'+string_char+'*?'+bad_escape+string_char+'*"'
# floating constants (K&R2: A.2.5.3)
exponent_part = r"""([eE][-+]?[0-9]+)"""
@ -274,7 +276,6 @@ class CLexer(object):
def t_ppline_NEWLINE(self, t):
r'\n'
if self.pp_line is None:
self._error('line number missing in #line', t)
else:
@ -304,15 +305,14 @@ class CLexer(object):
def t_pppragma_PPPRAGMA(self, t):
r'pragma'
pass
return t
t_pppragma_ignore = ' \t<>.-{}();=+-*/$%@&^~!?:,0123456789'
t_pppragma_ignore = ' \t'
@TOKEN(string_literal)
def t_pppragma_STR(self, t): pass
@TOKEN(identifier)
def t_pppragma_ID(self, t): pass
def t_pppragma_STR(self, t):
'.+'
t.type = 'PPPRAGMASTR'
return t
def t_pppragma_error(self, t):
self._error('invalid #pragma directive', t)
@ -482,4 +482,3 @@ class CLexer(object):
def t_error(self, t):
msg = 'Illegal character %s' % repr(t.value[0])
self._error(msg, t)

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -1,4 +1,5 @@
# PLY package
# Author: David Beazley (dave@dabeaz.com)
__version__ = '3.9'
__all__ = ['lex','yacc']

View file

@ -2,12 +2,19 @@
# cpp.py
#
# Author: David Beazley (http://www.dabeaz.com)
# Copyright (C) 2007
# Copyright (C) 2017
# All rights reserved
#
# This module implements an ANSI-C style lexical preprocessor for PLY.
# This module implements an ANSI-C style lexical preprocessor for PLY.
# -----------------------------------------------------------------------------
from __future__ import generators
import sys
# Some Python 3 compatibility shims
if sys.version_info.major < 3:
STRING_TYPES = (str, unicode)
else:
STRING_TYPES = str
xrange = range
# -----------------------------------------------------------------------------
# Default preprocessor lexer definitions. These tokens are enough to get
@ -15,7 +22,7 @@ from __future__ import generators
# -----------------------------------------------------------------------------
tokens = (
'CPP_ID','CPP_INTEGER', 'CPP_FLOAT', 'CPP_STRING', 'CPP_CHAR', 'CPP_WS', 'CPP_COMMENT', 'CPP_POUND','CPP_DPOUND'
'CPP_ID','CPP_INTEGER', 'CPP_FLOAT', 'CPP_STRING', 'CPP_CHAR', 'CPP_WS', 'CPP_COMMENT1', 'CPP_COMMENT2', 'CPP_POUND','CPP_DPOUND'
)
literals = "+-*/%|&~^<>=!?()[]{}.,;:\\\'\""
@ -34,7 +41,7 @@ t_CPP_ID = r'[A-Za-z_][\w_]*'
# Integer literal
def CPP_INTEGER(t):
r'(((((0x)|(0X))[0-9a-fA-F]+)|(\d+))([uU]|[lL]|[uU][lL]|[lL][uU])?)'
r'(((((0x)|(0X))[0-9a-fA-F]+)|(\d+))([uU][lL]|[lL][uU]|[uU]|[lL])?)'
return t
t_CPP_INTEGER = CPP_INTEGER
@ -55,11 +62,21 @@ def t_CPP_CHAR(t):
return t
# Comment
def t_CPP_COMMENT(t):
r'(/\*(.|\n)*?\*/)|(//.*?\n)'
t.lexer.lineno += t.value.count("\n")
def t_CPP_COMMENT1(t):
r'(/\*(.|\n)*?\*/)'
ncr = t.value.count("\n")
t.lexer.lineno += ncr
# replace with one space or a number of '\n'
t.type = 'CPP_WS'; t.value = '\n' * ncr if ncr else ' '
return t
# Line comment
def t_CPP_COMMENT2(t):
r'(//.*?(\n|$))'
# replace with '/n'
t.type = 'CPP_WS'; t.value = '\n'
return t
def t_error(t):
t.type = t.value[0]
t.value = t.value[0]
@ -73,8 +90,8 @@ import os.path
# -----------------------------------------------------------------------------
# trigraph()
#
# Given an input string, this function replaces all trigraph sequences.
#
# Given an input string, this function replaces all trigraph sequences.
# The following mapping is used:
#
# ??= #
@ -244,7 +261,7 @@ class Preprocessor(object):
# ----------------------------------------------------------------------
# add_path()
#
# Adds a search path to the preprocessor.
# Adds a search path to the preprocessor.
# ----------------------------------------------------------------------
def add_path(self,path):
@ -288,7 +305,7 @@ class Preprocessor(object):
# ----------------------------------------------------------------------
# tokenstrip()
#
#
# Remove leading/trailing whitespace tokens from a token list
# ----------------------------------------------------------------------
@ -314,7 +331,7 @@ class Preprocessor(object):
# argument. Each argument is represented by a list of tokens.
#
# When collecting arguments, leading and trailing whitespace is removed
# from each argument.
# from each argument.
#
# This function properly handles nested parenthesis and commas---these do not
# define new arguments.
@ -326,7 +343,7 @@ class Preprocessor(object):
current_arg = []
nesting = 1
tokenlen = len(tokenlist)
# Search for the opening '('.
i = 0
while (i < tokenlen) and (tokenlist[i].type in self.t_WS):
@ -360,7 +377,7 @@ class Preprocessor(object):
else:
current_arg.append(t)
i += 1
# Missing end argument
self.error(self.source,tokenlist[-1].lineno,"Missing ')' in macro arguments")
return 0, [],[]
@ -372,9 +389,9 @@ class Preprocessor(object):
# This is used to speed up macro expansion later on---we'll know
# right away where to apply patches to the value to form the expansion
# ----------------------------------------------------------------------
def macro_prescan(self,macro):
macro.patch = [] # Standard macro arguments
macro.patch = [] # Standard macro arguments
macro.str_patch = [] # String conversion expansion
macro.var_comma_patch = [] # Variadic macro comma patch
i = 0
@ -421,7 +438,7 @@ class Preprocessor(object):
rep = [copy.copy(_x) for _x in macro.value]
# Make string expansion patches. These do not alter the length of the replacement sequence
str_expansion = {}
for argnum, i in macro.str_patch:
if argnum not in str_expansion:
@ -439,7 +456,7 @@ class Preprocessor(object):
# Make all other patches. The order of these matters. It is assumed that the patch list
# has been sorted in reverse order of patch location since replacements will cause the
# size of the replacement sequence to expand from the patch point.
expanded = { }
for ptype, argnum, i in macro.patch:
# Concatenation. Argument is left unexpanded
@ -476,7 +493,7 @@ class Preprocessor(object):
if t.value in self.macros and t.value not in expanded:
# Yes, we found a macro match
expanded[t.value] = True
m = self.macros[t.value]
if not m.arglist:
# A simple macro
@ -508,7 +525,7 @@ class Preprocessor(object):
else:
args[len(m.arglist)-1] = tokens[j+positions[len(m.arglist)-1]:j+tokcount-1]
del args[len(m.arglist):]
# Get macro replacement text
rep = self.macro_expand_args(m,args)
rep = self.expand_macros(rep,expanded)
@ -521,13 +538,13 @@ class Preprocessor(object):
elif t.value == '__LINE__':
t.type = self.t_INTEGER
t.value = self.t_INTEGER_TYPE(t.lineno)
i += 1
return tokens
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# evalexpr()
#
#
# Evaluate an expression token sequence for the purposes of evaluating
# integral expressions.
# ----------------------------------------------------------------------
@ -574,14 +591,14 @@ class Preprocessor(object):
tokens[i].value = str(tokens[i].value)
while tokens[i].value[-1] not in "0123456789abcdefABCDEF":
tokens[i].value = tokens[i].value[:-1]
expr = "".join([str(x.value) for x in tokens])
expr = expr.replace("&&"," and ")
expr = expr.replace("||"," or ")
expr = expr.replace("!"," not ")
try:
result = eval(expr)
except StandardError:
except Exception:
self.error(self.source,tokens[0].lineno,"Couldn't evaluate expression")
result = 0
return result
@ -599,7 +616,7 @@ class Preprocessor(object):
if not source:
source = ""
self.define("__FILE__ \"%s\"" % source)
self.source = source
@ -614,10 +631,11 @@ class Preprocessor(object):
if tok.value == '#':
# Preprocessor directive
# insert necessary whitespace instead of eaten tokens
for tok in x:
if tok in self.t_WS and '\n' in tok.value:
if tok.type in self.t_WS and '\n' in tok.value:
chunk.append(tok)
dirtokens = self.tokenstrip(x[i+1:])
if dirtokens:
name = dirtokens[0].value
@ -625,7 +643,7 @@ class Preprocessor(object):
else:
name = ""
args = []
if name == 'define':
if enable:
for tok in self.expand_macros(chunk):
@ -685,7 +703,7 @@ class Preprocessor(object):
iftrigger = True
else:
self.error(self.source,dirtokens[0].lineno,"Misplaced #elif")
elif name == 'else':
if ifstack:
if ifstack[-1][0]:
@ -771,7 +789,7 @@ class Preprocessor(object):
# ----------------------------------------------------------------------
def define(self,tokens):
if isinstance(tokens,(str,unicode)):
if isinstance(tokens,STRING_TYPES):
tokens = self.tokenize(tokens)
linetok = tokens
@ -855,7 +873,7 @@ class Preprocessor(object):
def parse(self,input,source=None,ignore={}):
self.ignore = ignore
self.parser = self.parsegen(input,source)
# ----------------------------------------------------------------------
# token()
#
@ -885,14 +903,3 @@ if __name__ == '__main__':
tok = p.token()
if not tok: break
print(p.source, tok)

View file

@ -9,10 +9,10 @@
tokens = [
# Literals (identifier, integer constant, float constant, string constant, char const)
'ID', 'TYPEID', 'ICONST', 'FCONST', 'SCONST', 'CCONST',
'ID', 'TYPEID', 'INTEGER', 'FLOAT', 'STRING', 'CHARACTER',
# Operators (+,-,*,/,%,|,&,~,^,<<,>>, ||, &&, !, <, <=, >, >=, ==, !=)
'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'MOD',
'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'MODULO',
'OR', 'AND', 'NOT', 'XOR', 'LSHIFT', 'RSHIFT',
'LOR', 'LAND', 'LNOT',
'LT', 'LE', 'GT', 'GE', 'EQ', 'NE',
@ -22,7 +22,7 @@ tokens = [
'LSHIFTEQUAL','RSHIFTEQUAL', 'ANDEQUAL', 'XOREQUAL', 'OREQUAL',
# Increment/decrement (++,--)
'PLUSPLUS', 'MINUSMINUS',
'INCREMENT', 'DECREMENT',
# Structure dereference (->)
'ARROW',
@ -74,7 +74,7 @@ t_LSHIFTEQUAL = r'<<='
t_RSHIFTEQUAL = r'>>='
t_ANDEQUAL = r'&='
t_OREQUAL = r'\|='
t_XOREQUAL = r'^='
t_XOREQUAL = r'\^='
# Increment/decrement
t_INCREMENT = r'\+\+'

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,74 @@
# ply: ygen.py
#
# This is a support program that auto-generates different versions of the YACC parsing
# function with different features removed for the purposes of performance.
#
# Users should edit the method LParser.parsedebug() in yacc.py. The source code
# for that method is then used to create the other methods. See the comments in
# yacc.py for further details.
import os.path
import shutil
def get_source_range(lines, tag):
srclines = enumerate(lines)
start_tag = '#--! %s-start' % tag
end_tag = '#--! %s-end' % tag
for start_index, line in srclines:
if line.strip().startswith(start_tag):
break
for end_index, line in srclines:
if line.strip().endswith(end_tag):
break
return (start_index + 1, end_index)
def filter_section(lines, tag):
filtered_lines = []
include = True
tag_text = '#--! %s' % tag
for line in lines:
if line.strip().startswith(tag_text):
include = not include
elif include:
filtered_lines.append(line)
return filtered_lines
def main():
dirname = os.path.dirname(__file__)
shutil.copy2(os.path.join(dirname, 'yacc.py'), os.path.join(dirname, 'yacc.py.bak'))
with open(os.path.join(dirname, 'yacc.py'), 'r') as f:
lines = f.readlines()
parse_start, parse_end = get_source_range(lines, 'parsedebug')
parseopt_start, parseopt_end = get_source_range(lines, 'parseopt')
parseopt_notrack_start, parseopt_notrack_end = get_source_range(lines, 'parseopt-notrack')
# Get the original source
orig_lines = lines[parse_start:parse_end]
# Filter the DEBUG sections out
parseopt_lines = filter_section(orig_lines, 'DEBUG')
# Filter the TRACKING sections out
parseopt_notrack_lines = filter_section(parseopt_lines, 'TRACKING')
# Replace the parser source sections with updated versions
lines[parseopt_notrack_start:parseopt_notrack_end] = parseopt_notrack_lines
lines[parseopt_start:parseopt_end] = parseopt_lines
lines = [line.rstrip()+'\n' for line in lines]
with open(os.path.join(dirname, 'yacc.py'), 'w') as f:
f.writelines(lines)
print('Updated yacc.py')
if __name__ == '__main__':
main()

View file

@ -4,10 +4,11 @@
# PLYParser class and other utilites for simplifying programming
# parsers with PLY
#
# Copyright (C) 2008-2015, Eli Bendersky
# Eli Bendersky [https://eli.thegreenplace.net/]
# License: BSD
#-----------------------------------------------------------------
import warnings
class Coord(object):
""" Coordinates of a syntactic element. Consists of:
@ -51,5 +52,82 @@ class PLYParser(object):
line=lineno,
column=column)
def _token_coord(self, p, token_idx):
""" Returns the coordinates for the YaccProduction objet 'p' indexed
with 'token_idx'. The coordinate includes the 'lineno' and
'column'. Both follow the lex semantic, starting from 1.
"""
last_cr = p.lexer.lexer.lexdata.rfind('\n', 0, p.lexpos(token_idx))
if last_cr < 0:
last_cr = -1
column = (p.lexpos(token_idx) - (last_cr))
return self._coord(p.lineno(token_idx), column)
def _parse_error(self, msg, coord):
raise ParseError("%s: %s" % (coord, msg))
def parameterized(*params):
""" Decorator to create parameterized rules.
Parameterized rule methods must be named starting with 'p_' and contain
'xxx', and their docstrings may contain 'xxx' and 'yyy'. These will be
replaced by the given parameter tuples. For example, ``p_xxx_rule()`` with
docstring 'xxx_rule : yyy' when decorated with
``@parameterized(('id', 'ID'))`` produces ``p_id_rule()`` with the docstring
'id_rule : ID'. Using multiple tuples produces multiple rules.
"""
def decorate(rule_func):
rule_func._params = params
return rule_func
return decorate
def template(cls):
""" Class decorator to generate rules from parameterized rule templates.
See `parameterized` for more information on parameterized rules.
"""
issued_nodoc_warning = False
for attr_name in dir(cls):
if attr_name.startswith('p_'):
method = getattr(cls, attr_name)
if hasattr(method, '_params'):
# Remove the template method
delattr(cls, attr_name)
# Create parameterized rules from this method; only run this if
# the method has a docstring. This is to address an issue when
# pycparser's users are installed in -OO mode which strips
# docstrings away.
# See: https://github.com/eliben/pycparser/pull/198/ and
# https://github.com/eliben/pycparser/issues/197
# for discussion.
if method.__doc__ is not None:
_create_param_rules(cls, method)
elif not issued_nodoc_warning:
warnings.warn(
'parsing methods must have __doc__ for pycparser to work properly',
RuntimeWarning,
stacklevel=2)
issued_nodoc_warning = True
return cls
def _create_param_rules(cls, func):
""" Create ply.yacc rules based on a parameterized rule function
Generates new methods (one per each pair of parameters) based on the
template rule function `func`, and attaches them to `cls`. The rule
function's parameters must be accessible via its `_params` attribute.
"""
for xxx, yyy in func._params:
# Use the template method's body for each new method
def param_rule(self, p):
func(self, p)
# Substitute in the params for the grammar rule and function name
param_rule.__doc__ = func.__doc__.replace('xxx', xxx).replace('yyy', yyy)
param_rule.__name__ = func.__name__.replace('xxx', xxx)
# Attach the new method to the class
setattr(cls, param_rule.__name__, param_rule)

File diff suppressed because one or more lines are too long