Index: sasmodels/py2c.py
===================================================================
--- sasmodels/py2c.py	(revision 7b1dcf924220a1a38691997b1962d9b6c8c934d1)
+++ sasmodels/py2c.py	(revision 4339764151090f686344466eda6255a8743c996b)
@@ -1,17 +1,14 @@
-
 """
-    codegen
-    ~~~~~~~
-
-    Extension to ast that allow ast -> python code generation.
-
-    :copyright: Copyright 2008 by Armin Ronacher.
-    :license: BSD.
-"""
-"""
+    py2c
+    ~~~~
+
+    Convert simple numeric python code into C code.
+
+    The translate() function works on
+
     Variables definition in C
     -------------------------
-    Defining variables within the Translate function is a bit of a guess work,
-    using following rules.
+    Defining variables within the translate function is a bit of a guess work,
+    using following rules:
     *   By default, a variable is a 'double'.
     *   Variable in a for loop is an int.
@@ -19,24 +16,32 @@
         variable within the brackets is integer. For example, in the
         reference 'var1[var2]', var1 is a double array, and var2 is an integer.
-    *   Assignment to an argument makes that argument an array, and the index in
-        that assignment is 0.
-        For example, the following python code
+    *   Assignment to an argument makes that argument an array, and the index
+        in that assignment is 0.
+        For example, the following python code::
             def func(arg1, arg2):
                 arg2 = 17.
-        is translated to the following C code
+        is translated to the following C code::
             double func(double arg1)
             {
                 arg2[0] = 17.0;
             }
-        For example, the following python code is translated to the following C code
+        For example, the following python code is translated to the
+        following C code::
+
             def func(arg1, arg2):          double func(double arg1) {
                 arg2 = 17.                      arg2[0] = 17.0;
                                             }
-    *   All functions are defined as double, even if there is no return statement.
-
-
+    *   All functions are defined as double, even if there is no
+        return statement.
+
+Based on codegen.py:
+
+    :copyright: Copyright 2008 by Armin Ronacher.
+    :license: BSD.
+"""
+"""
 Update Notes
 ============
-11/22 14:15, O.E.   Each 'visit_*' method is to build a C statement string. It
+11/22/2017, O.E.   Each 'visit_*' method is to build a C statement string. It
                     shold insert 4 blanks per indentation level.
                     The 'body' method will combine all the strings, by adding
@@ -52,5 +57,5 @@
 12/07/2017, OE: Translation of integer division, '\\' in python, implemented
                 in translate_integer_divide, called from visit_BinOp
-12/07/2017, OE: C variable definition handled in 'define_C_Vars'
+12/07/2017, OE: C variable definition handled in 'define_c_vars'
               : Python integer division, '//', translated to C in
                 'translate_integer_divide'
@@ -59,4 +64,14 @@
 12/18/2017, OE: Added call to 'add_current_line()' at the beginning
                 of visit_Return
+01/4/2018, O.E. Added functions 'get_files_names()', , 'print_usage()'. The get_files_names()
+                function retrieves the in/out file names form the command line, and returns
+                true/false if the number of parameters is valid. In case of no input
+                parameters, usage is prompt and the program terminates.
+01/4/2018, O.E. 'translate(functions, constants=None)' returns string, instaed of a list
+01/04/2017 O.E. Fixed bug in 'visit_If': visiting node.orelse in case else exists.
+01/05/2018 O.E. New class C_Vector defined. It holds name, type, size and initial values.
+                Assignment to that class in 'sequence_visit'.
+                Reading and inserting declaration in 'insert_c_vars'
+
 
 """
@@ -102,26 +117,13 @@
 
 
-def to_source(node, func_name, constants=None):
-    """This function can convert a node tree back into python sourcecode.
-    This is useful for debugging purposes, especially if you're dealing with
-    custom asts not generated by python itself.
-
-    It could be that the sourcecode is evaluable when the AST itself is not
-    compilable / evaluable.  The reason for this is that the AST contains some
-    more data than regular sourcecode does, which is dropped during
-    conversion.
-
-    Each level of indentation is replaced with `indent_with`.  Per default this
-    parameter is equal to four spaces as suggested by PEP 8, but it might be
-    adjusted to match the application's styleguide.
-
-    If `add_line_information` is set to `True` comments for the line numbers
-    of the nodes are added to the output.  This can be used to spot wrong line
-    number information of statement nodes.
+def to_source(tree, constants=None, fname=None, lineno=0):
     """
-    generator = SourceGenerator(' ' * 4, False, constants)
-    generator.visit(node)
-
-    return ''.join(generator.c_proc)
+    This function can convert a syntax tree into C sourcecode.
+    """
+    generator = SourceGenerator(constants=constants, fname=fname, lineno=lineno)
+    generator.visit(tree)
+    c_code = "\n".join(generator.c_proc)
+    c_code = "".join(generator.c_proc)
+    return (c_code, generator.warnings)
 
 def isevaluable(s):
@@ -129,6 +131,43 @@
         eval(s)
         return True
-    except:
+    except Exception:
         return False
+
+class C_Vector():
+    def __init__(self):
+        self.size = 0
+        self.type = "double"
+        self.values = []
+        self.assign_line = -1
+        self.name = ""
+
+    def get_leading_space(self, indent_with="    ", indent_level = 1):
+        leading_space = ""
+        for n in range(indent_level):
+            leading_space += indent_with
+        return leading_space
+        
+    def item_declare_string(self, indent_with="    ", indent_level = 1):
+        declare_string = self.name + "[" + str(len(self.values)) + "]"
+        return declare_string
+    
+    def declare_string(self, indent_with="    ", indent_level = 1):
+        declare_string = self.get_leading_space(indent_with, indent_level)
+        declare_string += self.type + " " + item_declare_string(indent_with, indent_level)
+#        self.name + "[" + str(len(self.values)) + "];\n"
+        return declare_string
+    
+    def get_assign(self, indent_with="    ", indent_level = 1):
+        assign_loop = []
+        c_string = self.get_leading_space(indent_with, indent_level - 1)
+        c_string += "for (n=0 ; n < " + str(len(self.values)) + " ; n++) {"
+        assign_loop.append(c_string)
+        for n,value in enumerate(self.values):
+            c_string = self.get_leading_space(indent_with, indent_level)
+            c_string += self.name + "[" + str(n) + "] = " + str(value) + ";"
+            assign_loop.append(c_string)
+        c_string = self.get_leading_space(indent_with, indent_level - 1) + "}"
+        assign_loop.append(c_string)
+        return (assign_loop)
 
 class SourceGenerator(NodeVisitor):
@@ -138,5 +177,6 @@
     """
 
-    def __init__(self, indent_with, add_line_information=False, constants=None):
+    def __init__(self, indent_with="    ", add_line_information=False,
+                 constants=None, fname=None, lineno=0):
         self.result = []
         self.indent_with = indent_with
@@ -144,27 +184,33 @@
         self.indentation = 0
         self.new_lines = 0
+
+        # for C
         self.c_proc = []
-        # for C
         self.signature_line = 0
         self.arguments = []
-        self.name = ""
+        self.current_function = ""
+        self.fname = fname
+        self.lineno_offset = lineno
         self.warnings = []
-        self.Statements = []
+        self.statements = []
         self.current_statement = ""
-        self.strMethodSignature = ""
-        self.C_Vars = []
-        self.C_IntVars = []
-        self.MathIncludeed = False
-        self.C_Pointers = []
-        self.C_DclPointers = []
-        self.C_Functions = []
-        self.C_Vectors = []
-        self.C_Constants = constants
-        self.SubRef = False
-        self.InSubscript = False
-        self.Tuples = []
+        # TODO: use set rather than list for c_vars, ...
+        self.c_vars = []
+        self.c_int_vars = []
+        self.c_pointers = []
+        self.c_dcl_pointers = []
+        self.c_functions = []
+        self.c_vectors = []
+        self.c_constants = constants if constants is not None else {}
+        self.in_subref = False
+        self.in_subscript = False
+        self.tuples = []
         self.required_functions = []
         self.is_sequence = False
         self.visited_args = False
+        self.inside_if = False
+        self.C_Vectors = []
+        self.assign_target = ""
+        self.assign_c_vector = []
 
     def write_python(self, x):
@@ -176,14 +222,11 @@
         self.result.append(x)
 
-    def write_c(self, x):
-        self.current_statement += x
-
-    def add_c_line(self, x):
-        string = ''
-        for _ in range(self.indentation):
-            string += ("    ")
-        string += str(x)
-        self.c_proc.append(str(string + "\n"))
-        x = ''
+    def write_c(self, statement):
+        # TODO: build up as a list rather than adding to string
+        self.current_statement += statement
+
+    def add_c_line(self, line):
+        indentation = self.indent_with * self.indentation
+        self.c_proc.append("".join((indentation, line, "\n")))
 
     def add_current_line(self):
@@ -192,9 +235,9 @@
             self.current_statement = ''
 
-    def AddUniqueVar(self, new_var):
-        if new_var not in self.C_Vars:
-            self.C_Vars.append(str(new_var))
-
-    def WriteSincos(self, node):
+    def add_unique_var(self, new_var):
+        if new_var not in self.c_vars:
+            self.c_vars.append(str(new_var))
+
+    def write_sincos(self, node):
         angle = str(node.args[0].id)
         self.write_c(node.args[1].id + " = sin(" + angle + ");")
@@ -203,5 +246,30 @@
         self.add_current_line()
         for arg in node.args:
-            self.AddUniqueVar(arg.id)
+            self.add_unique_var(arg.id)
+
+    def write_print(self, node):
+        self.write_c ("printf (")
+        c_str = self.current_statement
+        self.current_statement = ""
+        self.visit(node.args[0])
+        print_params = self.current_statement # save print agruments
+        self.current_statement = c_str
+        print_params = print_params[1:(len(print_params) - 1)] # remove parentheses
+        prcnt = print_params.rfind('%')
+        if prcnt >= 0:
+            format_string = print_params[0:prcnt-1].strip()
+            format_string = format_string[1:len(format_string) - 1]
+            var_string = print_params[prcnt+1:len(print_params)].strip()
+        else:
+            format_string = print_params
+            var_string = ""
+        format_string= format_string[:len(format_string)]
+        self.write_c('"' + format_string + '\\n"')
+        if (len(var_string) > 0):
+            self.write_c(', ' + var_string)
+        self.write_c(");")
+        self.add_current_line()
+
+
 
     def newline(self, node=None, extra=0):
@@ -211,5 +279,5 @@
             self.new_lines = 1
         if self.current_statement:
-            self.Statements.append(self.current_statement)
+            self.statements.append(self.current_statement)
             self.current_statement = ''
 
@@ -258,6 +326,6 @@
                 except AttributeError:
                     arg_name = arg.id
-                w_str = ("Default Parameters are unknown to C: '%s = %s"
-                         % arg_name, str(default.n))
+                w_str = ("Default Parameters are unknown to C: '%s = %s" \
+                        % (arg_name, str(default.n)))
                 self.warnings.append(w_str)
 
@@ -278,5 +346,5 @@
             self.visit(node.msg)
 
-    def define_C_Vars(self, target):
+    def define_c_vars(self, target):
         if hasattr(target, 'id'):
         # a variable is considered an array if it apears in the agrument list
@@ -287,13 +355,13 @@
         #  return
         #
-            if target.id not in self.C_Vars:
+            if target.id not in self.c_vars:
                 if target.id in self.arguments:
                     idx = self.arguments.index(target.id)
                     new_target = self.arguments[idx] + "[0]"
-                    if new_target not in self.C_Pointers:
+                    if new_target not in self.c_pointers:
                         target.id = new_target
-                        self.C_Pointers.append(self.arguments[idx])
+                        self.c_pointers.append(self.arguments[idx])
                 else:
-                    self.C_Vars.append(target.id)
+                    self.c_vars.append(target.id)
 
     def add_semi_colon(self):
@@ -308,35 +376,46 @@
             if idx:
                 self.write_c(' = ')
-            self.define_C_Vars(target)
+            self.define_c_vars(target)
             self.visit(target)
-        if self.Tuples:
-            tplTargets = list(self.Tuples)
-            del self.Tuples[:]
+            if hasattr(target,'id'):
+                self.assign_target = target.id
+        # Capture assigned tuple names, if any
+        targets = self.tuples[:]
+        del self.tuples[:]
         self.write_c(' = ')
         self.is_sequence = False
         self.visited_args = False
         self.visit(node.value)
-        self.add_semi_colon()
-        self.add_current_line()
-        for n, item in enumerate(self.Tuples):
-            self.visit(tplTargets[n])
-            self.write_c(' = ')
-            self.visit(item)
+        if len(self.assign_c_vector):
+            for c_statement in self.assign_c_vector:
+                self.add_c_line (c_statement)
+#                self.c_proc.append(c_statement)
+            self.assign_c_vector.clear()
+        else:
             self.add_semi_colon()
             self.add_current_line()
-        if self.is_sequence and not self.visited_args:
-            for target in node.targets:
-                if hasattr(target, 'id'):
-                    if target.id in self.C_Vars and target.id not in self.C_DclPointers:
-                        if target.id not in self.C_DclPointers:
-                            self.C_DclPointers.append(target.id)
-                            if target.id in self.C_Vars:
-                                self.C_Vars.remove(target.id)
+        # Assign tuples to tuples, if any
+        # TODO: doesn't handle swap:  a,b = b,a
+            for target, item in zip(targets, self.tuples):
+                self.visit(target)
+                self.write_c(' = ')
+                self.visit(item)
+                self.add_semi_colon()
+                self.add_current_line()
+            if self.is_sequence and not self.visited_args:
+                for target in node.targets:
+                    if hasattr(target, 'id'):
+                        if target.id in self.c_vars and target.id not in self.c_dcl_pointers:
+                            if target.id not in self.c_dcl_pointers:
+                                self.c_dcl_pointers.append(target.id)
+                                if target.id in self.c_vars:
+                                    self.c_vars.remove(target.id)
         self.current_statement = ''
+        self.assign_target = ''
 
     def visit_AugAssign(self, node):
-        if node.target.id not in self.C_Vars:
+        if node.target.id not in self.c_vars:
             if node.target.id not in self.arguments:
-                self.C_Vars.append(node.target.id)
+                self.c_vars.append(node.target.id)
         self.visit(node.target)
         self.write_c(' ' + BINOP_SYMBOLS[type(node.op)] + '= ')
@@ -346,4 +425,5 @@
 
     def visit_ImportFrom(self, node):
+        return  # import ignored
         self.newline(node)
         self.write_python('from %s%s import ' %('.' * node.level, node.module))
@@ -354,4 +434,5 @@
 
     def visit_Import(self, node):
+        return  # import ignored
         self.newline(node)
         for item in node.names:
@@ -363,17 +444,12 @@
         self.generic_visit(node)
 
-    def listToDeclare(self, vars):
-        return ", ".join(vars)
-
-    def write_C_Pointers(self, start_var):
-        if self.C_DclPointers:
+    def write_c_pointers(self, start_var):
+        if self.c_dcl_pointers:
             var_list = []
-            for c_ptr in self.C_DclPointers:
-                if(len(vars) > 0):
-                    vars += ", "
+            for c_ptr in self.c_dcl_pointers:
                 if c_ptr not in self.arguments:
                     var_list.append("*" + c_ptr)
-                if c_ptr in self.C_Vars:
-                    self.C_Vars.remove(c_ptr)
+                if c_ptr in self.c_vars:
+                    self.c_vars.remove(c_ptr)
             if var_list:
                 c_dcl = "    double " + ", ".join(var_list) + ";\n"
@@ -382,71 +458,87 @@
         return start_var
 
-    def insert_C_Vars(self, start_var):
-        fLine = False
-        start_var = self.write_C_Pointers(start_var)
-        if self.C_IntVars:
-            for var in self.C_IntVars:
-                if var in self.C_Vars:
-                    self.C_Vars.remove(var)
-            s = self.listToDeclare(self.C_IntVars)
-            self.c_proc.insert(start_var, "    int " + s + ";\n")
-            fLine = True
+    def insert_c_vars(self, start_var):
+        have_decls = False
+        start_var = self.write_c_pointers(start_var)
+        if self.c_int_vars:
+            for var in self.c_int_vars:
+                if var in self.c_vars:
+                    self.c_vars.remove(var)
+            decls = ", ".join(self.c_int_vars)
+            self.c_proc.insert(start_var, "    int " + decls + ";\n")
+            have_decls = True
             start_var += 1
-
-        if self.C_Vars:
-            s = self.listToDeclare(self.C_Vars)
-            self.c_proc.insert(start_var, "    double " + s + ";\n")
-            fLine = True
+        if len(self.C_Vectors) > 0:
+            vec_declare = []
+            for c_vec in self.C_Vectors:
+                item_declare = c_vec.item_declare_string()
+                if item_declare not in vec_declare:
+                    vec_declare.append (item_declare)
+                if c_vec.name in self.c_vars:
+                    self.c_vars.remove(c_vec.name)
+            all_declare = "    double " + ", ".join (vec_declare) + ";\n"
+            self.c_proc.insert(start_var, all_declare)
             start_var += 1
 
-        if self.C_Vectors:
-            s = self.listToDeclare(self.C_Vectors)
-            for n in range(len(self.C_Vectors)):
-                name = "vec" + str(n+1)
-                c_dcl = "    double " + name + "[] = {" + self.C_Vectors[n] + "};"
-                self.c_proc.insert(start_var, c_dcl + "\n")
+        if self.c_vars:
+            decls = ", ".join(self.c_vars)
+            self.c_proc.insert(start_var, "    double " + decls + ";\n")
+            have_decls = True
+            start_var += 1
+
+        if self.c_vectors:
+            for vec_number, vec_value  in enumerate(self.c_vectors):
+                name = "vec" + str(vec_number + 1)
+                decl = "    double " + name + "[] = {" + vec_value + "};"
+                self.c_proc.insert(start_var, decl + "\n")
                 start_var += 1
 
-        del self.C_Vars[:]
-        del self.C_IntVars[:]
-        del self.C_Vectors[:]
-        del self.C_Pointers[:]
-        self.C_DclPointers
-        if fLine:
+        del self.c_vars[:]
+        del self.c_int_vars[:]
+        del self.c_vectors[:]
+        del self.c_pointers[:]
+        del self.c_dcl_pointers[:]
+        if have_decls:
             self.c_proc.insert(start_var, "\n")
 
-    def InsertSignature(self):
+    def insert_signature(self):
         arg_decls = []
         for arg in self.arguments:
             decl = "double " + arg
-            if arg in self.C_Pointers:
+            if arg in self.c_pointers:
                 decl += "[]"
             arg_decls.append(decl)
         args_str = ", ".join(arg_decls)
-        self.strMethodSignature = 'double ' + self.name + '(' + args_str + ")"
+        method_sig = 'double ' + self.current_function + '(' + args_str + ")"
         if self.signature_line >= 0:
-            self.c_proc.insert(self.signature_line, self.strMethodSignature)
+            self.c_proc.insert(self.signature_line, method_sig)
 
     def visit_FunctionDef(self, node):
+        if self.current_function:
+            self.unsupported(node, "function within a function")
+        self.current_function = node.name
+
+        warning_index = len(self.warnings)
         self.newline(extra=1)
         self.decorators(node)
         self.newline(node)
         self.arguments = []
-        self.name = node.name
-        #if self.name not in self.required_functions[0]:
-        #   return
-        #print("Parsing '" + self.name + "'")
-
         self.visit(node.args)
         # for C
         self.signature_line = len(self.c_proc)
-        #self.add_c_line(self.strMethodSignature)
         self.add_c_line("\n{")
         start_vars = len(self.c_proc) + 1
         self.body(node.body)
         self.add_c_line("}\n")
-        self.InsertSignature()
-        self.insert_C_Vars(start_vars)
-        self.C_Pointers = []
+        self.insert_signature()
+        self.insert_c_vars(start_vars)
+#        self.c_pointers = []
+        self.c_pointers.clear()
+        self.C_Vectors.clear()
+        self.current_function = ""
+        if (warning_index != len(self.warnings)):
+            self.warnings.insert(warning_index, "Warning in function '" + node.name + "':")
+            self.warnings.append("Note: C compilation will fail")
+
 
     def visit_ClassDef(self, node):
@@ -484,4 +576,6 @@
 
     def visit_If(self, node):
+        self.add_current_line()
+        self.inside_if = True
         self.write_c('if ')
         self.visit(node.test)
@@ -507,26 +601,10 @@
                 self.newline()
                 self.write_c('else {')
-                self.body(node.body)
+                self.body(node.orelse)
                 self.add_c_line('}')
                 break
-
-    def getNodeLineNo(self, node):
-        line_number = -1
-        if hasattr(node, 'value'):
-            line_number = node.value.lineno
-        elif hasattr(node, 'iter'):
-            if hasattr(node.iter, 'lineno'):
-                line_number = node.iter.lineno
-        return line_number
-
-    def GetNodeAsString(self, node):
-        res = ''
-        if hasattr(node, 'n'):
-            res = str(node.n)
-        elif hasattr(node, 'id'):
-            res = node.id
-        return res
-
-    def GetForRange(self, node):
+        self.inside_if = False
+
+    def get_for_range(self, node):
         stop = ""
         start = '0'
@@ -553,4 +631,8 @@
         return start, stop, step
 
+    def add_c_int_var (self, iterator):
+        if iterator not in self.c_int_vars:
+            self.c_int_vars.append(iterator)
+
     def visit_For(self, node):
         # node: for iterator is stored in node.target.
@@ -565,7 +647,6 @@
                     iterator = self.current_statement
                     self.current_statement = ''
-                    if iterator not in self.C_IntVars:
-                        self.C_IntVars.append(iterator)
-                    start, stop, step = self.GetForRange(node)
+                    self.add_c_int_var (iterator)
+                    start, stop, step = self.get_for_range(node)
                     self.write_c("for(" + iterator + "=" + str(start) +
                                  " ; " + iterator + " < " + str(stop) +
@@ -575,5 +656,5 @@
                     fForDone = True
         if not fForDone:
-            line_number = self.getNodeLineNo(node)
+            # Generate the statement that is causing the error
             self.current_statement = ''
             self.write_c('for ')
@@ -582,7 +663,6 @@
             self.visit(node.iter)
             self.write_c(':')
-            errStr = "Conversion Error in function " + self.name + ", Line #" + str(line_number)
-            errStr += "\nPython for expression not supported: '" + self.current_statement + "'"
-            raise Exception(errStr)
+            # report the error
+            self.unsupported("unsupported " + self.current_statement)
 
     def visit_While(self, node):
@@ -590,8 +670,11 @@
         self.write_c('while ')
         self.visit(node.test)
-        self.write_c(':')
+        self.write_c(' { ')
         self.body_or_else(node)
+        self.write_c('}')
+        self.add_current_line()
 
     def visit_With(self, node):
+        self.unsupported(node)
         self.newline(node)
         self.write_python('with ')
@@ -605,7 +688,9 @@
     def visit_Pass(self, node):
         self.newline(node)
-        self.write_python('pass')
+        #self.write_python('pass')
 
     def visit_Print(self, node):
+        # TODO: print support would be nice, though hard to do
+        self.unsupported(node)
         # CRUFT: python 2.6 only
         self.newline(node)
@@ -625,4 +710,5 @@
 
     def visit_Delete(self, node):
+        self.unsupported(node)
         self.newline(node)
         self.write_python('del ')
@@ -633,4 +719,5 @@
 
     def visit_TryExcept(self, node):
+        self.unsupported(node)
         self.newline(node)
         self.write_python('try:')
@@ -640,4 +727,5 @@
 
     def visit_TryFinally(self, node):
+        self.unsupported(node)
         self.newline(node)
         self.write_python('try:')
@@ -648,4 +736,5 @@
 
     def visit_Global(self, node):
+        self.unsupported(node)
         self.newline(node)
         self.write_python('global ' + ', '.join(node.names))
@@ -676,4 +765,5 @@
 
     def visit_Raise(self, node):
+        self.unsupported(node)
         # CRUFT: Python 2.6 / 3.0 compatibility
         self.newline(node)
@@ -697,7 +787,5 @@
 
     def visit_Attribute(self, node):
-        errStr = "Conversion Error in function " + self.name + ", Line #" + str(node.value.lineno)
-        errStr += "\nPython expression not supported: '" + node.value.id + "." + node.attr + "'"
-        raise Exception(errStr)
+        self.unsupported(node, "attribute reference a.b not supported")
         self.visit(node.value)
         self.write_python('.' + node.attr)
@@ -711,6 +799,6 @@
                 want_comma.append(True)
         if hasattr(node.func, 'id'):
-            if node.func.id not in self.C_Functions:
-                self.C_Functions.append(node.func.id)
+            if node.func.id not in self.c_functions:
+                self.c_functions.append(node.func.id)
             if node.func.id == 'abs':
                 self.write_c("fabs ")
@@ -718,5 +806,8 @@
                 self.write_c('(int) ')
             elif node.func.id == "SINCOS":
-                self.WriteSincos(node)
+                self.write_sincos(node)
+                return
+            elif node.func.id == "print":
+                self.write_print(node)
                 return
             else:
@@ -724,5 +815,4 @@
         else:
             self.visit(node.func)
-#self.C_Functions
         self.write_c('(')
         for arg in node.args:
@@ -744,9 +834,11 @@
                 self.write_c('**')
                 self.visit(node.kwargs)
-        self.write_c(');')
+        self.write_c(')')
+        if (self.inside_if == False):
+            self.write_c(';')
 
     def visit_Name(self, node):
         self.write_c(node.id)
-        if node.id in self.C_Pointers and not self.SubRef:
+        if node.id in self.c_pointers and not self.in_subref:
             self.write_c("[0]")
         name = ""
@@ -756,12 +848,12 @@
         else:
             name = node.id
-        # add variable to C_Vars if it ins't there yet, not an argument and not a number
-        if (name not in self.C_Functions and name not in self.C_Vars and
-                name not in self.C_IntVars and name not in self.arguments and
-                name not in self.C_Constants and not name.isdigit()):
-            if self.InSubscript:
-                self.C_IntVars.append(node.id)
+        # add variable to c_vars if it ins't there yet, not an argument and not a number
+        if (name not in self.c_functions and name not in self.c_vars and
+                name not in self.c_int_vars and name not in self.arguments and
+                name not in self.c_constants and not name.isdigit()):
+            if self.in_subscript:
+                self.add_c_int_var (self, node.id)
             else:
-                self.C_Vars.append(node.id)
+                self.c_vars.append(node.id)
 
     def visit_Str(self, node):
@@ -777,5 +869,5 @@
         for idx, item in enumerate(node.elts):
             if idx:
-                self.Tuples.append(item)
+                self.tuples.append(item)
             else:
                 self.visit(item)
@@ -784,4 +876,5 @@
         def visit(self, node):
             self.is_sequence = True
+            c_vec = C_Vector()
             s = ""
             for idx, item in enumerate(node.elts):
@@ -789,11 +882,28 @@
                     s += ', '
                 if hasattr(item, 'id'):
-                    s += item.id
+                    c_vec.values.append(item.id)
+#                    s += item.id
                 elif hasattr(item, 'n'):
-                    s += str(item.n)
-            if s:
-                self.C_Vectors.append(s)
-                vec_name = "vec"  + str(len(self.C_Vectors))
-                self.write_c(vec_name)
+                    c_vec.values.append(item.n)
+#                    s += str(item.n)
+                else:
+                    temp = self.current_statement
+                    self.current_statement = ""
+                    self.visit(item)
+                    c_vec.values.append(self.current_statement)
+#                    s += self.current_statement
+                    self.current_statement = temp
+            if (self.assign_target):
+                self.add_c_int_var ('n')
+                c_vec.name = self.assign_target
+                self.C_Vectors.append(c_vec)
+                assign_strings = c_vec.get_assign()
+                for assign_str in assign_strings:
+                    self.assign_c_vector.append(assign_str)
+#                    self.add_c_line(assign_str)
+#            if s:
+#                self.c_vectors.append(s)
+#                vec_name = "vec"  + str(len(self.c_vectors))
+#                self.write_c(vec_name)
         return visit
 
@@ -803,4 +913,5 @@
 
     def visit_Dict(self, node):
+        self.unsupported(node)
         self.write_python('{')
         for idx, (key, value) in enumerate(zip(node.keys, node.values)):
@@ -901,14 +1012,14 @@
 
     def visit_Subscript(self, node):
-        if node.value.id not in self.C_Constants:
-            if node.value.id not in self.C_Pointers:
-                self.C_Pointers.append(node.value.id)
-        self.SubRef = True
+        if node.value.id not in self.c_constants:
+            if node.value.id not in self.c_pointers:
+                self.c_pointers.append(node.value.id)
+        self.in_subref = True
         self.visit(node.value)
-        self.SubRef = False
+        self.in_subref = False
         self.write_c('[')
-        self.InSubscript = True
+        self.in_subscript = True
         self.visit(node.slice)
-        self.InSubscript = False
+        self.in_subscript = False
         self.write_c(']')
 
@@ -931,8 +1042,10 @@
 
     def visit_Yield(self, node):
+        self.unsupported(node)
         self.write_python('yield ')
         self.visit(node.value)
 
     def visit_Lambda(self, node):
+        self.unsupported(node)
         self.write_python('lambda ')
         self.visit(node.args)
@@ -941,4 +1054,5 @@
 
     def visit_Ellipsis(self, node):
+        self.unsupported(node)
         self.write_python('Ellipsis')
 
@@ -960,4 +1074,5 @@
 
     def visit_DictComp(self, node):
+        self.unsupported(node)
         self.write_python('{')
         self.visit(node.key)
@@ -968,10 +1083,23 @@
         self.write_python('}')
 
+    def visit_NameConstant (self, node):
+        if (hasattr (node, "value")):
+            if (node.value == True):
+                val = "1"
+            elif node.value == False:
+                val = "0"
+            else:
+                val = ""
+            if (len(val) > 0):
+                self.write_c("(" + val + ")")
+
     def visit_IfExp(self, node):
+        self.write_c('(')
+        self.visit(node.test)
+        self.write_c(' ? ')
         self.visit(node.body)
-        self.write_c(' if ')
-        self.visit(node.test)
-        self.write_c(' else ')
+        self.write_c(' : ')
         self.visit(node.orelse)
+        self.write_c(');')
 
     def visit_Starred(self, node):
@@ -988,4 +1116,5 @@
 
     def visit_alias(self, node):
+        self.unsupported(node)
         self.write_python(node.name)
         if node.asname is not None:
@@ -1005,4 +1134,24 @@
     def visit_arguments(self, node):
         self.signature(node)
+
+    def unsupported(self, node, message=None):
+        if hasattr(node, "value"):
+            lineno = node.value.lineno
+        elif hasattr(node, "iter"):
+            lineno = node.iter.lineno
+        else:
+            #print(dir(node))
+            lineno = 0
+
+        lineno += self.lineno_offset
+        if self.fname:
+            location = "%s(%d)" % (self.fname, lineno)
+        else:
+            location = "%d" % (self.fname, lineno)
+        if self.current_function:
+            location += ", function %s" % self.current_function
+        if message is None:
+            message = node.__class__.__name__ + " syntax not supported"
+        raise SyntaxError("[%s] %s" % (location, message))
 
 def print_function(f=None):
@@ -1018,44 +1167,143 @@
         print(tree_source)
 
-def translate(functions, constants=0):
+def define_constant(name, value, block_size=1):
+    # type: (str, any, int) -> str
+    """
+    Convert a python constant into a C constant of the same name.
+
+    Returns the C declaration of the constant as a string, possibly containing
+    line feeds.  The string will not be indented.
+
+    Supports int, double and sequences of double.
+    """
+    const = "constant "  # OpenCL needs globals to be constant
+    if isinstance(value, int):
+        parts = [const + "int ", name, " = ", "%d"%value, ";"]
+    elif isinstance(value, float):
+        parts = [const + "double ", name, " = ", "%.15g"%value, ";"]
+    else:
+        try:
+            len(value)
+        except TypeError:
+            raise TypeError("constant %s must be int, float or [float, ...]"%name)
+        # extend constant arrays to a multiple of 4; not sure if this
+        # is necessary, but some OpenCL targets broke if the number
+        # of parameters in the parameter table was not a multiple of 4,
+        # so do it for all constant arrays to be safe.
+        if len(value)%block_size != 0:
+            value = list(value) + [0.]*(block_size - len(value)%block_size)
+        elements = ["%.15g"%v for v in value]
+        parts = [const + "double ", name, "[]", " = ",
+                 "{\n   ", ", ".join(elements), "\n};"]
+
+    return "".join(parts)
+
+
+# Modified from the following:
+#
+#    http://code.activestate.com/recipes/578272-topological-sort/
+#    Copyright (C) 2012 Sam Denton
+#    License: MIT
+def ordered_dag(dag):
+    # type: (Dict[T, Set[T]]) -> Iterator[T]
+    """
+    Given a dag defined by a dictionary of {k1: [k2, ...]} yield keys
+    in order such that every key occurs after the keys it depends upon.
+
+    This is an iterator not a sequence.  To reverse it use::
+
+        reversed(tuple(ordered_dag(dag)))
+
+    Raise an error if there are any cycles.
+
+    Keys are arbitrary hashable values.
+    """
+    # Local import to make the function stand-alone, and easier to borrow
+    from functools import reduce
+
+    dag = dag.copy()
+
+    # make leaves depend on the empty set
+    leaves = reduce(set.union, dag.values()) - set(dag.keys())
+    dag.update({node: set() for node in leaves})
+    while True:
+        leaves = set(node for node, links in dag.items() if not links)
+        if not leaves:
+            break
+        for node in leaves:
+            yield node
+        dag = {node: (links-leaves)
+               for node, links in dag.items() if node not in leaves}
+    if dag:
+        raise ValueError("Cyclic dependes exists amongst these items:\n%s"
+                         % ", ".join(str(node) for node in dag.keys()))
+
+def translate(functions, constants=None):
+    # type: (List[(str, str, int)], Dict[str, any]) -> List[str]
+    """
+    Convert a set of functions
+    """
     snippets = []
-    #snippets.append("#include <math.h>")
-    #snippets.append("")
-    for source, fname, line_no in functions:
-        line_directive = '#line %d "%s"'%(line_no, fname.replace('\\', '\\\\'))
+    snippets.append("#include <math.h>")
+    snippets.append("")
+    warnings = []
+    for source, fname, lineno in functions:
+        line_directive = '#line %d "%s"'%(lineno, fname.replace('\\', '\\\\'))
         snippets.append(line_directive)
         tree = ast.parse(source)
-        # in the future add filename, offset, constants
-        c_code = to_source(tree, functions, constants)
+        c_code,w = to_source(tree, constants=constants, fname=fname, lineno=lineno)
+        if w:
+            warnings.append ("\n".join(w))
         snippets.append(c_code)
-    return snippets
+    return "\n".join(snippets),warnings
+#    return snippets
+
+def print_usage ():
+        print("""\
+            Usage: python py2c.py <infile> [<outfile>]
+            if outfile is omitted, output file is '<infile>.c'
+        """)
+
+def get_files_names ():
+    import os
+    fname_in = fname_out = ""
+    valid_params =  len(sys.argv) > 1
+    if (valid_params == False):
+        print_usage()
+    else:
+        fname_in = sys.argv[1]
+        if len(sys.argv) == 2:
+            fname_base = os.path.splitext(fname_in)[0]
+            fname_out = str(fname_base) + '.c'
+        else:
+            fname_out = sys.argv[2]
+    return valid_params, fname_in,fname_out
 
 def main():
-    import os
     print("Parsing...using Python" + sys.version)
-    if len(sys.argv) == 1:
-        print("""\
-Usage: python py2c.py <infile> [<outfile>]
-
-if outfile is omitted, output file is '<infile>.c'
-""")
+    valid_params, fname_in, fname_out = get_files_names ()
+    if (valid_params == False):
+        print("Input parameters error.\nExiting")
         return
 
-    fname_in = sys.argv[1]
-    if len(sys.argv) == 2:
-        fname_base = os.path.splitext(fname_in)[0]
-        fname_out = str(fname_base) + '.c'
-    else:
-        fname_out = sys.argv[2]
-
     with open(fname_in, "r") as python_file:
-        code = python_file.read()
-
-    translation = translate([code, fname_in, 1])[0]
+            code = python_file.read()
+    name = "gauss"
+    code = (code
+            .replace(name+'.n', 'GAUSS_N')
+            .replace(name+'.z', 'GAUSS_Z')
+            .replace(name+'.w', 'GAUSS_W'))
+
+    translation,warnings = translate([(code, fname_in, 1)])
 
     with open(fname_out, "w") as file_out:
-        file_out.write(translation)
+        file_out.write(str(translation))
+    if warnings:
+        print("".join(str(warnings[0])))
     print("...Done")
 
 if __name__ == "__main__":
-    main()
+    try:
+        main()
+    except Exception as excp:
+        print ("Error:\n" + str(excp.args))
