Index: tcc4tcl.tcl
==================================================================
--- tcc4tcl.tcl
+++ tcc4tcl.tcl
@@ -125,10 +125,193 @@
 
 	proc _delete {handle} {
 		rename $handle ""
 		unset $handle
 	}
+
+	proc _proc {handle cname adefs rtype body args} {
+		# Convert body into a C-style string
+		binary scan $body H* cbody
+		set cbody [regsub -all {..} $cbody {\\x&}]
+
+		# Parse optional arguments
+		foreach {argname argval} $args {
+			switch -- $argname {
+				"-error" {
+					set returnErrorValue $argval
+				}
+			}
+		}
+
+		# Argument definitions (in C style) initialization
+		set adefs_c [list]
+
+		# Names of all arguments initialization
+		set args [list]
+
+		# If we aren't creating a new interp, it must be the first argument
+		# If the definition of this proc already includes the interp
+		# argument, use it -- otherwise add one
+		if {[lindex $adefs 0] != "Tcl_Interp*"} {
+			set newInterp 1
+		} else {
+			set newInterp 0
+			set interp_name [lindex $adefs 1]
+		}
+
+		# Create the C-style argument definition
+		foreach {type var} $adefs {
+			lappend adefs_c [list $type $var]
+			set types($var) $type
+			lappend args $var
+		}
+
+		set adefs_c [join $adefs_c {, }]
+
+		# Determine how to return in failure
+		if {$rtype != "void"} {
+			if {[info exists returnErrorValue]} {
+				set return_failure "return(${returnErrorValue})"
+			} else {
+				switch -- $rtype {
+					int - long - Tcl_WideInt {
+						set return_failure "return(-1)"
+					}
+					ok {
+						set return_failure "return(TCL_ERROR)"
+					}
+					double - float {
+						set return_failure "return(NaN)"
+					}
+					default {
+						set return_failure "return(NULL)"
+					}
+				}
+			}
+		} else {
+			set return_failure "return"
+		}
+
+		# Define the C function
+		_ccode $handle "$rtype $cname\($adefs_c) \{"
+
+		## Define the Tcl return value checking variable
+		_ccode $handle "    int tclrv;"
+
+		## If the interpreters return value is relevant, create a variable to store it
+		if {$rtype != "ok" && $rtype != "void"} {
+			_ccode $handle "    Tcl_Obj *rv_interp;"
+		}
+
+		## If we are returning a value, declare a variable for that
+		if {$rtype != "void"} {
+			_ccode $handle "    $rtype rv;"
+		}
+
+		## If we need to create a new interpreter, do so
+		if {$newInterp} {
+			set interp_name "ip"
+			_ccode $handle "    Tcl_Interp *${interp_name};"
+
+			set args_nointerp $args
+		} else {
+			set args_nointerp [lrange $args 1 end]
+		}
+
+		# Declare Tcl_Obj variables
+		_ccode $handle "    Tcl_Obj *_[join $args_nointerp {, *_}];"
+
+		_ccode $handle ""
+
+		if {$newInterp} {
+			_ccode $handle "    ${interp_name}  = Tcl_CreateInterp();"
+			_ccode $handle "    if (!${interp_name}) $return_failure;"
+			_ccode $handle ""
+		}
+
+		# Process all arguments
+		foreach arg $args_nointerp {
+			set type $types($arg)
+			switch -- $type {
+				int - long - Tcl_WideInt - float - double {
+					switch -- $type {
+						float {
+							set convCmd Double
+						}
+						Tcl_WideInt {
+							set convCmd WideInt
+						}
+						default {
+							set convCmd [string totitle $type]
+						}
+					}
+
+					_ccode $handle "    _$arg = Tcl_New${convCmd}Obj($arg);"
+					_ccode $handle "    if (!_$arg) $return_failure;"
+				}
+				char* {
+					_ccode $handle "    _$arg = Tcl_NewStringObj($arg, -1);"
+				}
+				Tcl_Obj* {
+					_ccode $handle "    _$arg = $arg;"
+				}
+				default {
+					return -code error "Unknown type: $type"
+				}
+			}
+			_ccode $handle "    if (!Tcl_ObjSetVar2(${interp_name}, Tcl_NewStringObj(\"${arg}\", -1), NULL, _$arg, 0)) $return_failure;"
+		}
+
+		_ccode $handle ""
+		_ccode $handle "    tclrv = Tcl_Eval($interp_name, \"$cbody\");"
+		_ccode $handle "    if (tclrv != TCL_OK) $return_failure;"
+		_ccode $handle ""
+
+		if {$rtype != "ok" && $rtype != "void"} {
+			_ccode $handle "    rv_interp = Tcl_GetObjResult(${interp_name});"
+		}
+
+		switch -- $rtype {
+			void { }
+			ok {
+				_ccode $handle "    rv = 0;"
+			}
+			int {
+				_ccode $handle "    if (Tcl_GetIntFromObj(ip, rv_interp, &rv) != TCL_OK) $return_failure;"
+			}
+			long {
+				_ccode $handle "    if (Tcl_GetLongFromObj(ip, rv_interp, &rv) != TCL_OK) $return_failure;"
+			}
+			Tcl_WideInt {
+				_ccode $handle "    if (Tcl_GetWideIntFromObj(ip, rv_interp, &rv) != TCL_OK) $return_failure;"
+			}
+			float {
+				_ccode $handle "    {"
+				_ccode $handle "        double t;"
+				_ccode $handle "        if (Tcl_GetDoubleFromObj(ip, rv_interp, &t) != TCL_OK) $return_failure;"
+				_ccode $handle "        rv = (float) t;"
+				_ccode $handle "    }"
+			}
+			double {
+				_ccode $handle "    if (Tcl_GetDoubleFromObj(ip, rv_interp, &rv) != TCL_OK) $return_failure;"
+			}
+			char* {
+				_ccode $handle "    rv = Tcl_GetString(rv_interp);"
+			}
+			char* {
+				_ccode $handle "    rv = Tcl_GetString(rv_interp);"
+			}
+		}
+
+		_ccode $handle ""
+		if {$rtype != "void"} {
+			_ccode $handle "    return(rv);"
+		} else {
+			_ccode $handle "    return;"
+		}
+		_ccode $handle "\}"
+	}
 
 	proc _go {handle {outputOnly 0}} {
 		variable dir
 
 		upvar #0 $handle state

Index: test.tcl
==================================================================
--- test.tcl
+++ test.tcl
@@ -143,5 +143,17 @@
 	$handle add_library curl
 	$handle go
     
 	curl_fetch http://rkeene.org/
 }
+
+set handle [tcc4tcl::new]
+$handle proc callToTcl {int a int b} int {
+	set retval [expr {$a + $b}]
+
+	return $retval
+}
+$handle cwrap callToTcl {int a int b} int
+$handle go
+if {[callToTcl 3 5] != 8} {
+	error "3 + 5 is 8"
+}