home *** CD-ROM | disk | FTP | other *** search
- /** kvikrt.c
- ** Kvik runtime routines.
- **
- ** Written by and Copyright 1994 Asher Hoskins.
- **
- ** The author retains copyright on this implementation. Permission for
- ** educational and non-profit use is granted to all. If you're planning to
- ** make money with this or any code derived from it, check with the author
- ** first.
- **/
-
- #include <stdio.h>
- #include <ctype.h>
- #include "systypes.h"
- #include "systimeb.h"
- #include "timea.h"
- #include "kvikmath.h"
- #include "kvik_obj_types.h"
- #include "kvikrt.h"
- #include "parse.h"
-
- static void check_dp(dp_t *);
- void output_baudot(kviknum);
- kviknum input_baudot(void);
- static int pwr2(int);
- static kviknum kviktime(void);
- extern data_area_t *data;
-
- /** Allocate storage space. Returns a pointer to that storage.
- **/
-
- kviknum *alloc_storage(unsigned int id, unsigned int size, int value)
- {
- data_area_t *dt;
- kviknum *new_st;
- data_area_t *new_dt;
- unsigned int i;
-
- if (size == 0) {
- printf("KVIK: TRIED TO CREATE ZERO LENGTH STORAGE %d\n", id);
- exit(1);
- }
-
- dt = data;
- while (dt != NULL && dt->id != id)
- dt = dt->next;
-
- if (dt != NULL) {
- free(dt->start);
- new_dt = dt;
- }
- else {
- if ((new_dt = (data_area_t *) malloc(sizeof(data_area_t))) == NULL) {
- printf("KVIK: CANNOT CREATE STORAGE %d\n", id);
- exit(1);
- }
- new_dt->next = data;
- data = new_dt;
- }
-
- if ((new_st = (kviknum *) malloc(sizeof(kviknum)*size)) == NULL) {
- printf("KVIK: CANNOT CREATE STORAGE %d TO SIZE %d\n", id, size);
- exit(1);
- }
-
- new_dt->id = id;
- new_dt->start = new_st;
- new_dt->size = size;
-
- for (i=0; i<size; i++)
- new_st[i] = value;
-
- return(new_st);
- }
-
- /** Set a data pointer to a data area. Bit of a bodge with the linked list
- ** being searched twice - this was the easiest (ie. least thought :-)) way
- ** of adding set_dp_intoff when I realised I needed it (for std call 888).
- ** This will be fixed in a later release...
- **/
-
- void set_dp(dp_t *d, unsigned int id, kviknum pos)
- {
- data_area_t *dt;
- unsigned int offst;
-
- dt = data;
- while (dt != NULL && dt->id != id)
- dt = dt->next;
-
- if (dt == NULL) {
- printf("KVIK: NO SUCH STORAGE %d\n", id);
- exit(1);
- }
-
- offst = kvik2doub(pos) * pwr2(dt->size);
- set_dp_intoff(d, id, offst);
- }
-
- /** Set a data pointer to a data area with an integer offset within the
- ** area.
- **/
-
- void set_dp_intoff(dp_t *d, unsigned int id, unsigned int offst)
- {
- data_area_t *dt;
-
- dt = data;
- while (dt != NULL && dt->id != id)
- dt = dt->next;
-
- if (dt == NULL) {
- printf("KVIK: NO SUCH STORAGE %d\n", id);
- exit(1);
- }
-
- if (offst < 0 || offst >= dt->size) {
- puts("KVIK: ILLEGAL STORAGE POSITION");
- exit(1);
- }
-
- d->id = id;
- d->start = dt->start;
- d->offset = offst;
- d->size = dt->size;
- }
-
- /** Return the power of 2 greater than 'n'.
- **/
-
- static int pwr2(int n)
- {
- unsigned int p = 1;
-
- while (p < n)
- p <<= 1;
-
- return(p);
- }
-
- /** Check a data pointer is valid. Exit if it isn't.
- **/
-
- static void check_dp(dp_t *d)
- {
- if (d->start == NULL) {
- puts("KVIK: DATA POINTER NOT INITIALISED");
- exit(1);
- }
- }
-
- /** Move data pointer back one location in a storage area.
- **/
-
- void previous(dp_t *d)
- {
- check_dp(d);
-
- if (d->offset == 0) {
- puts("KVIK: MOVED DATA POINTER OFF BEGINNING OF STORAGE");
- exit(1);
- }
-
- (d->offset)--;
- }
-
- /** Move data pointer forwards one location in a storage area.
- **/
-
- void next(dp_t *d)
- {
- check_dp(d);
-
- if (d->offset == d->size-1) {
- puts("KVIK: MOVED DATA POINTER OFF END OF STORAGE");
- exit(1);
- }
-
- (d->offset)++;
- }
-
- /** Read a data item from storage.
- **/
-
- kviknum read_data(dp_t *d)
- {
- check_dp(d);
-
- return(*(d->start + d->offset));
- }
-
- /** Write a data item into storage.
- **/
-
- void write_data(dp_t *d, kviknum n)
- {
- check_dp(d);
-
- *(d->start + d->offset) = n;
- }
-
- /** Perform an expression.
- ** (I know 'op' should really be of type 'token_t' but keeping it as an
- ** int means I don't have to include 'parse.h' into the output code even
- ** if the compiler gets really picky...)
- **/
-
- kviknum expr(int s1, kviknum n1, int op, int s2, kviknum n2)
- {
- double d1, d2;
- double r;
-
- if ((d1 == OVERFLOW || d2 == OVERFLOW) && op != T_EQUAL
- && op != T_NOT_EQUAL)
- return(OVERFLOW);
-
- if (s1 == -1)
- n1 = negate(n1);
- if (s2 == -1)
- n2 = negate(n2);
-
- d1 = kvik2doub(n1);
- d2 = kvik2doub(n2);
-
- switch (op) {
- case T_PLUS:
- r = d1 + d2;
- break;
- case T_MINUS:
- r = d1 - d2;
- break;
- case T_MULTIPLY:
- r = d1 * d2;
- break;
- case T_DIVIDE:
- r = d1 / d2;
- break;
- case T_EQUAL:
- r = (d1 == d2) / 10.0;
- break;
- case T_NOT_EQUAL:
- r = (d1 != d2) / 10.0;
- break;
- case T_LESS_THAN:
- r = (d1 < d2) / 10.0;
- break;
- case T_GREATER_THAN:
- r = (d1 > d2) / 10.0;
- break;
- case T_LESS_THAN_OR_EQ:
- r = (d1 <= d2) / 10.0;
- break;
- case T_GREATER_THAN_OR_EQ:
- r = (d1 >= d2) / 10.0;
- }
-
- return(doub2kvik(r));
- }
-
- /** Read a value from a channel.
- **/
-
- kviknum read_channel(int c)
- {
- switch(c) {
-
- case 0:
- return(input_baudot());
-
- case 1:
- return(doub2kvik(-0.1));
-
- case 2:
- return(kviktime());
-
- case 3:
- return(OVERFLOW); /* Hot simulation :-) */
-
- default:
- return(doub2kvik(-0.1));
- }
- }
-
- /** Write a value to a channel.
- **/
-
- void write_channel(int c, kviknum n)
- {
- switch(c) {
-
- case 0:
- output_baudot(n);
- break;
-
- case 9: /* FOR TESTING ONLY */
- printf("Chan9: ");
- if (n == OVERFLOW)
- printf("Overflow\n");
- else
- printf("%.5lf\n", kvik2doub(n));
- break;
-
- default:
- ;
- }
- }
-
- /** Output a Baudot code character.
- **/
-
- void output_baudot(kviknum n)
- {
- static int baudot_shift = 0;
- static char baudot_chrs[] =
- "bTrO HNMdLRGIPCVEZDBSYFXAWJfUQKlb5r9 n,.d)4n80:=3+w?!6n/-2cf71(l";
- int chr;
- char bc;
-
- chr = 32 * kvik2doub(n);
- if (chr < 0 || chr > 31)
- return;
-
- bc = baudot_chrs[baudot_shift + chr];
- switch(bc) {
- case 'w': case 'n': case 'b': /* who are you, nothing, blank */
- break; /* do nothing */
- case 'c': /* bell */
- putchar('\a');
- break;
- case 'l': /* letter shift */
- baudot_shift = 0;
- break;
- case 'f': /* figure shift */
- baudot_shift = 32;
- break;
- case 'r': /* carriage return */
- putchar('\r');
- break;
- case 'd': /* line feed */
- putchar('\n');
- break;
- default: /* everything else */
- putchar(bc);
- }
-
- return;
- }
-
- /** Input a character from the keyboard. Sends letter/figure shifts
- ** automatically.
- **
- ** Returns a negative value on EOF.
- **/
-
- kviknum input_baudot(void)
- {
- static int baudot_shift = 0;
- static int chr_buffer = -1;
- static char baudot_chrs[] =
- "bTrO HNMdLRGIPCVEZDBSYFXAWJfUQKlb5r9 n,.d)4n80:=3+w?!6n/-2cf71(l";
- int chr, i, cdiff;
-
- if (chr_buffer != -1) {
- chr = chr_buffer;
- chr_buffer = -1;
- return(doub2kvik(chr/32.0));
- }
-
- if ((chr = getchar()) == EOF)
- return(doub2kvik(-0.1));
-
- if (islower(chr))
- chr = toupper(chr);
-
- switch (chr) {
- case ' ':
- return(doub2kvik(0.12500));
- case '\a':
- chr = 'c';
- break;
- case '\r':
- return(doub2kvik(0.06250));
- case '\n':
- return(doub2kvik(0.25000));
- }
-
- for (i = 0; i < 63; i++)
- if (chr == baudot_chrs[i]) {
- cdiff = i - baudot_shift;
- if (cdiff < 0) {
- baudot_shift = 0; /* set letter mode */
- chr_buffer = i;
- return(doub2kvik(0.96875));
- }
- if (cdiff > 31) {
- baudot_shift = 32; /* set figure mode */
- chr_buffer = i - 32;
- return(doub2kvik(0.84375));
- }
- return(doub2kvik(cdiff/32.0));
- }
-
- return(doub2kvik(0.0)); /* return blank if non-Baudot chr entered */
- }
-
- /** Return position within hour as number from "0 to "9.
- ** Note that if the precision of arithmetic is ever increased then
- ** the [-]0.99995's will have to be changed.
- **/
-
- static kviknum kviktime(void)
- {
- time_t t;
- struct tm *lt;
- double convtime;
-
- t = time(NULL);
- lt = localtime(&t);
-
- convtime = (lt->tm_min*60 + lt->tm_sec)/1800.0 - 1.0;
- if (convtime < -0.99995)
- convtime = -0.99995;
- if (convtime > 0.99995)
- convtime = 0.99995;
-
- return(doub2kvik(convtime));
- }
-