Skip to content
Snippets Groups Projects
Commit 6c696202 authored by James K. Lowden's avatar James K. Lowden :anchor:
Browse files

version 0.1

parents
No related branches found
No related tags found
No related merge requests found
cscan 0 → 100755
#! /usr/bin/env python3
# Copyright (c) 2020, Symas Corporation
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Use pycparser to report casts in a C file.
#
from __future__ import print_function
import sys, re
from os import environ, getcwd
from getopt import getopt
from subprocess import CalledProcessError
# In case not installed in site-packages/ with setup.py
sys.path.extend(['.', '..'])
from pycparser import c_parser, c_ast, parse_file
from pycparser.plyparser import ParseError
verbose = False
def string_of(node):
if isinstance(node, c_ast.ArrayDecl):
return '%s %s[%s]' % (string_of(node.type),
'name',
' '.join(string_of(node.dim_quals),
string_of(node.dim)))
if isinstance(node, c_ast.ArrayRef):
return '%s[%s]' % (string_of(node.name),
string_of(node.subscript))
if isinstance(node, c_ast.Assignment):
return '%s %s %s' % (string_of(node.lvalue),
string_of(node.op),
string_of(node.rvalue))
if isinstance(node, c_ast.BinaryOp):
return '%s %s %s' % (string_of(node.left),
string_of(node.op),
string_of(node.right))
if isinstance(node, c_ast.Break):
return 'break?'
if isinstance(node, c_ast.Case):
return '%s %s' % (string_of(node.expr),
string_of(node.stmts))
if isinstance(node, c_ast.Cast):
return '(%s) (%s)' % (string_of(node.to_type),
string_of(node.expr))
if isinstance(node, c_ast.Compound):
return '%s' % (string_of(node.block_items))
if isinstance(node, c_ast.CompoundLiteral):
return '%s %s' % ( string_of(node.init),
string_of(node.type) )
if isinstance(node, c_ast.Constant):
return '%s %s' % (string_of(node.type),
string_of(node.value))
# class Continue(Node)
if isinstance(node, c_ast.Decl):
return '%s/%s/%s/%s/%s/%s/%s' % ( string_of(node.bitsize),
string_of(node.funcspec),
string_of(node.init),
string_of(node.name),
string_of(node.quals),
string_of(node.storage),
string_of(node.type) )
if isinstance(node, c_ast.DeclList):
return '%s' % string_of(node.decls)
if isinstance(node, c_ast.Default):
return '%s' % string_of(node.stmts)
if isinstance(node, c_ast.DoWhile):
return 'do/while (%s) { %s }' % (string_of(node.cond),
string_of(node.stmt))
#class EllipsisParam(Node)
#class EmptyStatement(Node)
if isinstance(node, c_ast.Enum):
return '%s {%s}' % ( string_of(node.name),
string_of(node.values) )
if isinstance(node, c_ast.Enumerator):
return '%s %s' % ( string_of(node.name),
string_of(node.value) )
if isinstance(node, c_ast.EnumeratorList):
return '%s %s' % ( string_of(node.enumerators) )
if isinstance(node, c_ast.ExprList):
return '%s' % ( string_of(node.exprs) )
# FileAST
if isinstance(node, c_ast.For):
return 'for(%s; %s; %s {%s}' % ( string_of(node.init),
string_of(node.cond),
string_of(node.next),
string_of(node.stmt) )
if isinstance(node, c_ast.FuncCall):
return '%s(%s)' % ( string_of(node.name),
string_of(node.args) )
if isinstance(node, c_ast.FuncDecl):
return '%s %s(%s)' % ( string_of(node.type),
'funcname',
string_of(node.args) )
if isinstance(node, c_ast.FuncDef):
return '%s %s() {%s}' % ( string_of(node.decl),
string_of(node.param_decls),
string_of(node.body) )
if isinstance(node, c_ast.Goto):
return 'goto %s' % ( string_of(node.name) )
if isinstance(node, c_ast.ID):
assert(isinstance(node.name, str))
return '%s' % ( node.name )
if isinstance(node, c_ast.IdentifierType):
for name in node.names:
assert(isinstance(name, str))
return '%s' % ( ' '.join(node.names) )
if isinstance(node, c_ast.If):
return 'if (%s) {%s} else {%s}' % ( string_of(node.cond),
string_of(node.iftrue),
string_of(node.iffalse) )
if isinstance(node, c_ast.InitList):
return '%s %s' % ( string_of(node.exprs) )
if isinstance(node, c_ast.Label):
return '%s: %s' % ( string_of(node.name),
string_of(node.stmt) )
if isinstance(node, c_ast.NamedInitializer):
return '%s %s' % ( string_of(node.name),
string_of(node.expr) )
# Node
# NodeVisitor
if isinstance(node, c_ast.ParamList):
return '%s' % ( string_of(node.params) )
if isinstance(node, c_ast.Pragma):
return '#pragma %s' % ( string_of(node.string) )
if isinstance(node, c_ast.PtrDecl):
return '%s*' % ' '.join( ( string_of(node.quals),
string_of(node.type) ) )
if isinstance(node, c_ast.Return):
return 'return %s' % ( string_of(node.expr) )
if isinstance(node, c_ast.Struct):
return '%s {%s}' % ( string_of(node.name),
string_of(node.decls) )
if isinstance(node, c_ast.StructRef):
return '%s%s%s' % ( string_of(node.name),
string_of(node.type),
string_of(node.field) )
if isinstance(node, c_ast.Switch):
return 'switch %s (%s)' % ( string_of(node.cond),
string_of(node.stmt) )
if isinstance(node, c_ast.TernaryOp):
return '%s ? %s : %s' % ( string_of(node.cond),
string_of(node.iftrue),
string_of(node.iffalse) )
if isinstance(node, c_ast.TypeDecl):
return '%s %s' % ( ' '.join( (string_of(node.quals),
string_of(node.declname)) ),
string_of(node.type) )
if isinstance(node, c_ast.Typedef):
return '%s %s' % ( ' '.join( (string_of(node.quals),
string_of(node.storage),
string_of(node.type)) ),
string_of(node.name) )
if isinstance(node, c_ast.Typename):
output = '%s %s' % ( ' '.join( (string_of(node.quals),
string_of(node.type))),
string_of(node.name) )
# typename.qual and PtrDecl.TypeDecl.quals may both say 'const'
output = re.sub(r'(const +)+', 'const ', output)
return output.strip()
if isinstance(node, c_ast.UnaryOp):
return '%s%s' % ( string_of(node.op),
string_of(node.expr) )
if isinstance(node, c_ast.Union):
return 'union %s {%s}' % ( string_of(node.name),
string_of(node.decls) )
if isinstance(node, c_ast.While):
return 'while (%s) (%s)' % ( string_of(node.cond),
string_of(node.stmt) )
if isinstance(node, tuple) or isinstance(node, list):
elems = [ string_of(x) for x in node ]
return ' '.join(elems)
if isinstance(node, str):
return node
if node is None:
return ''
print( 'error: string_of: unhandled type "%s"' % str(type(node)) )
def cast_pair(node):
assert( isinstance(node, c_ast.Cast) )
def class_name(node):
return re.split(r'\W+', str(type(node)))[-2]
def coord(node):
return '%s:%s' % ( node.coord.file, node.coord.line )
if verbose:
print( 'cast: %s of %s' % (class_name(node.to_type),
class_name(node.expr)) )
#node.show(offset=2, showcoord=True)
#print( '----' )
return '%s: %-10s %s' % (coord(node),
class_name(node.expr) + ':',
string_of(node))
# Visitor for Cast nodes, to report where a cast is used.
class CastVisitor(c_ast.NodeVisitor):
def visit_Cast(self, node):
print( cast_pair(node) )
def show_casts(cpp, filename):
cpp_args = re.split(r'\s{2,}', environ['CSCAN_FLAGS'])
assert( len(cpp_args) > 1 )
ast = parse_file(filename, use_cpp=True,
cpp_path=cpp,
cpp_args=cpp_args)
v = CastVisitor()
v.visit(ast)
if __name__ == "__main__":
cpp = 'cpp'
try:
opts, args = getopt(sys.argv[1:], "E:v")
except getopt.GetoptError as err:
print(err)
exit(1)
narg = 1
for narg, (o, a) in enumerate(opts, start=2):
if o == "-E":
cpp = a
elif o == '-v':
verbose = True
else:
assert False, "unhandled option"
exit_status = 0
for filename in sys.argv[narg:]:
print( 'scanning "%s"' % filename )
try:
show_casts(cpp, filename)
except CalledProcessError as erc:
print( '%s in %s' % (erc, getcwd()), file=sys.stderr )
exit(1)
except ParseError as erc:
print( 'cscan error at\n%s in %s' % (erc, getcwd()),
file=sys.stderr )
if verbose:
raise RuntimeError("verbose causes traceback") from erc
exit_status = 1
except BrokenPipeError as erc:
exit(1)
exit(exit_status)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment