173 lines
5.8 KiB
C
173 lines
5.8 KiB
C
|
/*
|
|||
|
This program is the Microsoft C (ver. 4.0) implementation of the
|
|||
|
transcendental functions. The official implementation used by PC SCHEME
|
|||
|
was done under the Lattice C version. This purpose of this program is to
|
|||
|
show you what is needed to communicate with XLI via MS C. The
|
|||
|
lines containing comments that start out with @@ designate lines that
|
|||
|
will need to be modified by you when you use this template program
|
|||
|
for your own purpose.
|
|||
|
|
|||
|
Note: Before linking this program you will need to use the Macro
|
|||
|
Assembler to assemble the file GLUE_MS.ASM. The output of
|
|||
|
the assembler, GLUE_MS.OBJ will then be linked with the object
|
|||
|
of this file created by MSC.
|
|||
|
|
|||
|
The command line to compile is:
|
|||
|
MSC trig_ms;
|
|||
|
|
|||
|
The command line to assemble is:
|
|||
|
MASM glue_ms;
|
|||
|
|
|||
|
The command line to link this program is:
|
|||
|
LINK trig_ms+glue_ms;
|
|||
|
*/
|
|||
|
|
|||
|
#include "dos.h"
|
|||
|
#include "math.h"
|
|||
|
#include "stdlib.h"
|
|||
|
|
|||
|
#define F_NEAR 0x0001 /* Set model flag to near. USED */
|
|||
|
#define F_INT 0x0002 /* Set integer flag to 16 bits. NOT-USED */
|
|||
|
#define F_REL 0x0004 /* Set release env block by extern pgm flag. N-U */
|
|||
|
#define F_PAD 0x0008 /* Set parm blocking flag to unblocked. USED */
|
|||
|
|
|||
|
#define RT_INTEGER 0 /* Set return type to be an integer. NOT-USED */
|
|||
|
#define RT_BOOLEAN 1 /* Set return type to be boolean. NOT-USED */
|
|||
|
#define RT_STRING 2 /* Set return type to be a string. NOT-USED */
|
|||
|
#define RT_DOUBLE 3 /* Set the return type to be a float num. USED */
|
|||
|
|
|||
|
typedef unsigned short WORD; /* 16-bit unsigned value */
|
|||
|
|
|||
|
/*
|
|||
|
Xwait and xbye will contain the actual addresses, XLI entry points, that
|
|||
|
we'll jump to when we call XLI so they need to be big enough to hold FAR
|
|||
|
pointers.
|
|||
|
*/
|
|||
|
WORD xwait[2];
|
|||
|
WORD xbye[2];
|
|||
|
|
|||
|
WORD tsize; /* Will contain the length of this program in paragraphs. */
|
|||
|
|
|||
|
struct xli_file_struct {
|
|||
|
WORD id;
|
|||
|
WORD flags;
|
|||
|
WORD table[2]; /* offset in 0, segment in 1 */
|
|||
|
WORD parm_block[2];
|
|||
|
WORD reserved[8];
|
|||
|
} file_block;
|
|||
|
|
|||
|
struct xli_routine_struct {
|
|||
|
WORD select;
|
|||
|
WORD special_service;
|
|||
|
WORD ss_args[8];
|
|||
|
WORD reserved[8];
|
|||
|
WORD return_type;
|
|||
|
double return_value;
|
|||
|
double arg1; /* @@ Add as many args as you need. */
|
|||
|
double arg2;
|
|||
|
} parm_block;
|
|||
|
|
|||
|
char table[] =
|
|||
|
/*
|
|||
|
@@ The following string contains the names of the functions that can
|
|||
|
be called from within SCHEME when this file is loaded thru XLI.
|
|||
|
|
|||
|
0 1 2 3 4 5 6 7 8 9 10 11 12
|
|||
|
*/
|
|||
|
"sqrt/sin/cos/tan/asin/acos/atan/atan2/exp/expt/ln/log10/log//";
|
|||
|
|
|||
|
|
|||
|
void main()
|
|||
|
/*
|
|||
|
Within the main body of code the only portions that you will need to
|
|||
|
change are:
|
|||
|
1) The value of the FILE-BLOCK.FLAGS and
|
|||
|
2) The functions that you will call from within the CASE stmts.
|
|||
|
*/
|
|||
|
{
|
|||
|
struct SREGS segregs;
|
|||
|
|
|||
|
/*
|
|||
|
These function are defined in the assembly file GLUE_MS.ASM and are
|
|||
|
the functions that interface with Schemes XLI.
|
|||
|
*/
|
|||
|
int xli_wait();
|
|||
|
void xli_bye();
|
|||
|
|
|||
|
|
|||
|
union {
|
|||
|
WORD far * psp_ptr; /* declare as a far 32 bit pointer. */
|
|||
|
WORD half_ptrs[2]; /* declare two 16 bit words for Seg & Off. */
|
|||
|
} ptr;
|
|||
|
|
|||
|
/*
|
|||
|
The following code will initialize the File Block as needed.
|
|||
|
*/
|
|||
|
file_block.id = 0x4252;
|
|||
|
file_block.flags = F_NEAR+F_PAD; /* @@ Set flags as appropiate. */
|
|||
|
|
|||
|
segread(&segregs); /* Obtain the register information. */
|
|||
|
file_block.table[0] = (WORD) table;
|
|||
|
file_block.table[1] = segregs.ds;
|
|||
|
file_block.parm_block[0] = (WORD) &parm_block;
|
|||
|
file_block.parm_block[1] = segregs.ds;
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
The word at the PSP+2 is set by MS C to contain the next available
|
|||
|
paragraph number after this program. So if we subtract from this
|
|||
|
address the address of the PSP then we get the size of this program
|
|||
|
in paragraphs.
|
|||
|
*/
|
|||
|
ptr.half_ptrs[0] = 2; /* Set the offset to two, */
|
|||
|
ptr.half_ptrs[1] = _psp; /* and the segment to the PSP. */
|
|||
|
tsize = *(ptr.psp_ptr) - _psp;
|
|||
|
|
|||
|
|
|||
|
ptr.half_ptrs[0] = 0; /* Set the offset to zero, */
|
|||
|
ptr.half_ptrs[1] = _psp; /* and the segment to the PSP. */
|
|||
|
|
|||
|
/*
|
|||
|
Establish the connection between C and the PSP.
|
|||
|
*/
|
|||
|
ptr.psp_ptr[46] = (WORD far) &file_block; /* Set into the PSP the offset and */
|
|||
|
ptr.psp_ptr[47] = segregs.ds; /* segment address of file_block */
|
|||
|
|
|||
|
xwait[0] = ptr.psp_ptr[5]; /* Store into XWAIT the offset and */
|
|||
|
xwait[1] = ptr.psp_ptr[6]; /* segment address of DOS's terminate routine. */
|
|||
|
|
|||
|
xbye[0] = xwait[0]; /* Copy the termination segment and */
|
|||
|
xbye[1] = xwait[1]; /* offset address, from above, into here. */
|
|||
|
|
|||
|
xwait[0] += 3; /* incr by 3 for normal call */
|
|||
|
xbye[0] += 6; /* incr by 6 for termination */
|
|||
|
|
|||
|
while (xli_wait()) {
|
|||
|
switch (parm_block.select) {
|
|||
|
case 0: parm_block.return_value = sqrt(parm_block.arg1); break;
|
|||
|
case 1: parm_block.return_value = sin(parm_block.arg1); break;
|
|||
|
case 2: parm_block.return_value = cos(parm_block.arg1); break;
|
|||
|
case 3: parm_block.return_value = tan(parm_block.arg1); break;
|
|||
|
case 4: parm_block.return_value = asin(parm_block.arg1); break;
|
|||
|
case 5: parm_block.return_value = acos(parm_block.arg1); break;
|
|||
|
case 6: parm_block.return_value = atan(parm_block.arg1); break;
|
|||
|
case 7: parm_block.return_value =
|
|||
|
atan2(parm_block.arg1,parm_block.arg2); break;
|
|||
|
case 8: parm_block.return_value = exp(parm_block.arg1); break;
|
|||
|
case 9: parm_block.return_value =
|
|||
|
pow(parm_block.arg1,parm_block.arg2); break;
|
|||
|
case 10: parm_block.return_value = log(parm_block.arg1); break;
|
|||
|
case 11: parm_block.return_value = log10(parm_block.arg1); break;
|
|||
|
case 12: parm_block.return_value =
|
|||
|
log(parm_block.arg1) / log(parm_block.arg2); break;
|
|||
|
default: ;
|
|||
|
} /* end switch */
|
|||
|
|
|||
|
parm_block.return_type = RT_DOUBLE;
|
|||
|
|
|||
|
} /* end while */
|
|||
|
|
|||
|
xli_bye();
|
|||
|
|
|||
|
} /* end main */
|
|||
|
|