"""
AST nodes for C constructs.
"""
import os
import types
import subprocess
import logging
log = logging.getLogger(__name__)
from ctypes import CFUNCTYPE
from ctree.nodes import CtreeNode, File
from ctree.util import singleton, highlight
from ctree.types import get_ctype
[docs]class CNode(CtreeNode):
"""Base class for all C nodes in ctree."""
[docs] def codegen(self, indent=0):
from ctree.c.codegen import CCodeGen
return CCodeGen(indent).visit(self)
[docs] def label(self):
from ctree.c.dotgen import CDotGenLabeller
return CDotGenLabeller().visit(self)
[docs]class CFile(CNode, File):
"""Represents a .c file."""
_ext = "c"
def __init__(self, name="generated", body=None, config_target='c'):
if not body:
body = []
CNode.__init__(self)
File.__init__(self, name, body)
self.config_target = config_target
[docs] def get_bc_filename(self):
return "%s.bc" % self.name
def _compile(self, program_text, compilation_dir):
import ctree
from ctree.util import truncate
c_src_file = os.path.join(compilation_dir, self.get_filename())
ll_bc_file = os.path.join(compilation_dir, self.get_bc_filename())
log.info("file for generated C: %s", c_src_file)
log.info("file for generated LLVM: %s", ll_bc_file)
# syntax-highlight and print C program
highlighted = highlight(program_text, 'c')
log.info("generated C program: (((\n%s\n)))", highlighted)
# write program text to C file
with open(c_src_file, 'w') as c_file:
c_file.write(program_text)
# call clang to generate LLVM bitcode file
CC = ctree.CONFIG.get(self.config_target, 'CC')
CFLAGS = ctree.CONFIG.get(self.config_target, 'CFLAGS')
compile_cmd = "%s -emit-llvm %s -o %s -c %s" % (CC, CFLAGS, ll_bc_file, c_src_file)
log.info("compilation command: %s", compile_cmd)
subprocess.check_call(compile_cmd, shell=True)
# load llvm bitcode
import llvm.core
with open(ll_bc_file, 'rb') as bc:
ll_module = llvm.core.Module.from_bitcode(bc)
# syntax-highlight and print LLVM program
highlighted = highlight(str(ll_module), 'llvm')
log.debug("generated LLVM Program: (((\n%s\n)))", highlighted)
return ll_module
[docs]class Statement(CNode):
"""Section B.2.3 6.6."""
pass
[docs]class Expression(CNode):
"""Cite me."""
[docs]class Return(Statement):
"""Section B.2.3 6.6.6 line 4."""
_fields = ['value']
def __init__(self, value=None):
self.value = value
super(Return, self).__init__()
[docs]class If(Statement):
"""Cite me."""
_fields = ['cond', 'then', 'elze']
def __init__(self, cond=None, then=None, elze=None):
self.cond = cond
self.then = then
self.elze = elze
super(If, self).__init__()
[docs]class While(Statement):
"""Cite me."""
_fields = ['cond', 'body']
def __init__(self, cond=None, body=None):
self.cond = cond
self.body = body if body else []
super(While, self).__init__()
[docs]class DoWhile(Statement):
_fields = ['body', 'cond']
def __init__(self, body=None, cond=None):
self.body = body if body else []
self.cond = cond
super(DoWhile, self).__init__()
[docs]class For(Statement):
_fields = ['init', 'test', 'incr', 'body']
def __init__(self, init=None, test=None, incr=None, body=None):
self.init = init
self.test = test
self.incr = incr
self.body = body
super(For, self).__init__()
# class Define(Statement):
# mbd: deprecated. see ctree.cpp.nodes.CppDefine
[docs]class FunctionCall(Expression):
"""Cite me."""
_fields = ['func', 'args']
def __init__(self, func=None, args=None):
self.func = func
self.args = args if args else []
super(FunctionCall, self).__init__()
[docs]class Literal(Expression):
"""Cite me."""
pass
[docs]class Constant(Literal):
"""Section B.1.4 6.1.3."""
def __init__(self, value=None):
self.value = value
super(Constant, self).__init__()
[docs] def get_type(self):
return get_ctype(self.value)
[docs]class Block(Statement):
"""Cite me."""
_fields = ['body']
def __init__(self, body=None):
self.body = body if body else []
super(Block, self).__init__()
def _requires_semicolon(self):
return False
[docs]class String(Literal):
"""Cite me."""
def __init__(self, *values):
self.values = values
super(String, self).__init__()
[docs]class SymbolRef(Literal):
"""Cite me."""
_next_id = 0
def __init__(self, name=None, sym_type=None, _global=False,
_local=False, _const=False):
"""
Create a new symbol with the given name. If a declaration
type is specified, the symbol is considered a declaration
and unparsed with the type.
"""
self.name = name
self.type = sym_type
self._global = _global
self._local = _local
self._const = _const
super(SymbolRef, self).__init__()
[docs] def set_global(self, value=True):
self._global = value
return self
[docs] def set_local(self, value=True):
self._local = value
return self
[docs] def set_const(self, value=True):
self._const = value
return self
@classmethod
[docs] def unique(cls, name="name", sym_type=None):
"""
Factory for making unique symbols.
"""
sym = SymbolRef("%s_%d" % (name, cls._next_id), sym_type)
cls._next_id += 1
return sym
[docs] def copy(self, declare=False):
if declare:
return SymbolRef(self.name, self.type, self._global)
else:
return SymbolRef(self.name)
[docs]class FunctionDecl(Statement):
"""Cite me."""
_fields = ['params', 'defn']
def __init__(self, return_type=None, name=None, params=None, defn=None):
self.return_type = return_type
self.name = name
self.params = params if params else []
self.defn = defn if defn else []
self.inline = False
self.static = False
self.kernel = False
super(FunctionDecl, self).__init__()
[docs] def get_type(self):
type_sig = []
# return type
if self.return_type is None:
type_sig.append(self.return_type)
else:
assert not isinstance(self.return_type, type), \
"Expected a ctypes instance or None, got %s (%s)." % \
(self.return_type, type(self.return_type))
type_sig.append( type(self.return_type) )
# parameter types
for param in self.params:
assert not isinstance(param.type, type), \
"Expected a ctypes instance or None, got %s (%s)." % \
(param.type, type(param.type))
type_sig.append( type(param.type) )
return CFUNCTYPE(*type_sig)
[docs] def set_inline(self, value=True):
self.inline = value
return self
[docs] def set_static(self, value=True):
self.static = value
return self
[docs] def set_kernel(self, value=True):
self.kernel = value
return self
[docs]class UnaryOp(Expression):
"""Cite me."""
_fields = ['arg']
def __init__(self, op=None, arg=None):
self.op = op
self.arg = arg
super(UnaryOp, self).__init__()
[docs]class BinaryOp(Expression):
"""Cite me."""
_fields = ['left', 'right']
def __init__(self, left=None, op=None, right=None):
self.left = left
self.op = op
self.right = right
super(BinaryOp, self).__init__()
[docs] def get_type(self):
# FIXME: integer promotions and stuff like that
return self.left.get_type()
[docs]class AugAssign(Expression):
"""Cite me."""
_fields = ['target', 'value']
def __init__(self, target=None, op=None, value=None):
self.target = target
self.op = op
self.value = value
super(AugAssign, self).__init__()
[docs]class TernaryOp(Expression):
"""Cite me."""
_fields = ['cond', 'then', 'elze']
def __init__(self, cond=None, then=None, elze=None):
self.cond = cond
self.then = then
self.elze = elze
super(TernaryOp, self).__init__()
[docs]class Cast(Expression):
"""doc"""
_fields = ['value']
def __init__(self, sym_type=None, value=None):
self.type = sym_type
self.value = value
super(Cast, self).__init__()
[docs]class ArrayDef(Expression):
"""doc"""
_fields = ['target', 'size', 'body']
def __init__(self, target=None, size=None, body=None):
self.target = target
self.size = size
self.body = body if body else []
super(ArrayDef, self).__init__()
@singleton
class Op:
class _Op(object):
def __init__(self):
self._force_parentheses = False
def __str__(self):
return self._c_str
class PreInc(_Op):
_c_str = "++"
class PreDec(_Op):
_c_str = "--"
class PostInc(_Op):
_c_str = "++"
class PostDec(_Op):
_c_str = "--"
class Ref(_Op):
_c_str = "&"
class Deref(_Op):
_c_str = "*"
class SizeOf(_Op):
_c_str = "sizeof"
class Add(_Op):
_c_str = "+"
class AddUnary(_Op):
_c_str = "+"
class Sub(_Op):
_c_str = "-"
class SubUnary(_Op):
_c_str = "-"
class Mul(_Op):
_c_str = "*"
class Div(_Op):
_c_str = "/"
class Mod(_Op):
_c_str = "%"
class Gt(_Op):
_c_str = ">"
class Lt(_Op):
_c_str = "<"
class GtE(_Op):
_c_str = ">="
class LtE(_Op):
_c_str = "<="
class Eq(_Op):
_c_str = "=="
class NotEq(_Op):
_c_str = "!="
class BitAnd(_Op):
_c_str = "&"
class BitOr(_Op):
_c_str = "|"
class BitNot(_Op):
_c_str = "~"
class BitShL(_Op):
_c_str = "<<"
class BitShR(_Op):
_c_str = ">>"
class BitXor(_Op):
_c_str = "^"
class And(_Op):
_c_str = "&&"
class Or(_Op):
_c_str = "||"
class Not(_Op):
_c_str = "!"
class Comma(_Op):
_c_str = ","
class Dot(_Op):
_c_str = "."
class Arrow(_Op):
_c_str = "->"
class Assign(_Op):
_c_str = "="
class ArrayRef(_Op):
_c_str = "[]"
# ---------------------------------------------------------------------------
# factory routines for building UnaryOps, BinaryOps, etc.
[docs]def PreInc(a):
return UnaryOp(Op.PreInc(), a)
[docs]def PreDec(a):
return UnaryOp(Op.PreDec(), a)
[docs]def PostInc(a):
return UnaryOp(Op.PostInc(), a)
[docs]def PostDec(a):
return UnaryOp(Op.PostDec(), a)
[docs]def BitNot(a):
return UnaryOp(Op.BitNot(), a)
[docs]def Not(a):
return UnaryOp(Op.Not(), a)
[docs]def Ref(a):
return UnaryOp(Op.Ref(), a)
[docs]def Deref(a):
return UnaryOp(Op.Deref(), a)
[docs]def SizeOf(a):
return UnaryOp(Op.SizeOf(), a)
[docs]def Add(a, b=None):
if b is not None:
return BinaryOp(a, Op.Add(), b)
else:
return UnaryOp(Op.AddUnary(), a)
[docs]def Sub(a, b=None):
if b is not None:
return BinaryOp(a, Op.Sub(), b)
else:
return UnaryOp(Op.SubUnary(), a)
[docs]def Mul(a, b):
return BinaryOp(a, Op.Mul(), b)
[docs]def Div(a, b):
return BinaryOp(a, Op.Div(), b)
[docs]def Mod(a, b):
return BinaryOp(a, Op.Mod(), b)
[docs]def Gt(a, b):
return BinaryOp(a, Op.Gt(), b)
[docs]def Lt(a, b):
return BinaryOp(a, Op.Lt(), b)
[docs]def GtE(a, b):
return BinaryOp(a, Op.GtE(), b)
[docs]def LtE(a, b):
return BinaryOp(a, Op.LtE(), b)
[docs]def Eq(a, b):
return BinaryOp(a, Op.Eq(), b)
[docs]def NotEq(a, b):
return BinaryOp(a, Op.NotEq(), b)
[docs]def BitAnd(a, b):
return BinaryOp(a, Op.BitAnd(), b)
[docs]def BitOr(a, b):
return BinaryOp(a, Op.BitOr(), b)
[docs]def BitShL(a, b):
return BinaryOp(a, Op.BitShL(), b)
[docs]def BitShR(a, b):
return BinaryOp(a, Op.BitShR(), b)
[docs]def BitXor(a, b):
return BinaryOp(a, Op.BitXor(), b)
[docs]def And(a, b):
return BinaryOp(a, Op.And(), b)
[docs]def Or(a, b):
return BinaryOp(a, Op.Or(), b)
[docs]def Comma(a, b):
return BinaryOp(a, Op.Comma(), b)
[docs]def Dot(a, b):
return BinaryOp(a, Op.Dot(), b)
[docs]def Arrow(a, b):
return BinaryOp(a, Op.Arrow(), b)
[docs]def Assign(a, b):
return BinaryOp(a, Op.Assign(), b)
[docs]def ArrayRef(a, b):
return BinaryOp(a, Op.ArrayRef(), b)
[docs]def AddAssign(a, b):
return AugAssign(a, Op.Add(), b)
[docs]def SubAssign(a, b):
return AugAssign(a, Op.Sub(), b)
[docs]def MulAssign(a, b):
return AugAssign(a, Op.Mul(), b)
[docs]def DivAssign(a, b):
return AugAssign(a, Op.Div(), b)
[docs]def ModAssign(a, b):
return AugAssign(a, Op.Mod(), b)
[docs]def BitXorAssign(a, b):
return AugAssign(a, Op.BitXor(), b)
[docs]def BitAndAssign(a, b):
return AugAssign(a, Op.BitAnd(), b)
[docs]def BitOrAssign(a, b):
return AugAssign(a, Op.BitOr(), b)
[docs]def BitShLAssign(a, b):
return AugAssign(a, Op.BitShL(), b)
[docs]def BitShRAssign(a, b):
return AugAssign(a, Op.BitShR(), b)