extension.c 6.4 KB

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