| home
| contents
| previous
| next page
| send comment
| send link
| add bookmark |
EXC_STND.CPP
standard functions
/*-------------------------------------------------------------------*
T standard function interpreter
File: exc_stnd.cpp
Module: interpreter
by: Stephen R. Schmitt
*-------------------------------------------------------------------*/
#include "tpl_data.h"
#include <assert.h>
#include <conio.h>
#include <dos.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <values.h>
/*
* External variables
*/
/* in tpl_main.cpp */
extern bool Debug_flag; // true in debug mode
extern char *Debug_screen;
extern char *User_screen;
extern int User_col, User_lin; // cursor location
/* in exc_main.cpp */
extern OPCODE Operator;
extern MEMORY_PTR *CSeg;
extern MEMORY_PTR SSeg, DSeg;
extern int IPtr;
extern int SPtr;
extern int BPtr;
extern int SNum;
extern double DEAX;
extern long EAX;
extern long EBX;
extern long ECX;
extern int AX;
extern int BX;
extern int CX;
extern char String[];
/* in exc_dbug.cpp */
extern bool Trace_flag;
/*-------------------------------------------------------------------*
Code Section
*-------------------------------------------------------------------*/
/*
* "standard_routine" interprets standard functions and procedures
* appropriate interpreter routines.
*
* returns: nothing
*/
void standard_routine()
{
Operator = CSeg[SNum][IPtr].op.code2;
switch (Operator)
{
case SF_ABS:
SSeg[SPtr].real = fabs(SSeg[SPtr].real);
break;
case SF_ARCCOS:
if ((SSeg[SPtr].real > +1.0) || (SSeg[SPtr].real < -1.0))
runtime_error(M_INVALID, M_FUNCTION, M_ARGUMENT, M_0);
else
SSeg[SPtr].real = acos(SSeg[SPtr].real);
break;
case SF_ARCSIN:
if ((SSeg[SPtr].real > +1.0) || (SSeg[SPtr].real < -1.0))
runtime_error(M_INVALID, M_FUNCTION, M_ARGUMENT, M_0);
else
SSeg[SPtr].real = asin(SSeg[SPtr].real);
break;
case SF_ARCTAN:
SSeg[SPtr].real = atan(SSeg[SPtr].real);
break;
case SF_ARCTANXY:
DEAX = SSeg[SPtr].real;
decr_sptr();
if ((DEAX == 0.0) && (SSeg[SPtr].real == 0.0))
runtime_error(M_INVALID, M_FUNCTION, M_ARGUMENT, M_0);
else
SSeg[SPtr].real = atan2(DEAX, SSeg[SPtr].real);
break;
case SF_CEIL:
SSeg[SPtr].real = ceil(SSeg[SPtr].real);
break;
case SF_CHR:
real_to_int();
SSeg[SPtr].byte = (char) SSeg[SPtr].integer;
break;
case SF_CLOSE:
sf_close();
break;
case SF_COS:
SSeg[SPtr].real = cos(SSeg[SPtr].real);
break;
case SF_COSH:
SSeg[SPtr].real = cosh(SSeg[SPtr].real);
break;
case SP_CURSOR:
sp_cursor();
break;
case SF_EOFF:
sf_eoff();
break;
case SF_EREALSTR:
sf_erealstr();
break;
case SF_EXP:
SSeg[SPtr].real = exp(SSeg[SPtr].real);
break;
case SF_FLOOR:
SSeg[SPtr].real = floor(SSeg[SPtr].real);
break;
case SF_FREALSTR:
sf_frealstr();
break;
case SF_GETEXP:
if (SSeg[SPtr].real == 0.0)
/* do nothing to return zero */;
else
{
if (SSeg[SPtr].real < 0.0)
SSeg[SPtr].real = -SSeg[SPtr].real;
DEAX = log10(SSeg[SPtr].real);
SSeg[SPtr].real = floor(DEAX);
}
break;
case SF_GETKEY:
sf_getkey();
break;
case SF_INDEX:
sf_index();
break;
case SF_INTREAL:
// do nothing since integers are pushed as real numbers
break;
case SF_INTSTR:
sf_intstr();
break;
case SF_LENGTH:
AX = strlen(SSeg[SPtr].string.ptr);
delete_string();
SSeg[SPtr].real = (double) AX;
break;
case SF_LN:
if (SSeg[SPtr].real <= 0.0)
runtime_error(M_INVALID, M_FUNCTION, M_ARGUMENT, M_0);
else
SSeg[SPtr].real = log(SSeg[SPtr].real);
break;
case SP_LOCATE:
sp_locate();
break;
case SF_LOG10:
if (SSeg[SPtr].real <= 0.0)
runtime_error(M_INVALID, M_FUNCTION, M_ARGUMENT, M_0);
else
SSeg[SPtr].real = log10(SSeg[SPtr].real);
break;
case SF_LOG2:
if (SSeg[SPtr].real <= 0.0)
runtime_error(M_INVALID, M_FUNCTION, M_ARGUMENT, M_0);
else
SSeg[SPtr].real = log(SSeg[SPtr].real)/log(2);
break;
case SF_MAX:
DEAX = SSeg[SPtr].real;
decr_sptr();
if (DEAX > SSeg[SPtr].real)
SSeg[SPtr].real = DEAX;
break;
case SF_MIN:
DEAX = SSeg[SPtr].real;
decr_sptr();
if (DEAX < SSeg[SPtr].real)
SSeg[SPtr].real = DEAX;
break;
case SF_OPEN:
sf_open();
break;
case SF_ORD:
SSeg[SPtr].real = (double) SSeg[SPtr].byte;
break;
case SF_PRED:
AX = SSeg[SPtr].index;
decr_sptr();
if (SSeg[SPtr].index > 0)
SSeg[SPtr].index--;
else
SSeg[SPtr].index = AX;
break;
case SP_PUTCH:
sp_putch();
break;
case SP_PUTSTR:
sp_putstr();
break;
case SP_PUTLINE:
sp_putline();
break;
case SP_PUTPIXEL:
sp_putpixel();
break;
case SF_RAND:
incr_sptr();
DEAX = (double) rand();
SSeg[SPtr].real = DEAX / 32768.0;
break;
case SF_RANDINT:
real_to_int();
EBX = SSeg[SPtr].integer; // high
decr_sptr();
real_to_int();
ECX = SSeg[SPtr].integer; // low
EAX = EBX - ECX + 1L; // range
if (EAX < 1L)
runtime_error(M_INVALID, M_FUNCTION, M_ARGUMENT, M_0);
DEAX = (double) rand();
SSeg[SPtr].real = ECX + EAX * DEAX / 32768.0;
break;
case SP_RANDOMIZE:
srand((unsigned) time(NULL));
break;
case SP_RANDSEED:
real_to_int();
srand((unsigned) SSeg[SPtr].integer);
decr_sptr();
break;
case SF_REALSTR:
sf_realstr();
break;
case SF_REPEAT:
sf_repeat();
break;
case SF_ROUND:
if (SSeg[SPtr].real > 0.0)
EAX = (long) (SSeg[SPtr].real + 0.5);
else
EAX = (long) (SSeg[SPtr].real - 0.5);
SSeg[SPtr].real = (double) EAX;
break;
case SP_SCROLL:
sp_scroll();
break;
case SF_SETEXP:
sf_setexp();
break;
case SP_SETVIDEO:
sp_setvideo();
break;
case SF_SIGN:
if (SSeg[SPtr].real >= 0.0)
SSeg[SPtr].real = +1.0;
else
SSeg[SPtr].real = -1.0;
break;
case SF_SIN:
SSeg[SPtr].real = sin(SSeg[SPtr].real);
break;
case SF_SINH:
SSeg[SPtr].real = sinh(SSeg[SPtr].real);
break;
case SF_SQRT:
if (SSeg[SPtr].real < 0.0)
runtime_error(M_INVALID, M_FUNCTION, M_ARGUMENT, M_0);
else
SSeg[SPtr].real = sqrt(SSeg[SPtr].real);
break;
case SF_STRINT:
sf_strint();
break;
case SF_STRREAL:
sf_strreal();
break;
case SF_SUCC:
AX = SSeg[SPtr].index;
decr_sptr();
if (SSeg[SPtr].index < AX)
SSeg[SPtr].index++;
else
SSeg[SPtr].index = 0;
break;
case SF_TAN:
SSeg[SPtr].real = tan(SSeg[SPtr].real);
break;
case SF_TANH:
SSeg[SPtr].real = tanh(SSeg[SPtr].real);
break;
case SF_VIDEOMODE:
sf_videomode();
break;
case SF_VIDEOTYPE:
sf_videotype();
break;
case SP_WATCH:
if (Trace_flag) // ok to display
write_watch(SSeg[SPtr].string.ptr);
delete_string();
decr_sptr();
break;
default:
assert(0);
break;
}
}
void sf_close()
{
long integer;
FILE *file_ptr;
real_to_int();
integer = SSeg[SPtr].integer;
file_ptr = (FILE *) integer;
if (fclose(file_ptr) != 0)
SSeg[SPtr].index = false;
else
SSeg[SPtr].index = true;
}
void sp_putch()
{
union REGS reg;
int bg = (int)SSeg[SPtr].real;
decr_sptr();
int fg = (int)SSeg[SPtr].real;
decr_sptr();
char ch = SSeg[SPtr].byte;
decr_sptr();
char attr = 16*bg + fg;
if (Debug_flag)
{
User_screen[160*User_lin + 2*User_col] = ch;
User_screen[160*User_lin + 2*User_col + 1] = attr;
}
else
{
reg.h.ah = 9;
reg.h.al = ch;
reg.h.bh = 0;
reg.h.bl = attr;
reg.x.cx = 1;
int86(0x10, ®, ®);
}
}
void sp_putstr()
{
union REGS reg;
int bg = (int)SSeg[SPtr].real;
decr_sptr();
int fg = (int)SSeg[SPtr].real;
decr_sptr();
strcpy(String, SSeg[SPtr].string.ptr);
delete_string();
decr_sptr();
char attr = 16*bg + fg;
int length = strlen(String);
for (int i = 0; i < length; i++)
{
if (Debug_flag)
{
User_screen[160*User_lin + 2*User_col] = String[i];
User_screen[160*User_lin + 2*User_col + 1] = attr;
User_col++;
if (User_col > 79)
{
User_col = 0;
User_lin++;
if (User_lin > 24)
User_lin = 0;
}
}
else
{
reg.h.ah = 9; // put character
reg.h.al = String[i];
reg.h.bh = 0;
reg.h.bl = attr;
reg.x.cx = 1;
int86(0x10, ®, ®);
reg.h.ah = 3; // find cursor location
reg.h.bh = 0;
int86(0x10, ®, ®);
int r = reg.h.dh;
int c = reg.h.dl;
c++; // update for next char
if (c > 79)
{
r++;
c = 0;
if (r > 24)
r = 0;
}
reg.h.ah = 2; // set cursor location
reg.h.bh = 0;
reg.h.dh = r;
reg.h.dl = c;
int86(0x10, ®, ®);
}
}
}
void sp_cursor()
{
int type = (int) SSeg[SPtr].real;
decr_sptr();
if (type == 0)
_setcursortype(_NOCURSOR);
else if (type == 1)
_setcursortype(_NORMALCURSOR);
else if (type == 2)
_setcursortype(_SOLIDCURSOR);
}
void sf_eoff()
{
real_to_int();
long integer = SSeg[SPtr].integer;
FILE *file_ptr = (FILE *)integer;
if (feof(file_ptr) == 0)
SSeg[SPtr].index = false;
else
SSeg[SPtr].index = true;
}
void sf_erealstr()
{
int exp_width = (int) SSeg[SPtr].real;
decr_sptr();
if (exp_width < 0)
exp_width = 2; // default
else if (exp_width > 4)
exp_width = 4; // limit
int fra_width = (int) SSeg[SPtr].real;
decr_sptr();
if (fra_width < 0)
fra_width = 6; // default
else if (fra_width > MAX_STRING_LENGTH - 7)
fra_width = MAX_STRING_LENGTH - 7;
int str_width = (int) SSeg[SPtr].real;
decr_sptr();
if (str_width > MAX_STRING_LENGTH)
str_width = MAX_STRING_LENGTH;
else if (str_width < (fra_width + exp_width + 5))
str_width = fra_width + exp_width + 5;
double real = SSeg[SPtr].real;
sprintf(String, "%*.*le", str_width, fra_width, real);
// right justify exponent
char *exp_ptr = strchr(String, 'e');
char *str_ptr = String;
int length = (int) (strlen(String) - (exp_ptr - String) - 2);
if (exp_width > length)
{
int zeroes = exp_width - length;
for (int i = 0; i < zeroes; i++) // add zero to exponent
{
*(exp_ptr + 6) = *(exp_ptr + 5);
*(exp_ptr + 5) = *(exp_ptr + 4);
*(exp_ptr + 4) = *(exp_ptr + 3);
*(exp_ptr + 3) = *(exp_ptr + 2);
*(exp_ptr + 2) = '0';
if (*str_ptr == ' ') // remove leading space
str_ptr++;
}
}
new_string();
strcpy(SSeg[SPtr].string.ptr, str_ptr);
}
void sf_frealstr()
{
int fra_width = (int)SSeg[SPtr].real;
decr_sptr();
if (fra_width < 0)
fra_width = 6; // default
else if (fra_width > MAX_STRING_LENGTH - 3)
fra_width = MAX_STRING_LENGTH - 3;
int str_width = (int)SSeg[SPtr].real;
decr_sptr();
if (str_width > MAX_STRING_LENGTH)
str_width = MAX_STRING_LENGTH;
else if (str_width < fra_width)
str_width = fra_width;
double real = SSeg[SPtr].real;
sprintf(String, "%*.*lf", str_width, fra_width, real);
new_string();
strcpy(SSeg[SPtr].string.ptr, String);
}
void sf_getkey()
{
int key, al, ah;
union REGS reg;
if (Debug_flag) // swap screens
debug_to_user_screen();
reg.h.ah = 0;
int86(0x16, ®, ®);
al = reg.h.al;
ah = reg.h.ah;
if (Debug_flag) // re-swap screens
user_to_debug_screen();
if (al == 0) // function key?
key = ah + 256;
else
key = al;
incr_sptr();
SSeg[SPtr].real = (double) key;
}
void sf_index()
{
long integer;
char *s = SSeg[SPtr - 1].string.ptr;
char *patt = SSeg[SPtr].string.ptr;
char *loc = strstr(s, patt);
if (loc == NULL)
integer = -1;
else
integer = (long)(loc - s); // first char at 0
delete_string();
decr_sptr();
delete_string();
SSeg[SPtr].real = (double) integer;
}
void sf_intstr()
{
int str_width = (int)SSeg[SPtr].real;
decr_sptr();
if (str_width > MAX_STRING_LENGTH)
str_width = MAX_STRING_LENGTH;
else if (str_width < 0)
str_width = 0;
long integer = (long)SSeg[SPtr].real;
sprintf(String, "%*ld", str_width, integer);
new_string();
strcpy(SSeg[SPtr].string.ptr, String);
}
void sp_locate()
{
union REGS reg;
int c = (int) SSeg[SPtr].real;
decr_sptr();
int r = (int) SSeg[SPtr].real;
decr_sptr();
if (Debug_flag)
{
User_lin = r;
User_col = c;
}
else
{
reg.h.ah = 2;
reg.h.bh = 0;
reg.h.dh = r;
reg.h.dl = c;
int86(0x10, ®, ®);
}
}
void sf_open()
{
char filename[FILE_NAME_LENGTH];
strcpy(String, SSeg[SPtr].string.ptr);
delete_string();
decr_sptr();
strcpy(filename, SSeg[SPtr].string.ptr);
delete_string();
long integer = (long)fopen(filename, String);
SSeg[SPtr].real = (double) integer;
}
void sp_putpixel()
{
// get parameters
int color = (int)SSeg[SPtr].real;
decr_sptr();
int y = (int)SSeg[SPtr].real;
decr_sptr();
int x = (int)SSeg[SPtr].real;
decr_sptr();
if (!Debug_flag)
pixel(x, y, color);
}
void sp_putline()
{
int xstep, ystep;
int change;
// get parameters
int color = (int) SSeg[SPtr].real;
decr_sptr();
int y2 = (int) SSeg[SPtr].real;
decr_sptr();
int x2 = (int) SSeg[SPtr].real;
decr_sptr();
int y1 = (int) SSeg[SPtr].real;
decr_sptr();
int x1 = (int) SSeg[SPtr].real;
decr_sptr();
if (Debug_flag)
return;
// draw the line
int xdelta = x2 - x1;
int ydelta = y2 - y1;
if (xdelta < 0) // draw right to left
{
xdelta = -xdelta;
xstep = -1;
}
else // draw left to right
xstep = 1;
if (ydelta < 0) // draw bottom to top
{
ydelta = -ydelta;
ystep = -1;
}
else // draw top to bottom
ystep = 1;
if (xdelta > ydelta) // loop using x
{
change = xdelta >> 1; // set to twice xdelta
while (x1 != x2) // until end is reached
{
pixel(x1, y1, color);
x1 += xstep; // update x coordinate
change += ydelta; // update change
// If change is large enough, update the y coordinate
if (change > xdelta)
{
y1 += ystep; // update y coordinate
change -= xdelta; // reset change
}
}
}
else // loop using y
{
change = ydelta >> 1; // set to twice ydelta
while (y1 != y2) // until end is reached
{
pixel(x1, y1, color);
y1 += ystep; // update y coordinate
change += xdelta; // update change
// If change is large enough, update the x coordinate
if (change > ydelta)
{
x1 += xstep; // update x coordinate
change -= ydelta; // reset change
}
}
}
}
void sf_realstr()
{
int str_width = (int) SSeg[SPtr].real;
decr_sptr();
if (str_width > MAX_STRING_LENGTH)
str_width = MAX_STRING_LENGTH;
else if (str_width < 0)
str_width = 0;
double real = SSeg[SPtr].real;
sprintf(String, "%*lg", str_width, real);
new_string();
strcpy(SSeg[SPtr].string.ptr, String);
}
void sf_repeat()
{
int index = (int)SSeg[SPtr].real;
decr_sptr();
strcpy(String, SSeg[SPtr].string.ptr);
int length = index * strlen(String);
if ((length > MAX_STRING_LENGTH) || (length < 0))
runtime_error(M_VALUE, M_OUT, M_OF, M_RANGE, M_0);
while (index > 1)
{
strcat(SSeg[SPtr].string.ptr, String);
index--;
}
}
void sp_scroll()
{
int i, j, n;
int dir = 6; // up is default
union REGS reg;
// get parameters
int lines = (int) SSeg[SPtr].real;
decr_sptr();
int bg = (int) SSeg[SPtr].real;
decr_sptr();
int fg = (int) SSeg[SPtr].real;
decr_sptr();
int right = (int) SSeg[SPtr].real;
decr_sptr();
int left = (int) SSeg[SPtr].real;
decr_sptr();
int bottom = (int) SSeg[SPtr].real;
decr_sptr();
int top = (int) SSeg[SPtr].real;
decr_sptr();
// process
char attr = 16*bg + fg;
if (lines < 0)
{
dir = 7;
lines = -lines;
}
if (Debug_flag)
{
if (lines == 0) // clear
{
for (i = top; i <= bottom; i++)
{
for (j = left; j <= right; j++)
{
User_screen[160*i + 2*j] = ' ';
User_screen[160*i + 2*j + 1] = attr;
}
}
}
else if (dir == 6) // scroll up
{
for (n = 0; n < lines; n++)
{
for (i = top + 1; i <= bottom; i++)
{
for (j = 2*left; j <= 2*right + 1; j++)
User_screen[160*(i - 1) + j] = User_screen[160*i + j];
}
for (j = left; j <= right; j++)
{
User_screen[160*bottom + 2*j] = ' ';
User_screen[160*bottom + 2*j + 1] = attr;
}
}
}
else // scroll down
{
for (n = 0; n < lines; n++)
{
for (i = bottom - 1; i >= top; i--)
{
for (j = 2*left; j <= 2*right + 1; j++)
User_screen[160*(i + 1) + j] = User_screen[160*i + j];
}
for (j = left; j <= right; j++)
{
User_screen[160*top + 2*j] = ' ';
User_screen[160*top + 2*j + 1] = attr;
}
}
}
}
else
{
reg.h.ah = dir;
reg.h.al = lines;
reg.h.bh = attr;
reg.h.ch = top;
reg.h.cl = left;
reg.h.dh = bottom;
reg.h.dl = right;
int86(0x10, ®, ®);
}
}
void sf_setexp()
{
double real;
int index = (int) SSeg[SPtr].real;
decr_sptr();
if ((index > DMAXEXP) || (index < DMINEXP))
runtime_error(M_VALUE, M_OUT, M_OF, M_RANGE, M_0);
double value = SSeg[SPtr].real;
if (value == 0.0)
/* do nothing to return zero */;
else
{
// get current exponent
if (value > 0.0)
real = floor(log10( value));
else
real = floor(log10(-value));
// set new exponent
value = value * pow10(index - real);
}
SSeg[SPtr].real = value;
}
void sp_setvideo()
{
union REGS inr, outr;
// get parameter
int mode = (int) SSeg[SPtr].real;
decr_sptr();
if (!Debug_flag)
{
inr.h.ah = 0x00; // set video mode
inr.h.al = mode;
int86(16, &inr, &outr); // call bios
}
}
void sf_strint()
{
strcpy(String, SSeg[SPtr].string.ptr);
delete_string();
SSeg[SPtr].real = (double) atol(String);
}
void sf_strreal()
{
strcpy(String, SSeg[SPtr].string.ptr);
delete_string();
SSeg[SPtr].real = atof(String);
if (errno == ERANGE)
runtime_error(M_INVALID, M_FUNCTION, M_ARGUMENT, M_0);
}
void sf_videotype()
{
int mode;
union REGS inr,outr;
inr.h.ah = 0x1A; // VGA,PGA,EGA,CGA,MDA
inr.h.al = 0;
int86(16, &inr, &outr); // call bios
if (outr.h.al == 0x1A)
mode = outr.h.bl;
else // test for EGA
{
inr.h.ah = 0x12;
inr.h.bl = 0x10;
int86(16, &inr, &outr);
if (outr.h.bl != 0x10) // EGA if true
mode = 4; /* or 5? */
else // test for CGA, MDA
{
inr.h.ah = 0x0F;
int86(16, &inr, &outr);
if (outr.h.al == 0x07) // MDA if true
mode = 1;
else // CGA
mode = 2;
}
}
incr_sptr();
SSeg[SPtr].real = (double) mode;
}
void sf_videomode()
{
union REGS inr, outr;
inr.h.ah = 0x0F; // get video mode
int86(16, &inr, &outr); // call bios
incr_sptr();
SSeg[SPtr].real = (double) outr.h.al;
}
/*
* "pixel" sets the pixel at (x, y) to color
*
* returns: nothing
*/
void pixel(int x, int y, int color)
{
asm mov ax, color
asm mov ah, 0Ch
asm mov cx, x
asm mov dx, y
asm int 10h
}
| home
| contents
| previous
| next page
| send comment
| send link
| add bookmark |
Copyright © 2004, Stephen R. Schmitt