joxeankoret icon

Dump AST Python script

joxeankoret | PRO | 08/12/18 09:58:47 AM UTC | 0 ⭐ | 873 👁️ | Never ⏰ | []
Python |

3.38 KB

|

None

|

0 👍

/

0 👎

#!/usr/bin/python
 
import sys
import clang
import popen2
 
from clang.cindex import Diagnostic, CursorKind, TokenKind
 
#-------------------------------------------------------------------------------
def severity2text(severity):
  if severity == Diagnostic.Ignored:
    return ""
  elif severity == Diagnostic.Note:
    return "note"
  elif severity == Diagnostic.Warning:
    return "warning"
  elif severity == Diagnostic.Error:
    return "error"
  elif severity == Diagnostic.Fatal:
    return "fatal"
  else:
    return "unknown"
 
#-------------------------------------------------------------------------------
INLINE_NAMES = ["inline", "__inline", "__inline__", "__forceinline", "always_inline"]
def is_inline(cursor):
  if cursor.kind != CursorKind.FUNCTION_DECL:
    return False
 
  for token in cursor.get_tokens():
    tkn = token.spelling
    if tkn in INLINE_NAMES:
      return True
    if tkn == "{":
      break
  return False
 
#-------------------------------------------------------------------------------
def is_static(cursor):
  if cursor.kind != CursorKind.FUNCTION_DECL:
    return False
  token = next(cursor.get_tokens(), None)
  return token.spelling == "static"
 
#-------------------------------------------------------------------------------
def dump_ast(filename, cursor, level = 0):
  fileobj = cursor.location.file
  if fileobj is not None and fileobj.name != filename:
    return
 
  prototype = None
  if cursor.kind == CursorKind.FUNCTION_DECL:
    try:
      args = []
      for arg in cursor.get_arguments():
        args.append("%s %s" % (arg.type.spelling, arg.spelling))
 
      #prototype = "%s %s" % (cursor.get_definition().result_type.spelling, cursor.get_definition().displayname)
      definition = cursor.get_definition()
      if definition is not None:
        prototype = "%s %s(%s)" % (cursor.get_definition().result_type.spelling, cursor.spelling, ", ".join(args))
    except:
      pass
 
    inlined = is_inline(cursor)
 
  token = next(cursor.get_tokens(), None)
  if token is not None:
    token = token.spelling
 
  if prototype is not None:
    print "  "*level, cursor.kind, "INLINED?", inlined, repr(prototype), repr(token), cursor.location
  else:
    print "  "*level, cursor.kind, repr(cursor.spelling), repr(token), cursor.location
 
  for children in cursor.get_children():
    dump_ast(filename, children, level+1)
 
#-------------------------------------------------------------------------------
def resolve_clang_includes():
  cmd = "clang -print-file-name=include"
  rfd, wfd = popen2.popen2(cmd)
  return rfd.read().strip("\n")
 
#-------------------------------------------------------------------------------
def usage():
  print "Usage: %s <source file> <arguments>" % sys.argv[0]
 
#-------------------------------------------------------------------------------
def main(src, args):
  clang_includes = resolve_clang_includes()
  args.append("-I%s" % clang_includes)
  index = clang.cindex.Index.create()
  tu = index.parse(path=src, args=args)
  diags = tu.diagnostics
 
  for diag in diags:
    print("%s:%d,%d: %s: %s" % (diag.location.file, diag.location.line,
          diag.location.column, severity2text(diag.severity), diag.spelling))
  
  dump_ast(src, tu.cursor)
 
if __name__ == "__main__":
  args = []
  if len(sys.argv) != 3:
    usage()
  else:
    main(sys.argv[1], sys.argv[2:])

Comments