"""
Code generator for C constructs.
"""
from ctree.codegen import CodeGenVisitor
from ctree.c.nodes import Op
from ctree.types import codegen_type
from ctree.precedence import UnaryOp, BinaryOp, TernaryOp, Cast
from ctree.precedence import get_precedence, is_left_associative
[docs]class CCodeGen(CodeGenVisitor):
"""
Manages generation of C code.
"""
def _requires_parentheses(self, parent, node):
"""
Returns node as a string, optionally with parentheses around it if
needed to enforce precendence rules.
"""
if isinstance(node, (UnaryOp, BinaryOp, TernaryOp)) and\
isinstance(parent, (UnaryOp, BinaryOp, TernaryOp, Cast)):
prec = get_precedence(node)
parent_prec = get_precedence(parent)
is_not_last_child = isinstance(parent, UnaryOp) or\
isinstance(parent, Cast) or\
(isinstance(parent, BinaryOp) and node is parent.left) or\
(isinstance(parent, TernaryOp) and node is not parent.elze)
assoc_left = is_left_associative(parent)
if (prec < parent_prec) or \
(prec == parent_prec and (assoc_left is not is_not_last_child)):
return True
return False
# -------------------------------------------------------------------------
# visitor methods
[docs] def visit_FunctionDecl(self, node):
params = ", ".join(map(str, node.params))
s = ""
if node.kernel:
s += "__kernel "
if node.static:
s += "static "
if node.inline:
s += "inline "
s += "%s %s(%s)" % (codegen_type(node.return_type), node.name, params)
if node.defn:
s += " %s" % self._genblock(node.defn)
return s
[docs] def visit_UnaryOp(self, node):
op = self._parenthesize(node, node.op)
arg = self._parenthesize(node, node.arg)
if isinstance(node.op, (Op.PostInc, Op.PostDec)):
return "%s %s" % (arg, op)
else:
return "%s %s" % (op, arg)
[docs] def visit_BinaryOp(self, node):
left = self._parenthesize(node, node.left)
right = self._parenthesize(node, node.right)
if isinstance(node.op, Op.ArrayRef):
return "%s[%s]" % (left, right)
else:
return "%s %s %s" % (left, node.op, right)
[docs] def visit_AugAssign(self, node):
return "%s %s= %s" % (node.target, node.op, node.value)
[docs] def visit_TernaryOp(self, node):
cond = self._parenthesize(node, node.cond)
then = self._parenthesize(node, node.then)
elze = self._parenthesize(node, node.elze)
return "%s ? %s : %s" % (cond, then, elze)
[docs] def visit_Cast(self, node):
value = self._parenthesize(node, node.value)
return "(%s) %s" % (codegen_type(node.type), value)
[docs] def visit_Constant(self, node):
if isinstance(node.value, str):
return "'%s'" % node.value[0]
else:
return str(node.value)
[docs] def visit_SymbolRef(self, node):
s = ""
if node._global:
s += "__global "
if node._local:
s += "__local "
if node._const:
s += "const "
if node.type is not None:
s += "%s " % codegen_type(node.type)
return "%s%s" % (s, node.name)
[docs] def visit_Block(self, node):
return self._genblock(node.body)
[docs] def visit_Return(self, node):
if node.value:
return "return %s" % node.value
else:
return "return"
[docs] def visit_If(self, node):
then = self._genblock(node.then)
if node.elze:
elze = self._genblock(node.elze)
return "if (%s) %s else %s" % (node.cond, then, elze)
else:
return "if (%s) %s" % (node.cond, then)
[docs] def visit_While(self, node):
body = self._genblock(node.body)
return "while (%s) %s" % (node.cond, body)
[docs] def visit_DoWhile(self, node):
body = self._genblock(node.body)
return "do %s while (%s)" % (body, node.cond)
[docs] def visit_For(self, node):
body = self._genblock(node.body)
return "for (%s; %s; %s) %s" % (node.init, node.test, node.incr, body)
[docs] def visit_FunctionCall(self, node):
args = ", ".join(map(str, node.args))
return "%s(%s)" % (node.func, args)
[docs] def visit_String(self, node):
return '"%s"' % '" "'.join(node.values)
[docs] def visit_CFile(self, node):
stmts = self._genblock(node.body, insert_curly_brackets=False, increase_indent=False)
return '// <file: %s>%s' % (node.get_filename(), stmts)
[docs] def visit_ArrayDef(self, node):
body = ", ".join(map(str, node.body))
return "%s[%s] = { %s }" % (node.target, node.size, body)