* $Id: wrapper.sno,v 1.6 2013-11-10 01:32:18 phil Exp $ * * wrapper.sno -- create C code to wrap a C function for LOAD()'ing * Phil Budne, December, 2001 * * TODO: * malloc string buffers to right size??? * add 'HANDLE' type??? * * function to invoke C compiler, loader (libtool?) to create so/dl/shl/.. * overall wrapper; take prototype, create file, executable, and load it!! **************** * constants for wrapper.proto wpmaxstr = 1024 wpstrtype = 'STRING' wpinttype = 'INTEGER' wpint32type = 'INT32' wpint64type = 'INT64' wprealtype = 'REAL' wphdltype = 'HANDLE' wppredtype = 'PREDICATE' wpspredtype = 'SYSPRED' wptypes = wpinttype | wprealtype | wpstrtype | + wpint64type | wpint32type * | wphdltype wprtypes = wptypes | wpredtype | wpspredtype | '' wpname = ANY(&UCASE &LCASE '_') SPAN(&UCASE &LCASE '0123456789_') wpend = ANY(',)') wp4sp = ' ' wp8sp = ' ' **************** * wrapper.startfile(output_name) * * output_name: the NAME (STRING) of output variable for C file * * XXX take filename arg?, return generated name variable?? * keep unit in a table, do endfile when endwrapperfile() called? define("wrapper.startfile(fn)") :(e.wrapper.startfile) wrapper.startfile * XXX wrap in '#ifdef HAVE_CONFIG_H'?? $fn = '/* this file generated by wrapper.sno on ' DATE() ' */' $fn = $fn = '#include "config.h"' $fn = '#include "h.h"' $fn = '#include "snotypes.h"' $fn = '#include "macros.h"' $fn = '#include "load.h"' $fn = '#include "equ.h"' * XXX include handle.h? * XXX output handle list? :(return) e.wrapper.startfile **************** * wrapper.proto(prototype,output_name) * * prototype: a prototype, as passed to SNOBOL LOAD() function * C function to call is the lowercase version * of the function name. * output_name: the NAME (STRING) of output variable for C file define("wrapper.proto(proto,fn)types,i,n,c,call") :(e.wrapper.proto) wrapper.proto $fn = $fn = '/* ' proto ' */' * get function name proto POS(0) wpname . name '(' = :f(wperr) **************** * loop for each argument, saving types in array n = 0 wpcopy = 0 * sigh; max 30 arguments! keep as linked list? types = ARRAY('0:29') proto POS(0) ')' = :s(wpepars) wploop proto wptypes . type wpend . c = :f(wperr) types[n] = type :f(wperr) * terminal = 'types[' n '] = ' type n = n + 1 * count string/handle typed variables to save time later wpcopy = IDENT(type, wpstrtype) wpcopy + 1 wpcopy = IDENT(type, wphdltype) wpcopy + 1 * was terminator a close paren? if so we're done with args, else loop IDENT(c, ')') :s(wpepars)f(wploop) wperr TERMINAL = 'error in prototype: >' proto '<' :(FRETURN) * proto should now have return type (or be empty) wpepars * TERMINAL = 'return type: ' proto proto POS(0) wprtypes RPOS(0) :f(wperr) * output C function declaration i = 0 $fn = name '( LA_ALIST ) LA_DCL' $fn = '{' **************** * loop declaring variables eq(wpcopy,0) :s(wpnostrs) wploop2 * XXX branch based on type? IDENT(types[i],wpstrtype) :f(wpnext2) $fn = wp4sp 'char arg' i '[' wpmaxstr '];' wpnext2 i = i + 1 LT(i,n) :s(wploop2) **************** * loop copying string variables i = 0 wpcopy * dispatch based on type :($('wpcpy_' types[i])) wpcpy_STRING $fn = wp4sp 'getstring(LA_PTR(' i '), arg' i ', sizeof(arg' i '));' :(wpncopy) wpcpy_HANDLE * XXXX handle HANDLE here!! wpcpy_INTEGER wpcpy_INT64 wpcpy_INT32 wpcpy_REAL wpcpy_ wpncopy i = i + 1 LT(i,n) :s(wpcopy) **************** * construct function call wpnostrs call = REPLACE(name,&UCASE,&LCASE) '(' i = 0 wpcall GE(i,n) :s(wpecall) call = GT(i,0) call ',' * dispatch based on type :($('wparg_' types[i])) wparg_INTEGER wparg_INT32 call = call '(int)LA_INT(' i ')' :s(wpncall) wparg_INT64 call = call '(long long)LA_INT(' i ')' :s(wpncall) wparg_REAL call = call '(double)LA_REAL(' i ')' :s(wpncall) wparg_STRING wparg_HANDLE call = call 'arg' i wpncall i = i + 1 :(wpcall) wpecall call = call ')' * here with complete invocation in "call"; output w/ proper return * dispatch based on type :($('wpret_' proto)) wpret_STRING $fn = wp4sp 'RETSTR((char *)' call ');' :s(wpdone) wpret_INT32 wpret_INT64 wpret_INTEGER $fn = wp4sp 'RETINT(' call ');' :s(wpdone) wpret_REAL $fn = wp4sp 'RETREAL(' call ');' :s(wpdone) wpret_PREDICATE $fn = wp4sp 'if (' call ')' $fn = wp8sp 'RETNULL;' $fn = wp4sp 'RETFAIL;' :s(wpdone) * system call (< 0 for failure) wpret_SYSPRED $fn = wp4sp 'if (' call ' >= 0)' $fn = wp8sp 'RETNULL;' $fn = wp4sp 'RETFAIL;' :s(wpdone) wpret_ $fn = wp4sp call ';' $fn = wp4sp 'RETNULL;' * end of function wpdone $fn = '}' :(return) e.wrapper.proto **************** test; * wrapper.startfile(.OUTPUT) * wrapper.proto('FOO(INTEGER,STRING,REAL)STRING', .OUTPUT) * wrapper.proto('BAR(INTEGER,REAL)INTEGER', .OUTPUT) * wrapper.proto('BAZ(INTEGER,INTEGER,REAL,STRING)', .OUTPUT) * wrapper.proto('MUMBLE(STRING,STRING,STRING)REAL', .OUTPUT) * *end