extension.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /*
  2. * Part of Scheme 48 1.9. See file COPYING for notices and license.
  3. *
  4. * Authors: Richard Kelsey, Jonathan Rees, Mike Sperber
  5. */
  6. /* Implementation of the vm-extension opcode. This is completely
  7. optional; nothing in the standard system uses these features.
  8. The vm-extension opcode is being phased out. New code should use the
  9. external-call opcode to call C procedures.
  10. */
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <stdlib.h>
  14. #include <math.h>
  15. #include <signal.h>
  16. #include <errno.h>
  17. #include "scheme48.h"
  18. #define GREATEST_FIXNUM_VALUE S48_MAX_FIXNUM_VALUE
  19. #define LEAST_FIXNUM_VALUE S48_MIN_FIXNUM_VALUE
  20. #define CHANNEL_INDEX(x) EXTRACT_FIXNUM(STOB_REF(x, 1))
  21. #define FOR_INPUT 1
  22. #define FOR_OUTPUT 2
  23. typedef struct {
  24. char b[sizeof(double)];
  25. } unaligned_double;
  26. typedef union {
  27. double f;
  28. unaligned_double b;
  29. } float_or_bytes;
  30. extern long s48_Sextension_valueS; /* how values are returned */
  31. /* return status values */
  32. #define EXT_ST_OKAY 0
  33. #define EXT_ST_EXCEPTION 1
  34. #define EXT_RETURN(value) {s48_Sextension_valueS = (value); return EXT_ST_OKAY; }
  35. #define EXT_EXCEPTION return EXT_ST_EXCEPTION
  36. /******************************************/
  37. s48_value
  38. s48_extended_vm (long key, s48_value value)
  39. {
  40. double x, y;
  41. switch (key) {
  42. /* Cases 0 through 19 are reserved for the mobot system. */
  43. case 0: /* read jumpers on 68000 board */
  44. EXT_RETURN(S48_UNSAFE_ENTER_FIXNUM(0));
  45. /* Floating point */
  46. #define FLOP 100
  47. #define FLOP2(i) case FLOP+(i): \
  48. if (!S48_STOB_P(value) || S48_STOB_DESCRIPTOR_LENGTH(value) != 2) \
  49. EXT_EXCEPTION;
  50. #define FLOP3(i) case FLOP+(i): \
  51. if (!S48_STOB_P(value) || S48_STOB_DESCRIPTOR_LENGTH(value) != 3) \
  52. EXT_EXCEPTION;
  53. #define get_arg(args,i) S48_STOB_REF(args,(i))
  54. #define get_string_arg(args,i) (S48_UNSAFE_EXTRACT_STRING(get_arg(args,i)))
  55. #define get_float_arg(args, i, var) EXTRACT_FLOAT(get_arg(args, i), var)
  56. #define set_float_arg(args, i, val) SET_FLOAT(get_arg(args, i), val)
  57. #define EXTRACT_FLOAT(stob, var) \
  58. { s48_value temp_ = (stob); \
  59. float_or_bytes loser_; \
  60. if (!S48_STOB_P(temp_)) EXT_EXCEPTION; \
  61. loser_.b = *(unaligned_double*)(&S48_STOB_REF(temp_, 0)); \
  62. (var) = loser_.f; }
  63. #define SET_FLOAT(stob, val) \
  64. { s48_value temp_ = (stob); \
  65. float_or_bytes loser_; \
  66. if (!S48_STOB_P(temp_)) EXT_EXCEPTION; \
  67. loser_.f = (double)(val); \
  68. *(unaligned_double*)(&S48_STOB_REF(temp_, 0)) = loser_.b; }
  69. FLOP2(0) { /* fixnum->float */
  70. s48_value arg = get_arg(value, 0);
  71. if (!S48_FIXNUM_P(arg)) EXT_RETURN(S48_FALSE);
  72. set_float_arg(value, 1, S48_UNSAFE_EXTRACT_FIXNUM(arg));
  73. EXT_RETURN(S48_TRUE);}
  74. FLOP2(1) { /* string->float */
  75. static char* buf = NULL;
  76. static size_t max_size = 0;
  77. size_t len = s48_string_length(get_arg(value, 0));
  78. double retval;
  79. extern double ps_pos_infinity(void), ps_neg_infinity(void), ps_not_a_number(void);
  80. if (len + 1 > max_size)
  81. {
  82. max_size = ((len > 40) ? (len + 1) : 41);
  83. buf = realloc(buf, max_size);
  84. if (buf == NULL)
  85. EXT_RETURN(S48_FALSE);
  86. }
  87. s48_copy_string_to_latin_1(get_arg(value, 0), buf);
  88. buf[len] = '\0';
  89. if (buf[0] == '+')
  90. {
  91. if (!strcmp(buf, "+inf.0"))
  92. retval = ps_pos_infinity();
  93. else if (!strcmp(buf, "+nan.0"))
  94. retval = ps_not_a_number();
  95. else
  96. retval = atof(buf);
  97. }
  98. else if (buf[0] == '-')
  99. {
  100. if (!strcmp(buf, "-inf.0"))
  101. retval = ps_neg_infinity();
  102. else if (!strcmp(buf, "-nan.0"))
  103. retval = ps_not_a_number();
  104. else
  105. retval = atof(buf);
  106. }
  107. else
  108. retval = atof(buf);
  109. set_float_arg(value, 1, retval);
  110. EXT_RETURN(get_arg(value, 1));
  111. }
  112. FLOP2(2) { /* float->string */
  113. extern size_t s48_double_to_string(char *buf, double v);
  114. static char buf[40];
  115. int i;
  116. size_t len;
  117. get_float_arg(value, 0, x);
  118. len = s48_double_to_string(buf, x);
  119. s48_copy_latin_1_to_string_n(buf, len, get_arg(value,1));
  120. EXT_RETURN(S48_UNSAFE_ENTER_FIXNUM(len));
  121. }
  122. /* exp log sin cos tan asin acos atan1 atan2 sqrt */
  123. FLOP2(3) {
  124. get_float_arg(value, 0, x);
  125. set_float_arg(value, 1, exp(x));
  126. EXT_RETURN(S48_UNSPECIFIC);}
  127. FLOP2(4) {
  128. get_float_arg(value, 0, x);
  129. set_float_arg(value, 1, log(x));
  130. EXT_RETURN(S48_UNSPECIFIC);}
  131. FLOP2(5) {
  132. get_float_arg(value, 0, x);
  133. set_float_arg(value, 1, sin(x));
  134. EXT_RETURN(S48_UNSPECIFIC);}
  135. FLOP2(6) {
  136. get_float_arg(value, 0, x);
  137. set_float_arg(value, 1, cos(x));
  138. EXT_RETURN(S48_UNSPECIFIC);}
  139. FLOP2(7) {
  140. get_float_arg(value, 0, x);
  141. set_float_arg(value, 1, tan(x));
  142. EXT_RETURN(S48_UNSPECIFIC);}
  143. FLOP2(8) {
  144. get_float_arg(value, 0, x);
  145. set_float_arg(value, 1, asin(x));
  146. EXT_RETURN(S48_UNSPECIFIC);}
  147. FLOP2(9) {
  148. get_float_arg(value, 0, x);
  149. set_float_arg(value, 1, acos(x));
  150. EXT_RETURN(S48_UNSPECIFIC);}
  151. FLOP2(10) { /* atan 1 */
  152. get_float_arg(value, 0, x);
  153. set_float_arg(value, 1, atan(x));
  154. EXT_RETURN(S48_UNSPECIFIC);}
  155. FLOP3(11) { /* atan 2 */
  156. get_float_arg(value, 0, y);
  157. get_float_arg(value, 1, x);
  158. set_float_arg(value, 2, atan2(y, x));
  159. EXT_RETURN(S48_UNSPECIFIC);}
  160. FLOP2(12) {
  161. get_float_arg(value, 0, x);
  162. set_float_arg(value, 1, sqrt(x));
  163. EXT_RETURN(S48_UNSPECIFIC);}
  164. FLOP2(13) { /* floor */
  165. get_float_arg(value, 0, x);
  166. set_float_arg(value, 1, floor(x));
  167. EXT_RETURN(S48_UNSPECIFIC);}
  168. case FLOP+14: { /* integer? */
  169. EXTRACT_FLOAT(value, x);
  170. EXT_RETURN(S48_ENTER_BOOLEAN(fmod(x, 1.0) == 0.0)); }
  171. case FLOP+15: { /* float->fixnum */
  172. EXTRACT_FLOAT(value, x);
  173. if (x <= (double)GREATEST_FIXNUM_VALUE
  174. && x >= (double)LEAST_FIXNUM_VALUE)
  175. {
  176. EXT_RETURN(S48_UNSAFE_ENTER_FIXNUM((long)x)); }
  177. else
  178. EXT_RETURN(S48_FALSE);}
  179. FLOP3(16) { /* quotient */
  180. double z;
  181. get_float_arg(value, 0, x);
  182. get_float_arg(value, 1, y);
  183. if (fmod(x, 1.0) != 0.0 || fmod(y, 1.0) != 0.0) EXT_EXCEPTION;
  184. if (y == 0.0) EXT_EXCEPTION;
  185. z = x / y;
  186. set_float_arg(value, 2, z < 0.0 ? ceil(z) : floor(z));
  187. EXT_RETURN(S48_UNSPECIFIC);}
  188. FLOP3(17) { /* remainder */
  189. get_float_arg(value, 0, x);
  190. get_float_arg(value, 1, y);
  191. if (fmod(x, 1.0) != 0.0 || fmod(y, 1.0) != 0.0) EXT_EXCEPTION;
  192. if (y == 0.0) EXT_EXCEPTION;
  193. /* "fmod(double x, double y) returns the floating-point remainder
  194. (f) of the division of x by y, where f has the same sign as x,
  195. such that x=iy+f for some integer i, and |f| < |y|." */
  196. set_float_arg(value, 2, fmod(x, y));
  197. EXT_RETURN(S48_UNSPECIFIC);}
  198. default:
  199. EXT_EXCEPTION;
  200. }
  201. }