🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.lang.misc
Article #2692

Re: Look, Ma, I can dynamically compose functions in C!

#2692
From: Ross Cunniff
Date: Thu, 24 Jan 1991 23:39
145 lines
3719 bytes
In article <553@ssp9.idca.tds.philips.nl> dolf@idca.tds.PHILIPS.nl
(Dolf Grunbauer) writes:

>>In article <1990Dec19.222059.6878@mathrt0.math.chalmers.se> augustss@cs.chalmers.se (Lennart Augustsson) writes:
>>> To see the difference just try to write a function
>>> that does function composition.
>>> I claim that this is impossible to do in a portable way.
>>
>>Okay. (What follows isn't tested but you'll get the idea.)
>>
>>[ idea, which probably will work, deleted ]
>>

>I think this is not what Lennart wanted. He wanted something like:

>  extern int f(), g();
>  int (*fg)();
>  ...
>  fg = f;
>  (*fg)(x);            /* executes f(x) */
>  fg = compose (f,g);
>  (*fg)(x);            /* should execute f(g(x)) */

>That is: he just wants to use the result of compose just like any other
>pointer to function, so one needs not to known whether it is a real function
>or a composed one. In Dan's code one must made this disctinction.

And now for something completely perverse.  Of course, this violates
the 'portability' constraint, but the function is short enought that
it wouldn't be terribly hard to rewrite it for your target machine.
Here goes:

/* Assembly code we'll generate:
 *	mov.l	4(%sp),-(%sp)
 *	jsr	b
 *	mov.l	%d0,(%sp)
 *	jsr	a
 *	addq.w	%4,%sp
 *	rts
 */

/* Instructions used */
#define	INSTR_GETX1	0x2f2f	/* mov.l 4(%sp),-(%sp) */
#define	INSTR_GETX2	0x0004

#define	INSTR_JSR	0x4eb9	/* jsr ... */

#define	INSTR_GETB	0x2e80	/* mov.l %d0,(%sp) */

#define	INSTR_RET1	0x584f	/* addq.w %4,%sp */
#define	INSTR_RET2	0x4e75	/* rts */

#define	COMPOSE_SIZE	22	/* Bytes */

typedef
    int (*func)( int );

/* Build a function that returns a(b(x)) */
func compose( func a, func b )
{
    unsigned short
	*Res,
	*Abits,
	*Bbits;
    void
	*malloc( unsigned );

    Res = malloc( COMPOSE_SIZE );
    if( !Res ) {
	return 0;
    }

    /* Get addresses */
    Abits = (unsigned short *)&a;
    Bbits = (unsigned short *)&b;

    /* Call b */
    Res[0]  = INSTR_GETX1;
    Res[1]  = INSTR_GETX2;
    Res[2]  = INSTR_JSR;
    Res[3]  = Bbits[0];
    Res[4]  = Bbits[1];

    /* Call a, leaving result in d0 */
    Res[5]  = INSTR_GETB;
    Res[6]  = INSTR_JSR;
    Res[7]  = Abits[0];
    Res[8]  = Abits[1];

    /* Pop args off stack and return */
    Res[9]  = INSTR_RET1;
    Res[10] = INSTR_RET2;

    /* Flush caches - this is very system specific, but necessary */
    /* since separate I and D caches won't know about each other. */
    flush_cache( Res, COMPOSE_SIZE );

    /* Return result */
    return (func)Res;
}


int a( int x )
{
    return x + 2;
}


int b( int x )
{
    return x * 2;
}


main( int argc, char **argv )
{
    int
	x,
	atoi( char * );
    func
	f;

    x = atoi( argv[1] );
    printf( "a(%d) = %d\n", x, a(x) );
    printf( "b(%d) = %d\n", x, b(x) );
    printf( "a(b(%d)) = %d\n", x, a(b(x)) );
    f = compose( a, b );
    printf( "f(%d) = %d\n", x, (*f)(x) );

    return 0;
}


This printed:

	a(5) = 7
	b(5) = 10
	a(b(5)) = 12
	f(5) = 12

on an HP9000 Series 300 workstation.  How fun!

				Ross Cunniff
				Hewlett-Packard Colorado Language Lab
				cunniff@hpfcla.HP.COM
Technical Details
Message-ID: <8960034@hpfcso.HP.COM>
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!usc!apple!agate!shelby!unix!hplabs!hpfcso!cunniff
References: <19468:Dec2100:23:0790@kramden.acf.nyu.edu>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!usc!apple!agate!shelby!unix!hplabs!hpfcso!cunniff
From: cunniff@hpfcso.HP.COM (Ross Cunniff)
Newsgroups: comp.lang.misc
Subject: Re: Look, Ma, I can dynamically compose functions in C!
Message-ID: <8960034@hpfcso.HP.COM>
Date: 24 Jan 91 23:39:44 GMT
References: <19468:Dec2100:23:0790@kramden.acf.nyu.edu>
Organization: Hewlett-Packard, Fort Collins, CO, USA
Lines: 145