extension.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /* Copyright (c) 1993-2004 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 ((1 << 29) - 1)
  16. #define LEAST_FIXNUM_VALUE (-1 << 29)
  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. FLOP3(0) {
  67. get_float_arg(value, 0, x);
  68. get_float_arg(value, 1, y);
  69. set_float_arg(value, 2, x + y);
  70. EXT_RETURN(S48_UNSPECIFIC);}
  71. FLOP3(1) {
  72. get_float_arg(value, 0, x);
  73. get_float_arg(value, 1, y);
  74. set_float_arg(value, 2, x - y);
  75. EXT_RETURN(S48_UNSPECIFIC);}
  76. FLOP3(2) {
  77. get_float_arg(value, 0, x);
  78. get_float_arg(value, 1, y);
  79. set_float_arg(value, 2, x * y);
  80. EXT_RETURN(S48_UNSPECIFIC);}
  81. FLOP3(3) {
  82. get_float_arg(value, 0, x);
  83. get_float_arg(value, 1, y);
  84. if (y == 0.0) EXT_EXCEPTION;
  85. set_float_arg(value, 2, x / y);
  86. EXT_RETURN(S48_UNSPECIFIC);}
  87. FLOP2(4) {
  88. get_float_arg(value, 0, x);
  89. get_float_arg(value, 1, y);
  90. EXT_RETURN(S48_ENTER_BOOLEAN(x == y));}
  91. FLOP2(5) {
  92. get_float_arg(value, 0, x);
  93. get_float_arg(value, 1, y);
  94. EXT_RETURN(S48_ENTER_BOOLEAN(x < y));}
  95. FLOP2(6) { /* fixnum->float */
  96. s48_value arg = get_arg(value, 0);
  97. if (!S48_FIXNUM_P(arg)) EXT_RETURN(S48_FALSE);
  98. set_float_arg(value, 1, S48_UNSAFE_EXTRACT_FIXNUM(arg));
  99. EXT_RETURN(S48_TRUE);}
  100. FLOP2(7) { /* string->float */
  101. char *str = get_string_arg(value, 0);
  102. set_float_arg(value, 1, atof(str));
  103. EXT_RETURN(S48_UNSPECIFIC);}
  104. FLOP2(8) { /* float->string */
  105. size_t len;
  106. char *str = get_string_arg(value,1);
  107. get_float_arg(value, 0, x);
  108. sprintf(str, "%g", x);
  109. len = strlen(str);
  110. if (len > (size_t) S48_UNSAFE_STRING_LENGTH(get_arg(value,1)))
  111. /* unlikely but catastrophic */
  112. fprintf(stderr, "printing float: output too long: %s\n",
  113. str);
  114. EXT_RETURN(S48_UNSAFE_ENTER_FIXNUM(len));}
  115. /* exp log sin cos tan asin acos atan1 atan2 sqrt */
  116. FLOP2(9) {
  117. get_float_arg(value, 0, x);
  118. set_float_arg(value, 1, exp(x));
  119. EXT_RETURN(S48_UNSPECIFIC);}
  120. FLOP2(10) {
  121. get_float_arg(value, 0, x);
  122. set_float_arg(value, 1, log(x));
  123. EXT_RETURN(S48_UNSPECIFIC);}
  124. FLOP2(11) {
  125. get_float_arg(value, 0, x);
  126. set_float_arg(value, 1, sin(x));
  127. EXT_RETURN(S48_UNSPECIFIC);}
  128. FLOP2(12) {
  129. get_float_arg(value, 0, x);
  130. set_float_arg(value, 1, cos(x));
  131. EXT_RETURN(S48_UNSPECIFIC);}
  132. FLOP2(13) {
  133. get_float_arg(value, 0, x);
  134. set_float_arg(value, 1, tan(x));
  135. EXT_RETURN(S48_UNSPECIFIC);}
  136. FLOP2(14) {
  137. get_float_arg(value, 0, x);
  138. set_float_arg(value, 1, asin(x));
  139. EXT_RETURN(S48_UNSPECIFIC);}
  140. FLOP2(15) {
  141. get_float_arg(value, 0, x);
  142. set_float_arg(value, 1, acos(x));
  143. EXT_RETURN(S48_UNSPECIFIC);}
  144. FLOP2(16) { /* atan 1 */
  145. get_float_arg(value, 0, x);
  146. set_float_arg(value, 1, atan(x));
  147. EXT_RETURN(S48_UNSPECIFIC);}
  148. FLOP3(17) { /* atan 2 */
  149. get_float_arg(value, 0, y);
  150. get_float_arg(value, 1, x);
  151. set_float_arg(value, 2, atan2(y, x));
  152. EXT_RETURN(S48_UNSPECIFIC);}
  153. FLOP2(18) {
  154. get_float_arg(value, 0, x);
  155. set_float_arg(value, 1, sqrt(x));
  156. EXT_RETURN(S48_UNSPECIFIC);}
  157. FLOP2(19) { /* floor */
  158. get_float_arg(value, 0, x);
  159. set_float_arg(value, 1, floor(x));
  160. EXT_RETURN(S48_UNSPECIFIC);}
  161. case FLOP+20: { /* integer? */
  162. EXTRACT_FLOAT(value, x);
  163. EXT_RETURN(S48_ENTER_BOOLEAN(fmod(x, 1.0) == 0.0)); }
  164. case FLOP+21: { /* float->fixnum */
  165. EXTRACT_FLOAT(value, x);
  166. if (x <= (double)GREATEST_FIXNUM_VALUE
  167. && x >= (double)LEAST_FIXNUM_VALUE)
  168. {
  169. EXT_RETURN(S48_UNSAFE_ENTER_FIXNUM((long)x)); }
  170. else
  171. EXT_RETURN(S48_FALSE);}
  172. FLOP3(22) { /* quotient */
  173. double z;
  174. get_float_arg(value, 0, x);
  175. get_float_arg(value, 1, y);
  176. if (fmod(x, 1.0) != 0.0 || fmod(y, 1.0) != 0.0) EXT_EXCEPTION;
  177. if (y == 0.0) EXT_EXCEPTION;
  178. z = x / y;
  179. set_float_arg(value, 2, z < 0.0 ? ceil(z) : floor(z));
  180. EXT_RETURN(S48_UNSPECIFIC);}
  181. FLOP3(23) { /* remainder */
  182. get_float_arg(value, 0, x);
  183. get_float_arg(value, 1, y);
  184. if (fmod(x, 1.0) != 0.0 || fmod(y, 1.0) != 0.0) EXT_EXCEPTION;
  185. if (y == 0.0) EXT_EXCEPTION;
  186. /* "fmod(double x, double y) returns the floating-point remainder
  187. (f) of the division of x by y, where f has the same sign as x,
  188. such that x=iy+f for some integer i, and |f| < |y|." */
  189. set_float_arg(value, 2, fmod(x, y));
  190. EXT_RETURN(S48_UNSPECIFIC);}
  191. default:
  192. EXT_EXCEPTION;
  193. }
  194. }