PageRenderTime 52ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 3ms

/src/io.d

https://github.com/ynd/clisp-branch--ynd-devel
D | 10545 lines | 7316 code | 301 blank | 2928 comment | 1225 complexity | cbabd0b1128037aa0e6ab8460976b564 MD5 | raw file
Possible License(s): LGPL-2.0, GPL-2.0, BSD-3-Clause
  1. /*
  2. * Input/Output for CLISP
  3. * Bruno Haible 1990-2005
  4. * Marcus Daniels 11.3.1997
  5. * Sam Steingold 1998-2008
  6. * German comments translated into English: Stefan Kain 2001-06-12
  7. */
  8. #include "lispbibl.c"
  9. #include "arilev0.c" /* for Division in pr_uint */
  10. /* IO_DEBUG must be undefined in the code comitted to CVS */
  11. /* #define IO_DEBUG 0 */
  12. #ifdef IO_DEBUG
  13. #define PPH_OUT(label,stream) \
  14. do { printf(#label "[%d]: [",__LINE__); \
  15. nobject_out(stdout,stream); \
  16. printf("]\n"); } while(0)
  17. #else
  18. #define PPH_OUT(l,s)
  19. #endif
  20. /* ========================================================================
  21. Readtable-functions
  22. ======================================================================== */
  23. /* Maximum size of linear per-character arrays. */
  24. #define small_char_code_limit 0x100UL
  25. /* Tables indexed by characters.
  26. allocate_perchar_table()
  27. perchar_table_get(table,c)
  28. perchar_table_put(table,c,value)
  29. copy_perchar_table(table) */
  30. #if (small_char_code_limit < char_code_limit)
  31. /* A simple-vector of small_char_code_limit+1 elements, the last entry being
  32. a hash table for the non-base characters. */
  33. local object allocate_perchar_table (void) {
  34. /* Allocate the hash table.
  35. (MAKE-HASH-TABLE :KEY-TYPE 'CHARACTER
  36. :VALUE-TYPE '(OR FUNCTION SIMPLE-VECTOR)
  37. :TEST 'FASTHASH-EQ :WARN-IF-NEEDS-REHASH-AFTER-GC T) */
  38. pushSTACK(S(Ktest)); pushSTACK(S(fasthash_eq));
  39. pushSTACK(S(Kwarn_if_needs_rehash_after_gc)); pushSTACK(T);
  40. funcall(L(make_hash_table),4);
  41. pushSTACK(value1);
  42. /* Allocate the simple-vector. */
  43. var object table = allocate_vector(small_char_code_limit+1);
  44. TheSvector(table)->data[small_char_code_limit] = popSTACK();
  45. return table;
  46. }
  47. local object perchar_table_get (object table, chart c) {
  48. if (as_cint(c) < small_char_code_limit) {
  49. return TheSvector(table)->data[as_cint(c)];
  50. } else {
  51. var object value = gethash(code_char(c),
  52. TheSvector(table)->data[small_char_code_limit],
  53. false);
  54. return (eq(value,nullobj) ? NIL : value);
  55. }
  56. }
  57. local void perchar_table_put (object table, chart c, object value) {
  58. if (as_cint(c) < small_char_code_limit) {
  59. TheSvector(table)->data[as_cint(c)] = value;
  60. } else {
  61. shifthash(TheSvector(table)->data[small_char_code_limit],
  62. code_char(c),value,true);
  63. }
  64. }
  65. local object copy_perchar_table (object table) {
  66. pushSTACK(copy_svector(table));
  67. /* Allocate a new hash table.
  68. (MAKE-HASH-TABLE :KEY-TYPE 'CHARACTER
  69. :VALUE-TYPE '(OR FUNCTION SIMPLE-VECTOR)
  70. :TEST 'FASTHASH-EQ :WARN-IF-NEEDS-REHASH-AFTER-GC T) */
  71. pushSTACK(S(Ktest)); pushSTACK(S(fasthash_eq));
  72. pushSTACK(S(Kwarn_if_needs_rehash_after_gc)); pushSTACK(T);
  73. funcall(L(make_hash_table),4);
  74. pushSTACK(value1);
  75. /* stack layout: table, newht. */
  76. map_hashtable(TheSvector(STACK_1)->data[small_char_code_limit],
  77. key,value,{ shifthash(STACK_(0+1),key,value,true); });
  78. var object newht = popSTACK();
  79. var object table1 = popSTACK();
  80. TheSvector(table1)->data[small_char_code_limit] = newht;
  81. return table1;
  82. }
  83. #else
  84. /* A simple-vector of char_code_limit elements. */
  85. #define allocate_perchar_table() allocate_vector(char_code_limit)
  86. #define perchar_table_get(table,c) TheSvector(table)->data[(uintP)as_cint(c)]
  87. #define perchar_table_put(table,c,value) (TheSvector(table)->data[(uintP)as_cint(c)] = (value))
  88. #define copy_perchar_table(table) copy_svector(table)
  89. #endif
  90. /* Structure of Readtables (cf. LISPBIBL.D):
  91. readtable_syntax_table
  92. bitvector consisting of char_code_limit bytes: for each character the
  93. syntaxcode is assigned
  94. readtable_macro_table
  95. a vector with char_code_limit elements: for each character
  96. either (if the character is not a read-macro)
  97. NIL
  98. or (if the character is a dispatch-macro)
  99. a vector with char_code_limit functions/NILs,
  100. or (if the character is a read-macro defined by a function)
  101. the function, which is called, when the character is read.
  102. readtable_case
  103. a fixnum in {0,1,2,3}
  104. meaning of case (in sync with CONSTOBJ.D!): */
  105. #define case_upcase 0
  106. #define case_downcase 1
  107. #define case_preserve 2
  108. #define case_invert 3
  109. /* meaning of the entries in the syntax_table: */
  110. #define syntax_illegal 0 /* unprintable, excluding whitespace */
  111. #define syntax_single_esc 1 /* '\' (Single Escape) */
  112. #define syntax_multi_esc 2 /* '|' (Multiple Escape) */
  113. #define syntax_constituent 3 /* the rest (Constituent) */
  114. #define syntax_whitespace 4 /* TAB,LF,FF,CR,' ' (Whitespace) */
  115. #define syntax_eof 5 /* EOF */
  116. #define syntax_t_macro 6 /* '()'"' (Terminating Macro) */
  117. #define syntax_nt_macro 7 /* '#' (Non-Terminating Macro) */
  118. /* <= syntax_constituent : if an object starts with such a character, it's a
  119. token. (syntax_illegal will deliver an error then.)
  120. >= syntax_t_macro : macro-character. if an object starts like that:
  121. call read-macro function.
  122. Syntax tables, indexed by characters.
  123. allocate_syntax_table()
  124. syntax_table_get(table,c)
  125. syntax_table_put(table,c,value)
  126. syntax_table_put can trigger GC */
  127. #if (small_char_code_limit < char_code_limit)
  128. /* A cons, consisting of a simple-bit-vector with small_char_code_limit
  129. bytes, and a hash table mapping characters to fixnums. Characters not
  130. found in the hash table are assumed to have the syntax code
  131. (graphic_char_p(ch) ? syntax_constituent : syntax_illegal). */
  132. local object allocate_syntax_table (void) {
  133. /* Allocate the hash table.
  134. (MAKE-HASH-TABLE :KEY-TYPE 'CHARACTER
  135. :VALUE-TYPE 'FIXNUM
  136. :TEST 'FASTHASH-EQ :WARN-IF-NEEDS-REHASH-AFTER-GC T) */
  137. pushSTACK(S(Ktest)); pushSTACK(S(fasthash_eq));
  138. pushSTACK(S(Kwarn_if_needs_rehash_after_gc)); pushSTACK(T);
  139. funcall(L(make_hash_table),4);
  140. pushSTACK(value1);
  141. /* Allocate the simple-bit-vector. */
  142. pushSTACK(allocate_bit_vector(Atype_8Bit,small_char_code_limit));
  143. var object new_cons = allocate_cons();
  144. Car(new_cons) = popSTACK();
  145. Cdr(new_cons) = popSTACK();
  146. return new_cons;
  147. }
  148. local uintB syntax_table_get_notinline (object table, chart c) {
  149. var object val = gethash(code_char(c),Cdr(table),false);
  150. if (!eq(val,nullobj))
  151. return posfixnum_to_V(val);
  152. else
  153. return (graphic_char_p(c) ? syntax_constituent : syntax_illegal);
  154. }
  155. local inline uintB syntax_table_get (object table, chart c) {
  156. return (as_cint(c) < small_char_code_limit
  157. ? TheSbvector(Car(table))->data[as_cint(c)]
  158. : syntax_table_get_notinline(table,c));
  159. }
  160. local maygc void syntax_table_put_notinline (object table, chart c, uintB value)
  161. {
  162. shifthash(Cdr(table),code_char(c),fixnum(value),true);
  163. }
  164. local inline maygc void syntax_table_put (object table, chart c, uintB value) {
  165. if (as_cint(c) < small_char_code_limit)
  166. TheSbvector(Car(table))->data[as_cint(c)] = value;
  167. else
  168. syntax_table_put_notinline(table,c,value);
  169. }
  170. #else
  171. /* A simple-bit-vector with char_code_limit bytes. */
  172. #define allocate_syntax_table() \
  173. allocate_bit_vector(Atype_8Bit,char_code_limit)
  174. #define syntax_table_get(table,c) \
  175. TheSbvector(table)->data[as_cint(c)]
  176. #define syntax_table_put(table,c,value) \
  177. (TheSbvector(table)->data[as_cint(c)] = (value))
  178. #endif
  179. #define syntax_readtable_get(rt,c) \
  180. syntax_table_get(TheReadtable(rt)->readtable_syntax_table,c)
  181. #define syntax_readtable_put(rt,c,v) \
  182. syntax_table_put(TheReadtable(rt)->readtable_syntax_table,c,v)
  183. /* standard(original) syntaxtable(readtable) for read characters: */
  184. local const uintB orig_syntax_table [small_char_code_limit] = {
  185. #define illg syntax_illegal
  186. #define sesc syntax_single_esc
  187. #define mesc syntax_multi_esc
  188. #define cnst syntax_constituent
  189. #define whsp syntax_whitespace
  190. #define tmac syntax_t_macro
  191. #define nmac syntax_nt_macro
  192. illg,illg,illg,illg,illg,illg,illg,illg, /* chr(0) upto chr(7) */
  193. cnst,whsp,whsp,illg,whsp,whsp,illg,illg, /* chr(8) upto chr(15) */
  194. illg,illg,illg,illg,illg,illg,illg,illg, /* chr(16) upto chr(23) */
  195. illg,illg,illg,illg,illg,illg,illg,illg, /* chr(24) upto chr(31) */
  196. whsp,cnst,tmac,nmac,cnst,cnst,cnst,tmac, /* ' !"#$%&'' */
  197. tmac,tmac,cnst,cnst,tmac,cnst,cnst,cnst, /* '()*+,-./' */
  198. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst, /* '01234567' */
  199. cnst,cnst,cnst,tmac,cnst,cnst,cnst,cnst, /* '89:;<=>?' */
  200. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst, /* '@ABCDEFG' */
  201. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst, /* 'HIJKLMNO' */
  202. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst, /* 'PQRSTUVW' */
  203. cnst,cnst,cnst,cnst,sesc,cnst,cnst,cnst, /* 'XYZ[\]^_' */
  204. tmac,cnst,cnst,cnst,cnst,cnst,cnst,cnst, /* '`abcdefg' */
  205. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst, /* 'hijklmno' */
  206. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst, /* 'pqrstuvw' */
  207. cnst,cnst,cnst,cnst,mesc,cnst,cnst,cnst, /* 'xyz{|}~',chr(127) */
  208. #if defined(UNICODE) || defined(ISOLATIN_CHS) || defined(HPROMAN8_CHS)
  209. illg,illg,illg,illg,illg,illg,illg,illg,
  210. illg,illg,illg,illg,illg,illg,illg,illg,
  211. illg,illg,illg,illg,illg,illg,illg,illg,
  212. illg,illg,illg,illg,illg,illg,illg,illg,
  213. whsp,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  214. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  215. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  216. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  217. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  218. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  219. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  220. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  221. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  222. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  223. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  224. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  225. #elif defined(NEXTSTEP_CHS)
  226. whsp,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  227. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  228. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  229. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  230. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  231. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  232. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  233. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  234. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  235. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  236. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  237. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  238. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  239. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  240. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  241. cnst,cnst,cnst,cnst,cnst,cnst,cnst,cnst,
  242. #else /* defined(ASCII_CHS) && !defined(UNICODE) */
  243. illg,illg,illg,illg,illg,illg,illg,illg,
  244. illg,illg,illg,illg,illg,illg,illg,illg,
  245. illg,illg,illg,illg,illg,illg,illg,illg,
  246. illg,illg,illg,illg,illg,illg,illg,illg,
  247. illg,illg,illg,illg,illg,illg,illg,illg,
  248. illg,illg,illg,illg,illg,illg,illg,illg,
  249. illg,illg,illg,illg,illg,illg,illg,illg,
  250. illg,illg,illg,illg,illg,illg,illg,illg,
  251. illg,illg,illg,illg,illg,illg,illg,illg,
  252. illg,illg,illg,illg,illg,illg,illg,illg,
  253. illg,illg,illg,illg,illg,illg,illg,illg,
  254. illg,illg,illg,illg,illg,illg,illg,illg,
  255. illg,illg,illg,illg,illg,illg,illg,illg,
  256. illg,illg,illg,illg,illg,illg,illg,illg,
  257. illg,illg,illg,illg,illg,illg,illg,illg,
  258. illg,illg,illg,illg,illg,illg,illg,illg,
  259. #endif
  260. #undef illg
  261. #undef sesc
  262. #undef mesc
  263. #undef cnst
  264. #undef whsp
  265. #undef tmac
  266. #undef nmac
  267. };
  268. #if (small_char_code_limit < char_code_limit)
  269. #define orig_syntax_table_get(c) \
  270. (as_cint(c) < small_char_code_limit \
  271. ? orig_syntax_table[as_cint(c)] \
  272. : (graphic_char_p(c) ? syntax_constituent : syntax_illegal))
  273. #else
  274. #define orig_syntax_table_get(c) orig_syntax_table[as_cint(c)]
  275. #endif
  276. /* UP: returns the standard (original) readtable.
  277. orig_readtable()
  278. < result: standard(original) readtable
  279. can trigger GC */
  280. local maygc object orig_readtable (void) {
  281. { /* initialize the syntax-table: */
  282. var object s_table = allocate_syntax_table(); /* new bitvector */
  283. pushSTACK(s_table); /* save */
  284. /* and fill with the original: */
  285. #if (small_char_code_limit < char_code_limit)
  286. s_table = Car(s_table);
  287. #endif
  288. var const uintB * ptr1 = &orig_syntax_table[0];
  289. var uintB* ptr2 = &TheSbvector(s_table)->data[0];
  290. var uintC count;
  291. dotimesC(count,small_char_code_limit, { *ptr2++ = *ptr1++; } );
  292. }
  293. { /* initialize dispatch-macro '#': */
  294. var object d_table = allocate_perchar_table(); /* new vector */
  295. pushSTACK(d_table); /* save */
  296. /* and add the sub-character-functions for '#': */
  297. var gcv_object_t* table = &TheSvector(d_table)->data[0];
  298. table['\''] = L(function_reader);
  299. table['|'] = L(comment_reader);
  300. table['\\'] = L(char_reader);
  301. table['B'] = L(binary_reader);
  302. table['O'] = L(octal_reader);
  303. table['X'] = L(hexadecimal_reader);
  304. table['R'] = L(radix_reader);
  305. table['C'] = L(complex_reader);
  306. table[':'] = L(uninterned_reader);
  307. table['*'] = L(bit_vector_reader);
  308. table['('] = L(vector_reader);
  309. table['A'] = L(array_reader);
  310. table['.'] = L(read_eval_reader);
  311. table[','] = L(load_eval_reader);
  312. table['='] = L(label_definition_reader);
  313. table['#'] = L(label_reference_reader);
  314. table['<'] = L(not_readable_reader);
  315. table[')'] = L(syntax_error_reader);
  316. table[' '] = L(syntax_error_reader); /* #\Space */
  317. table[NL] = L(syntax_error_reader); /* #\Newline = 10 = #\Linefeed */
  318. table[BS] = L(syntax_error_reader); /* #\Backspace */
  319. table[TAB] = L(syntax_error_reader); /* #\Tab */
  320. table[CR] = L(syntax_error_reader); /* #\Return */
  321. table[PG] = L(syntax_error_reader); /* #\Page */
  322. table[RUBOUT] = L(syntax_error_reader); /* #\Rubout */
  323. table['+'] = L(feature_reader);
  324. table['-'] = L(not_feature_reader);
  325. table['S'] = L(structure_reader);
  326. table['Y'] = L(closure_reader);
  327. table['"'] = L(clisp_pathname_reader);
  328. table['P'] = L(ansi_pathname_reader);
  329. }
  330. { /* initialize READ-macros: */
  331. var object m_table = allocate_perchar_table(); /* new NIL-filled vector */
  332. /* and add the macro-characters: */
  333. var gcv_object_t* table = &TheSvector(m_table)->data[0];
  334. table['('] = L(lpar_reader);
  335. table[')'] = L(rpar_reader);
  336. table['"'] = L(string_reader);
  337. table['\''] = L(quote_reader);
  338. table['#'] = popSTACK(); /* dispatch-vector for '#' */
  339. table[';'] = L(line_comment_reader);
  340. table['`'] = S(backquote_reader); /* cf. BACKQUOTE.LISP */
  341. table[','] = S(comma_reader); /* cf. BACKQUOTE.LISP */
  342. pushSTACK(m_table); /* save */
  343. }
  344. { /* build readtable: */
  345. var object readtable = allocate_readtable(); /* new readtable */
  346. TheReadtable(readtable)->readtable_macro_table = popSTACK(); /* m_table */
  347. TheReadtable(readtable)->readtable_syntax_table = popSTACK(); /* s_table */
  348. TheReadtable(readtable)->readtable_case = fixnum(case_upcase); /* :UPCASE */
  349. return readtable;
  350. }
  351. }
  352. /* UP: copies a readtable
  353. copy_readtable_contents(from_readtable,to_readtable)
  354. > from-readtable
  355. > to-readtable
  356. < result : to-Readtable with same content
  357. can trigger GC */
  358. local maygc object copy_readtable_contents (object from_readtable,
  359. object to_readtable) {
  360. /* copy the case-slot: */
  361. TheReadtable(to_readtable)->readtable_case =
  362. TheReadtable(from_readtable)->readtable_case;
  363. { /* copy the syntaxtable: */
  364. var object stable1;
  365. var object stable2;
  366. #if (small_char_code_limit < char_code_limit)
  367. pushSTACK(to_readtable);
  368. pushSTACK(from_readtable);
  369. /* Allocate a new hash table.
  370. (MAKE-HASH-TABLE :KEY-TYPE 'CHARACTER
  371. :VALUE-TYPE 'FIXNUM
  372. :TEST 'FASTHASH-EQ :WARN-IF-NEEDS-REHASH-AFTER-GC T) */
  373. pushSTACK(S(Ktest)); pushSTACK(S(fasthash_eq));
  374. pushSTACK(S(Kwarn_if_needs_rehash_after_gc)); pushSTACK(T);
  375. funcall(L(make_hash_table),4);
  376. pushSTACK(value1);
  377. /* stack layout: to-readtable, from-readtable, newht. */
  378. map_hashtable(Cdr(TheReadtable(STACK_1)->readtable_syntax_table),ch,entry,
  379. { shifthash(STACK_(0+1),ch,entry,true); });
  380. {
  381. var object newht = popSTACK();
  382. from_readtable = popSTACK();
  383. to_readtable = popSTACK();
  384. stable1 = Car(TheReadtable(from_readtable)->readtable_syntax_table);
  385. stable2 = TheReadtable(to_readtable)->readtable_syntax_table;
  386. Cdr(stable2) = newht;
  387. stable2 = Car(stable2);
  388. }
  389. #else
  390. stable1 = TheReadtable(from_readtable)->readtable_syntax_table;
  391. stable2 = TheReadtable(to_readtable)->readtable_syntax_table;
  392. #endif
  393. var const uintB* ptr1 = &TheSbvector(stable1)->data[0];
  394. var uintB* ptr2 = &TheSbvector(stable2)->data[0];
  395. var uintC count;
  396. dotimesC(count,small_char_code_limit, { *ptr2++ = *ptr1++; } );
  397. }
  398. /* copy the macro-table: */
  399. pushSTACK(to_readtable); /* save to-readtable */
  400. {
  401. var object mtable1 = TheReadtable(from_readtable)->readtable_macro_table;
  402. var object mtable2 = TheReadtable(to_readtable)->readtable_macro_table;
  403. var uintL i;
  404. for (i = 0; i < small_char_code_limit; i++) {
  405. /* copy entry number i: */
  406. var object entry = TheSvector(mtable1)->data[i];
  407. if (simple_vector_p(entry)) {
  408. /* simple-vector is copied element for element: */
  409. pushSTACK(mtable1); pushSTACK(mtable2);
  410. entry = copy_perchar_table(entry);
  411. mtable2 = popSTACK(); mtable1 = popSTACK();
  412. }
  413. TheSvector(mtable2)->data[i] = entry;
  414. }
  415. #if (small_char_code_limit < char_code_limit)
  416. pushSTACK(mtable2);
  417. pushSTACK(mtable1);
  418. /* Allocate a new hash table.
  419. (MAKE-HASH-TABLE :KEY-TYPE 'CHARACTER
  420. :VALUE-TYPE '(OR FUNCTION SIMPLE-VECTOR)
  421. :TEST 'FASTHASH-EQ :WARN-IF-NEEDS-REHASH-AFTER-GC T) */
  422. pushSTACK(S(Ktest)); pushSTACK(S(fasthash_eq));
  423. pushSTACK(S(Kwarn_if_needs_rehash_after_gc)); pushSTACK(T);
  424. funcall(L(make_hash_table),4);
  425. mtable1 = STACK_0;
  426. STACK_0 = value1;
  427. /* stack layout: mtable2, newht. */
  428. map_hashtable(TheSvector(mtable1)->data[small_char_code_limit],ch,entry, {
  429. if (simple_vector_p(entry))
  430. entry = copy_perchar_table(entry);
  431. shifthash(STACK_(0+1),ch,entry,true);
  432. });
  433. TheSvector(STACK_1)->data[small_char_code_limit] = STACK_0;
  434. skipSTACK(2);
  435. #endif
  436. }
  437. return popSTACK(); /* to-readtable as result */
  438. }
  439. /* UP: copies a readtable
  440. copy_readtable(readtable)
  441. > readtable: Readtable
  442. < result: copy of readtable, semantically equivalent
  443. can trigger GC */
  444. local maygc object copy_readtable (object from_readtable) {
  445. pushSTACK(from_readtable); /* save */
  446. pushSTACK(allocate_syntax_table()); /* new empty syntaxtable */
  447. pushSTACK(allocate_perchar_table()); /* new empty macro-table */
  448. var object to_readtable = allocate_readtable(); /* new readtable */
  449. /* fill: */
  450. TheReadtable(to_readtable)->readtable_macro_table = popSTACK();
  451. TheReadtable(to_readtable)->readtable_syntax_table = popSTACK();
  452. /* and copy content: */
  453. return copy_readtable_contents(popSTACK(),to_readtable);
  454. }
  455. /* error at wrong value of *READTABLE*
  456. error_bad_readtable(); */
  457. nonreturning_function(local, error_bad_readtable, (void)) {
  458. /* correct *READTABLE*: */
  459. var object sym = S(readtablestern); /* Symbol *READTABLE* */
  460. var object oldvalue = Symbol_value(sym);
  461. Symbol_value(sym) = O(standard_readtable); /* := CL standard readtable */
  462. /* and report the error: */
  463. pushSTACK(oldvalue); /* TYPE-ERROR slot DATUM */
  464. pushSTACK(S(readtable)); /* TYPE-ERROR slot EXPECTED-TYPE */
  465. pushSTACK(sym);
  466. error(type_error,
  467. GETTEXT("The value of ~S was not a readtable. It has been reset."));
  468. }
  469. /* Macro: fetches the current readtable.
  470. get_readtable(readtable =);
  471. < readtable : the current readtable */
  472. #if 0
  473. #define get_readtable(assignment) \
  474. { if (!readtablep(Symbol_value(S(readtablestern)))) \
  475. { error_bad_readtable(); } \
  476. assignment Symbol_value(S(readtablestern)); }
  477. #else /* or (optimized): */
  478. #define get_readtable(assignment) \
  479. { if (!(orecordp(Symbol_value(S(readtablestern))) \
  480. && (Record_type( assignment Symbol_value(S(readtablestern)) ) \
  481. == Rectype_Readtable))) \
  482. { error_bad_readtable(); }}
  483. #endif
  484. /* =======================================================================
  485. Initialization
  486. ======================================================================= */
  487. /* UP: Initializes the reader.
  488. init_reader();
  489. can trigger GC */
  490. global maygc void init_reader (void) {
  491. /* initialize *READ-BASE*: */
  492. define_variable(S(read_base),fixnum(10)); /* *READ-BASE* := 10 */
  493. /* initialize *READ-SUPPRESS*: */
  494. define_variable(S(read_suppress),NIL); /* *READ-SUPPRESS* := NIL */
  495. /* initialize *READ-EVAL*: */
  496. define_variable(S(read_eval),T); /* *READ-EVAL* := T */
  497. /* initialize *READING-ARRAY* */
  498. define_variable(S(reading_array),NIL); /* *READING-ARRAY* := NIL */
  499. /* initialize *READING-STRUCT* */
  500. define_variable(S(reading_struct),NIL); /* *READING-STRUCT* := NIL */
  501. { /* initialize *READTABLE*: */
  502. var object readtable = orig_readtable();
  503. O(standard_readtable) = readtable; /* that is the standard-readtable, */
  504. readtable = copy_readtable(readtable); /* one copy of it */
  505. define_variable(S(readtablestern),readtable); /* =: *READTABLE* */
  506. }
  507. /* initialize token_buff_1 and token_buff_2: */
  508. O(token_buff_1) = NIL;
  509. /* token_buff_1 and token_buff_2 will be initialized
  510. with a semi-simple-string and a semi-simple-byte-vector
  511. at the first call of get_buffers (see below).
  512. Displaced-String initialisieren:
  513. new array (with data-vector NIL), Displaced, rank=1 */
  514. O(displaced_string) =
  515. allocate_iarray(bit(arrayflags_displaced_bit)|
  516. bit(arrayflags_dispoffset_bit)|
  517. Atype_Char,
  518. 1,
  519. Array_type_string);
  520. }
  521. /* (SYS::%DEFIO dispatch-reader vector-index) post-initialises the I/O. */
  522. LISPFUNN(defio,2) {
  523. O(dispatch_reader) = STACK_1;
  524. O(dispatch_reader_index) = STACK_0;
  525. VALUES0; skipSTACK(2);
  526. }
  527. /* ======================================================================
  528. LISP - Functions for readtables
  529. ====================================================================== */
  530. /* error, if argument is no Readtable.
  531. check_readtable(obj);
  532. > obj: possibly erroneous Argument
  533. can trigger GC */
  534. local maygc object check_readtable (object obj) {
  535. while (!readtablep(obj)) {
  536. pushSTACK(NIL); /* no PLACE */
  537. pushSTACK(obj); /* TYPE-ERROR slot DATUM */
  538. pushSTACK(S(readtable)); /* TYPE-ERROR slot EXPECTED-TYPE */
  539. pushSTACK(S(readtable)); pushSTACK(obj);
  540. pushSTACK(TheSubr(subr_self)->name);
  541. check_value(type_error,GETTEXT("~S: argument ~S is not a ~S"));
  542. obj = value1;
  543. }
  544. return obj;
  545. }
  546. LISPFUN(copy_readtable,seclass_read,0,2,norest,nokey,0,NIL)
  547. { /* (COPY-READTABLE [from-readtable [to-readtable]]), CLTL p. 361 */
  548. var object from_readtable = STACK_1;
  549. if (!boundp(from_readtable)) {
  550. /* no arguments are given */
  551. get_readtable(from_readtable=); /* current readtable */
  552. VALUES1(copy_readtable(from_readtable));
  553. } else {
  554. if (nullp(from_readtable))
  555. /* instead of NIL take the standard-readtable */
  556. from_readtable = STACK_1 = O(standard_readtable);
  557. else /* check from-readtable: */
  558. from_readtable = STACK_1 = check_readtable(from_readtable);
  559. /* from-readtable is OK */
  560. var object to_readtable = STACK_0;
  561. if (missingp(to_readtable))
  562. /* copy from-readtable, without to-readtable */
  563. VALUES1(copy_readtable(from_readtable));
  564. else { /* check to-readtable and perform the copying: */
  565. to_readtable = check_readtable(to_readtable);
  566. from_readtable = STACK_1; /* restore: check_readtable() may cons */
  567. VALUES1(copy_readtable_contents(from_readtable,to_readtable));
  568. }
  569. }
  570. skipSTACK(2);
  571. }
  572. LISPFUN(set_syntax_from_char,seclass_default,2,2,norest,nokey,0,NIL)
  573. { /* (SET-SYNTAX-FROM-CHAR to-char from-char [to-readtable [from-readtable]]),
  574. CLTL p. 361 */
  575. var chart to_char = char_code(check_char(STACK_3));
  576. var chart from_char = char_code(check_char(STACK_2));
  577. var object to_readtable = STACK_1;
  578. /* check to-readtable: */
  579. if (!boundp(to_readtable)) { /* default is the current readtable */
  580. get_readtable(to_readtable=STACK_1=);
  581. } else
  582. to_readtable = STACK_1 = check_readtable(to_readtable);
  583. /* check from-readtable: */
  584. var object from_readtable = STACK_0;
  585. if (missingp(from_readtable)) { /* default is the standard-readtable */
  586. STACK_0 = from_readtable = O(standard_readtable);
  587. } else {
  588. STACK_0 = from_readtable = check_readtable(from_readtable);
  589. to_readtable = STACK_1; /* restore: check_readtable() may cons */
  590. }
  591. /* now to_char, from_char, to_readtable, from_readtable are OK. */
  592. /* copy syntaxcode: */
  593. syntax_readtable_put(to_readtable,to_char,
  594. syntax_readtable_get(from_readtable,from_char));
  595. /* copy macro-function/vector: */
  596. var object entry =
  597. perchar_table_get(TheReadtable(STACK_0)->readtable_macro_table,from_char);
  598. if (simple_vector_p(entry))
  599. /* if entry is a simple-vector, it must be copied: */
  600. entry = copy_perchar_table(entry);
  601. perchar_table_put(TheReadtable(STACK_1)->readtable_macro_table,to_char,entry);
  602. VALUES1(T);
  603. skipSTACK(4);
  604. }
  605. /* UP: checks an optional readtable-argument,
  606. with default = current readtable.
  607. > readtable: Argument
  608. < result: readtable
  609. can trigger GC */
  610. local maygc object test_readtable_arg (object readtable) {
  611. if (!boundp(readtable)) {
  612. get_readtable(readtable=); /* the current readtable is default */
  613. } else
  614. readtable = check_readtable(readtable);
  615. return readtable;
  616. }
  617. /* UP: checks an optional readtable-argument,
  618. with default = current readtable, nil = standard-readtable.
  619. > readtable: Argument
  620. < result: readtable
  621. can trigger GC */
  622. local maygc object test_readtable_null_arg (object readtable) {
  623. if (!boundp(readtable)) {
  624. get_readtable(readtable=); /* the current readtable is default */
  625. } else if (nullp(readtable)) {
  626. readtable = O(standard_readtable); /* respectively the standard-readtable */
  627. } else
  628. readtable = check_readtable(readtable);
  629. return readtable;
  630. }
  631. /* UP: checks the next-to-last optional argument of
  632. SET-MACRO-CHARACTER and MAKE-DISPATCH-MACRO-CHARACTER.
  633. > arg: non-terminating-p - Argument
  634. < result: new syntaxcode */
  635. local uintB test_nontermp_arg (object arg) {
  636. if (missingp(arg))
  637. return syntax_t_macro; /* terminating is default */
  638. else
  639. return syntax_nt_macro; /* non-terminating-p given and /= NIL */
  640. }
  641. LISPFUN(set_macro_character,seclass_default,2,2,norest,nokey,0,NIL)
  642. { /* (SET-MACRO-CHARACTER char function [non-terminating-p [readtable]]),
  643. CLTL p. 362 */
  644. var chart c = char_code(check_char(STACK_3));
  645. { /* check function and convert into an object of type FUNCTION: */
  646. var object function = coerce_function(STACK_2);
  647. if (cclosurep(function)
  648. && eq(TheCclosure(function)->clos_codevec,
  649. TheCclosure(O(dispatch_reader))->clos_codevec)) {
  650. var object vector =
  651. TheCclosure(function)->clos_consts[posfixnum_to_V(O(dispatch_reader_index))];
  652. if (simple_vector_p(vector)) {
  653. /* It's a clone of #'dispatch-reader. Pull out the vector. */
  654. function = copy_perchar_table(vector);
  655. }
  656. }
  657. STACK_2 = function;
  658. }
  659. var object readtable = test_readtable_arg(popSTACK()); /* readtable */
  660. var uintB syntaxcode = test_nontermp_arg(popSTACK()); /* new syntaxcode */
  661. STACK_1 = readtable;
  662. /* set syntaxcode: */
  663. syntax_table_put(TheReadtable(readtable)->readtable_syntax_table,c,syntaxcode);
  664. /* add macrodefinition: */
  665. perchar_table_put(TheReadtable(STACK_1)->readtable_macro_table,c,STACK_0);
  666. VALUES1(T);
  667. skipSTACK(2);
  668. }
  669. LISPFUN(get_macro_character,seclass_read,1,1,norest,nokey,0,NIL)
  670. { /* (GET-MACRO-CHARACTER char [readtable]), CLTL p. 362 */
  671. var chart c = char_code(check_char(STACK_1));
  672. var object readtable = test_readtable_null_arg(STACK_0); /* Readtable */
  673. skipSTACK(2);
  674. /* Test the Syntaxcode: */
  675. var object nontermp = NIL; /* non-terminating-p Flag */
  676. switch (syntax_readtable_get(readtable,c)) {
  677. case syntax_nt_macro: { nontermp = T; }
  678. case syntax_t_macro: { /* nontermp = NIL; */
  679. /* c is a macro-character. */
  680. var object entry =
  681. perchar_table_get(TheReadtable(readtable)->readtable_macro_table,c);
  682. if (simple_vector_p(entry)) {
  683. /* c is a dispatch-macro-character. */
  684. if (nullp(O(dispatch_reader))) {
  685. /* Shouldn't happen (bootstrapping problem). */
  686. pushSTACK(code_char(c));
  687. pushSTACK(TheSubr(subr_self)->name);
  688. error(error_condition,GETTEXT("~S: ~S is a dispatch macro character"));
  689. }
  690. /* Clone #'dispatch-reader. */
  691. pushSTACK(copy_perchar_table(entry));
  692. var object newclos = allocate_cclosure_copy(O(dispatch_reader));
  693. do_cclosure_copy(newclos,O(dispatch_reader));
  694. TheCclosure(newclos)->clos_consts[posfixnum_to_V(O(dispatch_reader_index))] = popSTACK();
  695. value1 = newclos;
  696. } else
  697. value1 = entry;
  698. } break;
  699. default: /* nontermp = NIL; */
  700. value1 = NIL; break;
  701. }
  702. value2 = nontermp; mv_count=2; /* nontermp as second value */
  703. }
  704. LISPFUN(make_dispatch_macro_character,seclass_default,1,2,norest,nokey,0,NIL)
  705. { /* (MAKE-DISPATCH-MACRO-CHARACTER char [non-terminating-p [readtable]]),
  706. CLTL p. 363 */
  707. var object readtable = test_readtable_arg(STACK_0); /* Readtable */
  708. var uintB syntaxcode = test_nontermp_arg(STACK_1); /* new syntaxcode */
  709. STACK_1 = readtable;
  710. var chart c = char_code(check_char(STACK_2));
  711. /* fetch new (empty) dispatch-macro-table: */
  712. STACK_0 = allocate_perchar_table(); /* vector, filled with NIL */
  713. /* store everything in the readtable: */
  714. /* syntaxcode into syntax-table: */
  715. syntax_table_put(TheReadtable(STACK_1)->readtable_syntax_table,c,syntaxcode);
  716. /* new dispatch-macro-table into the macrodefinition table: */
  717. perchar_table_put(TheReadtable(STACK_1)->readtable_macro_table,c,STACK_0);
  718. VALUES1(T);
  719. skipSTACK(3);
  720. }
  721. /* UP: checks the arguments disp-char and sub-char.
  722. > in STACK: *(argsp STACKop 1) = disp-char, *(argsp STACKop 0) = sub-char
  723. > STACK_0: readtable
  724. < result: the dispatch-macro-table for disp-char,
  725. nullobj if sub-char is a digit.
  726. can trigger GC */
  727. local maygc object test_disp_sub_char (gcv_object_t* argsp) {
  728. var object sub_ch = check_char(*(argsp STACKop 0)); /* sub-char */
  729. retry_disp_ch:
  730. var object disp_ch = check_char(*(argsp STACKop 1)); /* disp-char */
  731. var chart disp_c = char_code(disp_ch);
  732. var object entry =
  733. perchar_table_get(TheReadtable(STACK_0)->readtable_macro_table,disp_c);
  734. if (!simple_vector_p(entry)) {
  735. pushSTACK(NIL); /* no PLACE */
  736. pushSTACK(disp_ch);
  737. pushSTACK(TheSubr(subr_self)->name);
  738. check_value(error_condition,GETTEXT("~S: ~S is not a dispatch macro character"));
  739. *(argsp STACKop 1) = value1;
  740. goto retry_disp_ch;
  741. }
  742. /* disp-char is a dispatching-macro-character, entry is the vector. */
  743. var cint sub_c = as_cint(up_case(char_code(sub_ch))); /* convert sub-char into upper case */
  744. if ((sub_c >= '0') && (sub_c <= '9')) /* digit */
  745. return nullobj;
  746. else /* valid sub-char */
  747. return entry;
  748. }
  749. LISPFUN(set_dispatch_macro_character,seclass_default,3,1,norest,nokey,0,NIL)
  750. { /* (SET-DISPATCH-MACRO-CHARACTER disp-char sub-char function [readtable]),
  751. CLTL p. 364 */
  752. /* check function and convert it into an object of Type FUNCTION: */
  753. STACK_1 = coerce_function(STACK_1);
  754. STACK_0 = test_readtable_arg(STACK_0); /* Readtable */
  755. var object dm_table = test_disp_sub_char(&STACK_2);
  756. if (eq(dm_table,nullobj)) {
  757. pushSTACK(STACK_2); /* sub-char, TYPE-ERROR slot DATUM */
  758. pushSTACK(O(type_not_digit)); /* TYPE-ERROR slot EXPECTED-TYPE */
  759. pushSTACK(STACK_(2+2));
  760. pushSTACK(TheSubr(subr_self)->name);
  761. error(type_error,GETTEXT("~S: digit ~C not allowed as sub-char"));
  762. } else {
  763. /* add function to the dispatch-macro-table */
  764. perchar_table_put(dm_table,up_case(char_code(STACK_2)),STACK_1);
  765. VALUES1(T); skipSTACK(4);
  766. }
  767. }
  768. LISPFUN(get_dispatch_macro_character,seclass_read,2,1,norest,nokey,0,NIL)
  769. { /* (GET-DISPATCH-MACRO-CHARACTER disp-char sub-char [readtable]),
  770. CLTL p. 364 */
  771. STACK_0 = test_readtable_null_arg(STACK_0); /* readtable */
  772. var object dm_table = test_disp_sub_char(&STACK_1);
  773. VALUES1(eq(dm_table,nullobj) ? NIL /* NIL or Function as value */
  774. : perchar_table_get(dm_table,up_case(char_code(STACK_1))));
  775. skipSTACK(3);
  776. }
  777. #define RTCase(rt) ((uintW)posfixnum_to_V(TheReadtable(rt)->readtable_case))
  778. LISPFUNN(readtable_case,1)
  779. { /* (READTABLE-CASE readtable), CLTL2 S. 549 */
  780. var object readtable = check_readtable(popSTACK()); /* Readtable */
  781. VALUES1((&O(rtcase_0))[RTCase(readtable)]);
  782. }
  783. LISPFUNN(set_readtable_case,2)
  784. { /* (SYSTEM::SET-READTABLE-CASE readtable value), CLTL2 p. 549 */
  785. var object value = popSTACK();
  786. retry_readtable_case:
  787. /* convert symbol value into an index by searching in table O(rtcase..): */
  788. var const gcv_object_t* ptr = &O(rtcase_0);
  789. var uintC rtcase = 0;
  790. var uintC count = 4;
  791. while (count--) {
  792. if (eq(*ptr,value))
  793. goto found;
  794. ptr++; rtcase++;
  795. };
  796. { /* invalid value */
  797. pushSTACK(NIL); /* no PLACE */
  798. pushSTACK(value); /* TYPE-ERROR slot DATUM */
  799. pushSTACK(O(type_rtcase)); /* TYPE-ERROR slot EXPECTED-TYPE */
  800. pushSTACK(O(rtcase_3)); pushSTACK(O(rtcase_2));
  801. pushSTACK(O(rtcase_1)); pushSTACK(O(rtcase_0));
  802. pushSTACK(value);
  803. pushSTACK(S(set_readtable_case));
  804. check_value(type_error,GETTEXT("~S: new value ~S should be ~S, ~S, ~S or ~S."));
  805. value = value1;
  806. }
  807. goto retry_readtable_case;
  808. found: /* found in table */
  809. var object readtable = check_readtable(popSTACK()); /* readtable */
  810. TheReadtable(readtable)->readtable_case = fixnum(rtcase);
  811. VALUES1(*ptr);
  812. }
  813. /* ======================================================================
  814. some auxiliary routines and macros for READ and PRINT
  815. ====================================================================== */
  816. /* UP: fetches the value of a symbol. must be fixnum >=2, <=36.
  817. get_base(symbol)
  818. > symbol: Symbol
  819. < result: value of the Symbols, >=2, <=36. */
  820. local uintL get_base (object symbol) {
  821. var object value = Symbol_value(symbol);
  822. var uintV intvalue;
  823. if (posfixnump(value)
  824. && (intvalue = posfixnum_to_V(value),
  825. ((intvalue >= 2) && (intvalue <= 36)))) {
  826. return intvalue;
  827. } else {
  828. Symbol_value(symbol) = fixnum(10);
  829. pushSTACK(value); /* TYPE-ERROR slot DATUM */
  830. pushSTACK(O(type_radix)); /* TYPE-ERROR slot EXPECTED-TYPE */
  831. pushSTACK(value);
  832. pushSTACK(symbol);
  833. error(type_error,
  834. GETTEXT("The value of ~S should be an integer between 2 and 36, not ~S.\n"
  835. "It has been reset to 10."));
  836. }
  837. }
  838. /* UP: fetches the value of *PRINT-BASE*
  839. get_print_base()
  840. < uintL result: >=2, <=36 */
  841. #define get_print_base() \
  842. (!nullpSv(print_readably) ? 10 : get_base(S(print_base)))
  843. /* UP: fetches the value of *READ-BASE*
  844. get_read_base()
  845. < uintL result: >=2, <=36 */
  846. #define get_read_base() get_base(S(read_base))
  847. /* ======================================================================
  848. R E A D
  849. ====================================================================== */
  850. /* Characters are read one by one.
  851. Their syntax codes are determined by use the readtable, cf. CLTL table 22-1.
  852. Syntax code 'constituent' starts a new (extended) token.
  853. For every character in the token, its attribute a_xxxx is looked up by use
  854. of the attribute table, cf. CLTL table 22-3.
  855. O(token_buff_1) is a semi-simple-string, which contains the characters of
  856. the currently read extended-token.
  857. O(token_buff_2) is a semi-simple-byte-vektor, which contains the attributes
  858. of the currently read extended-token.
  859. Both have the same length (in characters respectively bytes).
  860. Special objects, that can be returned by READ:
  861. eof_value: special object, that indicates EOF
  862. dot_value: auxiliary value for the detection of single dots
  863. ------------------------ READ on character-level ---------------------------
  864. error, if read object is not a character:
  865. error_charread(ch,&stream); */
  866. nonreturning_function(local, error_charread, (object ch, const gcv_object_t* stream_)) {
  867. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  868. pushSTACK(ch); /* Character */
  869. pushSTACK(*stream_); /* Stream */
  870. pushSTACK(S(read));
  871. error(stream_error,
  872. GETTEXT("~S from ~S: character read should be a character: ~S"));
  873. }
  874. /* UP: Reads a character and calculates its syntaxcode.
  875. read_char_syntax(ch=,scode=,&stream);
  876. > stream: Stream
  877. < stream: Stream
  878. < object ch: Character or eof_value
  879. < uintWL scode: Syntaxcode (from the current readtable) respectively syntax_eof
  880. can trigger GC */
  881. #define read_char_syntax(ch_assignment,scode_assignment,stream_) \
  882. { var object ch0 = read_char(stream_); /* read character */ \
  883. ch_assignment ch0; \
  884. if (eq(ch0,eof_value)) /* EOF ? */ \
  885. { scode_assignment syntax_eof; } \
  886. else { /* Check for character: */ \
  887. if (!charp(ch0)) { error_charread(ch0,stream_); } \
  888. {var object readtable; \
  889. get_readtable(readtable = ); \
  890. scode_assignment /* fetch syntaxcode from table */ \
  891. syntax_readtable_get(readtable,char_code(ch0)); \
  892. }}}
  893. /* error-message at EOF outside of objects
  894. error_eof_outside(&stream);
  895. > stream: Stream */
  896. nonreturning_function(local, error_eof_outside, (const gcv_object_t* stream_)) {
  897. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  898. pushSTACK(*stream_); /* Stream */
  899. pushSTACK(S(read));
  900. error(end_of_file,GETTEXT("~S: input stream ~S has reached its end"));
  901. }
  902. /* error-message at EOF inside of objects
  903. error_eof_inside(&stream);
  904. > stream: Stream */
  905. nonreturning_function(local, error_eof_inside, (const gcv_object_t* stream_)) {
  906. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  907. if (posfixnump(Symbol_value(S(read_line_number)))) { /* check SYS::*READ-LINE-NUMBER* */
  908. pushSTACK(Symbol_value(S(read_line_number))); /* line-number */
  909. pushSTACK(*stream_); /* Stream */
  910. pushSTACK(S(read));
  911. error(end_of_file,GETTEXT("~S: input stream ~S ends within an object. Last opening parenthesis probably in line ~S."));
  912. } else {
  913. pushSTACK(*stream_); /* Stream */
  914. pushSTACK(S(read));
  915. error(end_of_file,GETTEXT("~S: input stream ~S ends within an object"));
  916. }
  917. }
  918. /* error-message at EOF, according to *READ-RECURSIVE-P*
  919. error_eof(&stream);
  920. > stream: Stream */
  921. nonreturning_function(local, error_eof, (const gcv_object_t* stream_)) {
  922. if (!nullpSv(read_recursive_p)) /* *READ-RECURSIVE-P* /= NIL ? */
  923. error_eof_inside(stream_);
  924. else
  925. error_eof_outside(stream_);
  926. }
  927. /* UP: read up to the next non-whitespace-character, without consuming it
  928. At EOF --> Error.
  929. wpeek_char_syntax(ch=,scode=,&stream);
  930. > stream: Stream
  931. < stream: Stream
  932. < object ch: next character
  933. < uintWL scode: its syntaxcode
  934. can trigger GC */
  935. #define wpeek_char_syntax(ch_assignment,scode_assignment,stream_) \
  936. { while (1) { \
  937. object ch0 = read_char(stream_); /* read Character */ \
  938. if (eq(ch0,eof_value)) { error_eof(stream_); } /* EOF -> Error */ \
  939. /* check for Character: */ \
  940. if (!charp(ch0)) { error_charread(ch0,stream_); } \
  941. {var object readtable; \
  942. get_readtable(readtable = ); \
  943. if (!((scode_assignment /* fetch Syntaxcode from table */ \
  944. syntax_readtable_get(readtable,char_code(ch0))) \
  945. == syntax_whitespace)) \
  946. /* no Whitespace -> push back last read character */ \
  947. { unread_char(stream_,ch0); ch_assignment ch0; break; } \
  948. }}}
  949. /* UP: read up to the next non-whitespace-character, without consuming it.
  950. wpeek_char_eof(&stream)
  951. > stream: Stream
  952. < stream: Stream
  953. < result: next character or eof_value
  954. can trigger GC */
  955. local maygc object wpeek_char_eof (const gcv_object_t* stream_) {
  956. while (1) {
  957. var object ch = peek_char(stream_); /* peek character */
  958. if (eq(ch,eof_value)) /* EOF ? */
  959. return ch;
  960. /* check for Character: */
  961. if (!charp(ch))
  962. error_charread(ch,stream_);
  963. var object readtable;
  964. get_readtable(readtable = );
  965. if (!(( /* fetch Syntaxcode from table */
  966. syntax_readtable_get(readtable,char_code(ch)))
  967. == syntax_whitespace))
  968. return ch;
  969. read_char(stream_); /* drop the last (whitespace) character */
  970. }
  971. }
  972. /* ------------------- READ at token-level -------------------------------
  973. read_token and test_potential_number_syntax, test_number_syntax need
  974. the attributes according to CLTL table 22-3.
  975. During test_potential_number_syntax attributes are transformed,
  976. a_digit partially into a_alpha or a_letter or a_expo_m.
  977. meaning of the entries in attribute_table: */
  978. #define a_illg 0 /* illegal constituent */
  979. #define a_pack_m 1 /* ':' = Package-marker */
  980. #define a_alpha 2 /* character without special property (alphabetic) */
  981. #define a_escaped 3 /* character without special property, not subject to case conversion */
  982. #define a_ratio 4 /* '/' */
  983. #define a_dot 5 /* '.' */
  984. #define a_plus 6 /* '+' */
  985. #define a_minus 7 /* '-' */
  986. #define a_extens 8 /* '_^' extension characters */
  987. #define a_digit 9 /* '0123456789' */
  988. #define a_letterdigit 10 /* 'A'-'Z','a'-'z' less than base, not 'esfdlESFDL' */
  989. #define a_expodigit 11 /* 'esfdlESFDL' less than base */
  990. #define a_letter 12 /* 'A'-'Z','a'-'z', not 'esfdlESFDL' */
  991. #define a_expo_m 13 /* 'esfdlESFDL' */
  992. /* >= a_letter - 'A'-'Z','a'-'z'
  993. >= a_digit - '0123456789','A'-'Z','a'-'z'
  994. >= a_ratio - what a potential number must consist of */
  995. /* attribute-table for constituents, first interpretation:
  996. note: first, 0-9,A-Z,a-z are interpreted as a_digit or a_expo_m,
  997. then (if no integer can be deduced out of token), a_digit
  998. is interpreted as a_alpha (alphabetic) above of *READ-BASE*. */
  999. local const uintB attribute_table[small_char_code_limit] = {
  1000. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, /* chr(0) upto chr(7) */
  1001. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, /* chr(8) upto chr(15) */
  1002. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, /* chr(16) upto chr(23) */
  1003. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, /* chr(24) upto chr(31) */
  1004. a_illg, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, /* ' !"#$%&'' */
  1005. a_alpha, a_alpha, a_alpha, a_plus, a_alpha, a_minus, a_dot, a_ratio, /* '()*+,-./' */
  1006. a_digit, a_digit, a_digit, a_digit, a_digit, a_digit, a_digit, a_digit, /* '01234567' */
  1007. a_digit, a_digit, a_pack_m,a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, /* '89:;<=>?' */
  1008. a_alpha, a_letter,a_letter,a_letter,a_expo_m,a_expo_m,a_expo_m,a_letter, /* '@ABCDEFG' */
  1009. a_letter,a_letter,a_letter,a_letter,a_expo_m,a_letter,a_letter,a_letter, /* 'HIJKLMNO' */
  1010. a_letter,a_letter,a_letter,a_expo_m,a_letter,a_letter,a_letter,a_letter, /* 'PQRSTUVW' */
  1011. a_letter,a_letter,a_letter,a_alpha, a_alpha, a_alpha, a_extens,a_extens, /* 'XYZ[\]^_' */
  1012. a_alpha, a_letter,a_letter,a_letter,a_expo_m,a_expo_m,a_expo_m,a_letter, /* '`abcdefg' */
  1013. a_letter,a_letter,a_letter,a_letter,a_expo_m,a_letter,a_letter,a_letter, /* 'hijklmno' */
  1014. a_letter,a_letter,a_letter,a_expo_m,a_letter,a_letter,a_letter,a_letter, /* 'pqrstuvw' */
  1015. a_letter,a_letter,a_letter,a_alpha, a_alpha, a_alpha, a_alpha, /* 'xyz{|}~' */
  1016. #if defined(UNICODE) || defined(ISOLATIN_CHS) || defined(HPROMAN8_CHS)
  1017. a_illg,
  1018. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1019. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1020. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1021. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1022. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1023. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1024. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1025. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1026. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1027. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1028. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1029. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1030. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1031. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1032. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1033. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1034. #elif defined(NEXTSTEP_CHS)
  1035. a_illg,
  1036. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1037. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1038. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1039. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1040. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1041. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1042. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1043. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1044. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1045. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1046. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1047. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1048. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1049. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1050. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1051. a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha, a_alpha,
  1052. #else /* defined(ASCII_CHS) && !defined(UNICODE) */
  1053. a_illg,
  1054. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1055. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1056. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1057. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1058. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1059. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1060. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1061. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1062. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1063. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1064. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1065. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1066. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1067. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1068. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1069. a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg, a_illg,
  1070. #endif
  1071. };
  1072. /* Returns the attribute code for a character code.
  1073. attribute_of(c)
  1074. > chart c: character code
  1075. < uintB result: attribute code */
  1076. #if (small_char_code_limit < char_code_limit) /* i.e. defined(UNICODE) */
  1077. #define attribute_of(c) \
  1078. (uintB)(as_cint(c) < small_char_code_limit \
  1079. ? attribute_table[as_cint(c)] \
  1080. : (graphic_char_p(c) ? a_alpha : a_illg))
  1081. #else
  1082. #define attribute_of(c) attribute_table[as_cint(c)]
  1083. #endif
  1084. /* Flag. indicates, if a single-escape- or multiple-escape-character
  1085. occurred in the last read token: */
  1086. local bool token_escape_flag;
  1087. /* UP: delivers two buffers.
  1088. if two buffers are available in the reservoir O(token_buff_1), O(token_buff_2),
  1089. they are extracted. Otherwise new ones are allocated.
  1090. If the buffers are not needed anymore, they can be written back to
  1091. O(token_buff_1) and O(token_buff_2).
  1092. < STACK_1: a Semi-Simple String with Fill-Pointer 0
  1093. < STACK_0: a Semi-Simple Byte-Vector with Fill-Pointer 0
  1094. < STACK: decreased by 2
  1095. can trigger GC */
  1096. local maygc void get_buffers (void) {
  1097. /* Mechanism:
  1098. O(token_buff_1) and O(token_buff_2) hold a Semi-Simple-String
  1099. and a Semi-Simple-Byte-Vector, which are extracted if necessary (and marked
  1100. with O(token_buff_1) := NIL as extracted)
  1101. After use, they can be stored back again. Reentrant! */
  1102. var object buff_1 = O(token_buff_1);
  1103. if (!nullp(buff_1)) {
  1104. /* extract buffer and empty: */
  1105. TheIarray(buff_1)->dims[1] = 0; /* Fill-Pointer:=0 */
  1106. pushSTACK(buff_1); /* 1. buffer finished */
  1107. var object buff_2 = O(token_buff_2);
  1108. TheIarray(buff_2)->dims[1] = 0; /* Fill-Pointer:=0 */
  1109. pushSTACK(buff_2); /* 2. buffer finished */
  1110. O(token_buff_1) = NIL; /* mark buffer as extracted */
  1111. } else {
  1112. /* buffers are extracted. New ones must be allocated:
  1113. new Semi-Simple-String with Fill-Pointer=0 : */
  1114. pushSTACK(make_ssstring(SEMI_SIMPLE_DEFAULT_SIZE));
  1115. /* new Semi-Simple-Byte-Vector with Fill-Pointer=0 : */
  1116. pushSTACK(make_ssbvector(SEMI_SIMPLE_DEFAULT_SIZE));
  1117. }
  1118. }
  1119. /* UP: Reads an Extended Token.
  1120. read_token(&stream);
  1121. > stream: Stream
  1122. < stream: Stream
  1123. < O(token_buff_1): read Characters
  1124. < O(token_buff_2): their Attributcodes
  1125. < token_escape_flag: Escape-Character-Flag
  1126. can trigger GC */
  1127. local maygc void read_token (const gcv_object_t* stream_);
  1128. /* UP: reads an extended token, first character has already been read.
  1129. read_token_1(&stream,ch,scode);
  1130. > stream: Stream
  1131. > ch, scode: first character and its syntaxcode
  1132. < stream: Stream
  1133. < O(token_buff_1): read characters
  1134. < O(token_buff_2): their attributcodes
  1135. < token_escape_flag: Escape-character-Flag
  1136. can trigger GC */
  1137. local maygc void read_token_1 (const gcv_object_t* stream_, object ch, uintWL scode);
  1138. local maygc void read_token (const gcv_object_t* stream_) {
  1139. /* read first character: */
  1140. var object ch;
  1141. var uintWL scode;
  1142. read_char_syntax(ch = ,scode = ,stream_);
  1143. /* build up token: */
  1144. read_token_1(stream_,ch,scode);
  1145. }
  1146. local maygc void read_token_1 (const gcv_object_t* stream_, object ch,
  1147. uintWL scode) {
  1148. if (terminal_stream_p(*stream_))
  1149. dynamic_bind(S(terminal_read_open_object),S(symbol));
  1150. /* fetch empty Token-Buffers, upon STACK: */
  1151. get_buffers(); /* (don't need to save ch) */
  1152. /* the two buffers lie up th the end of read_token_1 in the Stack.
  1153. (thus read_char can call read recursively...)
  1154. Afterwards (during test_potential_number_syntax, test_number_syntax,
  1155. test_dots, read_internal up to the end of read_internal)
  1156. the buffers lie in O(token_buff_1) and O(token_buff_2). After the return of
  1157. read_internal their content is useless, and they can be used for further
  1158. read-operations. */
  1159. var bool multiple_escape_flag = false;
  1160. var bool escape_flag = false;
  1161. var bool fasl_stream = stream_get_fasl(*stream_); /* don't need to save ch */
  1162. goto char_read;
  1163. while (1) {
  1164. /* Here the token in STACK_1 (Semi-Simple-String for characters)
  1165. and STACK_0 (Semi-Simple-Byte-Vector for attributecodes) is constructed.
  1166. Multiple-Escape-Flag indicates, if we are situated between |...|.
  1167. Escape-Flag indicates, if a Escape-Character has appeared. */
  1168. read_char_syntax(ch = ,scode = ,stream_); /* read next character */
  1169. char_read:
  1170. switch(scode) {
  1171. case syntax_illegal: {
  1172. if (multiple_escape_flag) goto escape;
  1173. /* illegal -> issue Error: */
  1174. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  1175. pushSTACK(ch); /* character */
  1176. pushSTACK(*stream_); /* Stream */
  1177. pushSTACK(S(read));
  1178. error(reader_error, /* ANSI CL 2.2. wants a reader-error here */
  1179. GETTEXT("~S from ~S: illegal character ~S"));
  1180. } break;
  1181. case syntax_single_esc: /* Single-Escape-Character -> */
  1182. /* read next character and take over unchanged */
  1183. escape_flag = true;
  1184. read_char_syntax(ch = ,scode = ,stream_); /* read next character */
  1185. if (scode==syntax_eof) { /* reached EOF? */
  1186. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  1187. pushSTACK(*stream_);
  1188. pushSTACK(S(read));
  1189. error(end_of_file,GETTEXT("~S: input stream ~S ends within a token after single escape character"));
  1190. }
  1191. if (fasl_stream && multiple_escape_flag) {
  1192. if (eq(ch,ascii_char('n')))
  1193. ch = ascii_char(0x0A); /* "\n" = #\Linefeed */
  1194. else if (eq(ch,ascii_char('r')))
  1195. ch = ascii_char(0x0D); /* "\r" = #\Return */
  1196. }
  1197. escape: /* past Escape-character:
  1198. take over character into token without change */
  1199. ssstring_push_extend(STACK_1,char_code(ch));
  1200. ssbvector_push_extend(STACK_0,a_escaped);
  1201. break;
  1202. case syntax_multi_esc: /* Multiple-Escape-character */
  1203. multiple_escape_flag = !multiple_escape_flag;
  1204. escape_flag = true;
  1205. break;
  1206. case syntax_constituent:
  1207. case syntax_nt_macro: /* normal constituent */
  1208. if (multiple_escape_flag) /* between Multiple-Escape-characters? */
  1209. goto escape; /* yes -> take over character without change */
  1210. /* take over into token (capital-conversion takes place later): */
  1211. {
  1212. var chart c = char_code(ch);
  1213. ssstring_push_extend(STACK_1,c);
  1214. ssbvector_push_extend(STACK_0,attribute_of(c));
  1215. }
  1216. break;
  1217. case syntax_whitespace:
  1218. case syntax_t_macro: /* whitespace or terminating macro -> */
  1219. /* Token ends before this Character. */
  1220. if (multiple_escape_flag) /* between multiple-escape-characters? */
  1221. goto escape; /* yes -> take over character without change */
  1222. /* Token is finished.
  1223. Push back character to the Stream,
  1224. if ( it is no Whitespace ) or
  1225. ( it is a Whitespace and also *READ-PRESERVE-WHITESPACE* /= NIL holds true). */
  1226. if ((!(scode == syntax_whitespace))
  1227. || !nullpSv(read_preserve_whitespace))
  1228. unread_char(stream_,ch);
  1229. goto ende;
  1230. case syntax_eof: /* EOF reached. */
  1231. if (multiple_escape_flag) { /* between multiple-escape-character? */
  1232. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  1233. pushSTACK(*stream_);
  1234. pushSTACK(S(read));
  1235. error(end_of_file,GETTEXT("~S: input stream ~S ends within a token after multiple escape character"));
  1236. }
  1237. /* no -> token is finished normally */
  1238. goto ende;
  1239. default: NOTREACHED;
  1240. }
  1241. }
  1242. ende:
  1243. /* now token is finished, multiple_escape_flag = false. */
  1244. token_escape_flag = escape_flag; /* store Escape-Flag */
  1245. O(token_buff_2) = popSTACK(); /* Attributecode-Buffer */
  1246. O(token_buff_1) = popSTACK(); /* Character-Buffer */
  1247. if (terminal_stream_p(*stream_))
  1248. dynamic_unbind(S(terminal_read_open_object));
  1249. }
  1250. /* ----------- READ between token-level and object-level -------------- */
  1251. /* UP: checks, if the token-buffer contains a potential-number, and
  1252. transforms Attributecodes as preparation on read-routines for digits.
  1253. test_potential_number_syntax(&base,&token_info_t);
  1254. > O(token_buff_1): read characters
  1255. > O(token_buff_2): their attributecodes
  1256. > base: base of number-system (value of *READ-BASE* or *PRINT-BASE*)
  1257. < base: base of number-system (= 10 or old base)
  1258. conversion takes place within O(token_buff_2):
  1259. if potential number:
  1260. >=a_letter below the base of number-system -> a_letterdigit, a_expodigit
  1261. if not potential number:
  1262. distinction between [a_pack_m | a_dot | others] is preserved.
  1263. < result: true, if potential number
  1264. (and then token_info_t is filled with {charptr, attrptr, len} ) */
  1265. typedef struct {
  1266. chart* charptr;
  1267. uintB* attrptr;
  1268. uintL len;
  1269. } token_info_t;
  1270. local bool test_potential_number_syntax (uintWL* base_, token_info_t* info) {
  1271. /* A token is a potential number, if (CLTL, p. 341)
  1272. - it consists exclusively of digits, '+','-','/','^','_','.' and
  1273. Number-Markers. The base for the digits ist context-sensitive.
  1274. It is always 10, if a dot '.' is in the token.
  1275. A Number-Marker is a letter, that is no digit and
  1276. is not placed adjacent to another such letter.
  1277. - it contains at least one digit,
  1278. - it starts with a digit, '+','-','.','^' or '_',
  1279. - it does not end with '+' or '-'.
  1280. Verification:
  1281. 1. Search for a dot. if ther is one ===> Base:=10.
  1282. 2. Test, if only chars >=a_ratio are in the token. No -> no potential number.
  1283. 3. Every char that is >=a_letter (also 'A'-'Z','a'-'z') and has a value < base,
  1284. will be converted to a_letterdigit or a_expodigit.
  1285. (Now a_digit,a_letterdigit,a_expodigit is interpreted as "digit" and
  1286. >=a_letter as "letter".)
  1287. 4. Test, if an a_digit is in the token. No -> no potential number.
  1288. (No the length is >0.)
  1289. 5. Test, if adjacent >=a_letter are in the token.
  1290. Yes -> no potential number.
  1291. 6. Test, if first character attribute is >=a_dot and <=a_digit.
  1292. No -> no potential number.
  1293. 7. Test, if last character attribute is =a_plus or =a_minus.
  1294. Yes -> no potential number.
  1295. 8. Otherwise it is a potential number. */
  1296. var chart* charptr0; /* Pointer to the characters */
  1297. var uintB* attrptr0; /* Pointer to the attributes */
  1298. var uintL len; /* Length of token */
  1299. { /* initialize: */
  1300. var object buff = O(token_buff_1); /* Semi-Simple String */
  1301. len = TheIarray(buff)->dims[1]; /* length = Fill-Pointer */
  1302. charptr0 = &TheSnstring(TheIarray(buff)->data)->data[0]; /* characters from this point on */
  1303. buff = O(token_buff_2); /* Semi-Simple Byte-Vektor */
  1304. attrptr0 = &TheSbvector(TheIarray(buff)->data)->data[0]; /* attributecodes from this point on */
  1305. }
  1306. { /* 1. search, if there is a dot: */
  1307. if (len > 0) {
  1308. var uintB* attrptr = attrptr0;
  1309. var uintL count;
  1310. dotimespL(count,len, {
  1311. if (*attrptr++ == a_dot) goto dot;
  1312. });
  1313. }
  1314. /* no dot -> leave base unchanged */
  1315. goto no_dot;
  1316. /* dot -> base := 10 */
  1317. dot: *base_ = 10;
  1318. no_dot: ;
  1319. }
  1320. /* 2. Test, if only attributecodes >=a_ratio occur: */
  1321. if (len > 0) {
  1322. var uintB* attrptr = attrptr0;
  1323. var uintL count;
  1324. dotimespL(count,len, {
  1325. if (!(*attrptr++ >= a_ratio))
  1326. return false; /* no -> no potential number */
  1327. });
  1328. }
  1329. /* 3. translate everything >=a_letter with value < base into a_letterdigit, a_expodigit: */
  1330. if (len > 0) {
  1331. var uintB* attrptr = attrptr0;
  1332. var chart* charptr = charptr0;
  1333. var uintL count;
  1334. dotimespL(count,len, {
  1335. if (*attrptr >= a_letter) { /* Attributecode >= a_letter */
  1336. var cint c = as_cint(*charptr); /* character, must be 'A'-'Z','a'-'Z' */
  1337. if (c >= 'a') { c -= 'a'-'A'; }
  1338. if ((c - 'A') + 10 < *base_) /* value < base ? */
  1339. *attrptr -= 2; /* a_letter -> a_letterdigit, a_expo_m -> a_expodigit */
  1340. }
  1341. attrptr++; charptr++;
  1342. });
  1343. }
  1344. { /* 4. Test, if an a_*digit occurs: */
  1345. if (len > 0) {
  1346. var uintB* attrptr = attrptr0;
  1347. var uintL count;
  1348. dotimespL(count,len, {
  1349. var uintB attr = *attrptr++;
  1350. if (attr >= a_digit && attr <= a_expodigit)
  1351. goto digit_ok;
  1352. });
  1353. }
  1354. return false; /* no potential number */
  1355. digit_ok: ;
  1356. }
  1357. /* length len>0.
  1358. 5. Test, if two attributecodes >= a_letter follow adjacently: */
  1359. if (len > 1) {
  1360. var uintB* attrptr = attrptr0;
  1361. var uintL count;
  1362. dotimespL(count,len-1, {
  1363. if (*attrptr++ >= a_letter)
  1364. if (*attrptr >= a_letter)
  1365. return false;
  1366. });
  1367. }
  1368. { /* 6. Test, if first attributecode is >=a_dot and <=a_*digit: */
  1369. var uintB attr = attrptr0[0];
  1370. if (!((attr >= a_dot) && (attr <= a_expodigit)))
  1371. return false;
  1372. }
  1373. { /* 7. Test, if last attributecode is =a_plus or =a_minus: */
  1374. var uintB attr = attrptr0[len-1];
  1375. if ((attr == a_plus) || (attr == a_minus))
  1376. return false;
  1377. }
  1378. /* 8. It is a potential number. */
  1379. info->charptr = charptr0; info->attrptr = attrptr0; info->len = len;
  1380. return true;
  1381. }
  1382. /* UP: verifies if the token-buffer contains a number (syntax according to
  1383. CLTL Table 22-2), and provides the parameters which are necessary for
  1384. the translation into a number, where necessary.
  1385. test_number_syntax(&base,&string,&info)
  1386. > O(token_buff_1): read characters
  1387. > O(token_buff_2): their attributecodes
  1388. > token_escape_flag: Escape-Character-Flag
  1389. > base: number-system-base (value of *READ-BASE* or *PRINT-BASE*)
  1390. < base: number-system-base
  1391. < string: Normal-Simple-String with the characters
  1392. < info.sign: sign (/=0 if negative)
  1393. < result: number-type
  1394. 0 : no number (then also base,string,info are meaningless)
  1395. 1 : Integer
  1396. < index1: Index of the first digit
  1397. < index2: Index after the last digit
  1398. (that means index2-index1 digits, incl. a possible decimal
  1399. dot at the end)
  1400. 2 : Rational
  1401. < index1: Index of the first digit
  1402. < index3: Index of '/'
  1403. < index2: Index after the last digit
  1404. (that means index3-index1 numerator-digits and
  1405. index2-index3-1 denominator-digits)
  1406. 3 : Float
  1407. < index1: Index of the start of mantissa (excl. sign)
  1408. < index4: Index after the end of mantissa
  1409. < index2: Index at the end of the characters
  1410. < index3: Index after the decimal dot (=index4 if there is no dot)
  1411. (implies: mantissa with index4-index1 characters: digits and at
  1412. most one '.')
  1413. (implies: index4-index3 digits after the dot)
  1414. (implies: if index4<index2: index4 = Index of the exponent-marker,
  1415. index4+1 = index of exponenten-sign or of the first
  1416. exponenten-digit) */
  1417. typedef struct {
  1418. signean sign;
  1419. uintL index1;
  1420. uintL index2;
  1421. uintL index3;
  1422. uintL index4;
  1423. } zahl_info_t;
  1424. local uintWL test_number_syntax (uintWL* base_, object* string_,
  1425. zahl_info_t* info) {
  1426. /* Method:
  1427. 1. test for potential number.
  1428. Then there exist only Attributcodes >= a_ratio,
  1429. and with a_dot, the base=10.
  1430. 2. read sign { a_plus | a_minus | } and store.
  1431. 3. try to read token as a rational number:
  1432. test, if syntax
  1433. { a_plus | a_minus | } - already read
  1434. { a_digit < base }+ { a_ratio { a_digit < base }+ | }
  1435. is matching.
  1436. 4. set base:=10.
  1437. 5. try to interprete the token as a floating-point-number or decimal-integer:
  1438. Test, if the syntax
  1439. { a_plus | a_minus | } - already read
  1440. { a_digit }* { a_dot { a_digit }* | }
  1441. { a_expo_m { a_plus | a_minus | } { a_digit }+ | }
  1442. is matching.
  1443. if there is an exponent, there must be digits before or after the dot;
  1444. it is a float, Type will be determined by exponent-marker
  1445. (e,E deliver the value of the variable *read-default-float-format* as type).
  1446. if there is no exponent:
  1447. if there is no dot, it is not a number (should have been delivered at
  1448. step 3, but base obviously did not fit).
  1449. if decimal dot exists:
  1450. if there are digits after the dot, it is a float (type is
  1451. denoted by the variable *read-default-float-format*).
  1452. if there are no digits after the dot:
  1453. if there were digits before the dot --> decimal-integer.
  1454. otherwise no number. */
  1455. var chart* charptr0; /* Pointer to the characters */
  1456. var uintB* attrptr0; /* Pointer to the attributes */
  1457. var uintL len; /* length of the token */
  1458. { /* 1. test for potential number: */
  1459. if (token_escape_flag) /* token with escape-character -> */
  1460. return 0; /* no potential number -> no number */
  1461. /* escape-flag deleted. */
  1462. var token_info_t info;
  1463. if (!test_potential_number_syntax(base_,&info)) /* potential number ? */
  1464. return 0; /* no -> no number */
  1465. /* yes -> read outputparameter returned by test_potential_number_syntax: */
  1466. charptr0 = info.charptr;
  1467. attrptr0 = info.attrptr;
  1468. len = info.len;
  1469. }
  1470. *string_ = TheIarray(O(token_buff_1))->data; /* Normal-Simple-String */
  1471. var uintL index0 = 0;
  1472. /* read 2. sign and store: */
  1473. info->sign = 0; /* sign:=positiv */
  1474. switch (*attrptr0) {
  1475. case a_minus: info->sign = -1; /* sign:=negativ */
  1476. case a_plus: /* read over sign: */
  1477. charptr0++; attrptr0++; index0++;
  1478. default:
  1479. break;
  1480. }
  1481. info->index1 = index0; /* Startindex */
  1482. info->index2 = len; /* Endindex */
  1483. /* info->sign, info->index1 and info->index2 finished.
  1484. charptr0 and attrptr0 and index0 from now on unchanged. */
  1485. var uintB flags = 0; /* delete all flags */
  1486. { /* 3. Rational number */
  1487. var chart* charptr = charptr0;
  1488. var uintB* attrptr = attrptr0;
  1489. var uintL index = index0;
  1490. /* flags & bit(0) indicates, if an a_digit < base
  1491. has already arrived.
  1492. flags & bit(1) indicates, if an a_ratio has already arrived
  1493. (and then info->index3 is its position) */
  1494. while (index<len) { /* next character */
  1495. var uintB attr = *attrptr++; /* its attributcode */
  1496. if (attr>=a_digit && attr<=a_expodigit) {
  1497. var cint c = as_cint(*charptr++); /* character (Digit, namely '0'-'9','A'-'Z','a'-'z') */
  1498. /* determine value: */
  1499. var uintB value = (c<'A' ? c-'0' : c<'a' ? c-'A'+10 : c-'a'+10);
  1500. if (value >= *base_) /* Digit with value >=base ? */
  1501. goto schritt4; /* yes -> no rational number */
  1502. /* Digit with value <base */
  1503. flags |= bit(0); /* set bit 0 */
  1504. index++;
  1505. } else if (attr==a_ratio) {
  1506. if (flags & bit(1)) /* not the only '/' ? */
  1507. goto schritt4; /* yes -> not a rational number */
  1508. flags |= bit(1); /* first '/' */
  1509. if (!(flags & bit(0))) /* no digits before the fraction bar? */
  1510. goto schritt4; /* yes -> not a rational number */
  1511. flags &= ~bit(0); /* delete bit 0, new block starts */
  1512. info->index3 = index; /* store index of '/' */
  1513. charptr++; index++;
  1514. } else
  1515. /* Attributecode /= a_*digit, a_ratio -> not a rational number */
  1516. goto schritt4;
  1517. }
  1518. /* Token finished */
  1519. if (!(flags & bit(0))) /* no digits in the last block ? */
  1520. goto schritt4; /* yes -> not a rational number */
  1521. /* rational number */
  1522. if (!(flags & bit(1))) /* a_ratio? */
  1523. /* no -> it's an integer, info is ready. */
  1524. return 1;
  1525. else
  1526. /* yes -> it's a fraction, info is ready. */
  1527. return 2;
  1528. }
  1529. schritt4:
  1530. /* 4. base:=10 */
  1531. *base_ = 10;
  1532. { /* 5. Floating-Point-Number or decimal-integer */
  1533. var uintB* attrptr = attrptr0;
  1534. var uintL index = index0;
  1535. /* flags & bit(2) indicates, if an a_dot has arrived already
  1536. (then info->index3 is the subsequent position)
  1537. flags & bit(3) indicates whether in the last digit block already
  1538. a_digit was found
  1539. flags & bit(4) indicates, if there was an a_dot with digits in front
  1540. of it */
  1541. while (index<len) { /* next character */
  1542. var uintB attr = *attrptr++; /* its attribute code */
  1543. if (attr==a_digit) {
  1544. /* Digit ('0'-'9') */
  1545. flags |= bit(3); index++;
  1546. } else if (attr==a_dot) {
  1547. if (flags & bit(2)) /* not the only '.' ? */
  1548. return 0; /* yes -> not a number */
  1549. flags |= bit(2); /* first '.' */
  1550. if (flags & bit(3))
  1551. flags |= bit(4); /* maybe with digits in front of the dot */
  1552. flags &= ~bit(3); /* reset flag */
  1553. index++;
  1554. info->index3 = index; /* store index after the '.' */
  1555. } else if (attr==a_expo_m || attr==a_expodigit)
  1556. goto expo; /* treat exponent */
  1557. else
  1558. return 0; /* not a float, thus not a number */
  1559. }
  1560. /* token finished, no exponent */
  1561. if (!(flags & bit(2))) /* only decimal digits without '.' ? */
  1562. return 0; /* yes -> not a number */
  1563. info->index4 = index;
  1564. if (flags & bit(3)) /* with digits behind the dot? */
  1565. return 3; /* yes -> Float, info ready. */
  1566. /* no. */
  1567. if (!(flags & bit(4))) /* also without digits in front of dot? */
  1568. return 0; /* yes -> only '.' -> no number */
  1569. /* only digits in front of '.',none behind it -> decimal-integer.
  1570. Don't need to cut '.' away at the end (will be omitted). */
  1571. return 1;
  1572. expo:
  1573. /* reached exponent. */
  1574. info->index4 = index;
  1575. index++; /* count exponent-marker */
  1576. if (!(flags & bit(2)))
  1577. info->index3 = info->index4; /* default for index3 */
  1578. if (!(flags & (bit(3)|bit(4)))) /* were there digits in front of */
  1579. /* or behind the dot? */
  1580. return 0; /* no -> not a number */
  1581. /* continue with exponent:
  1582. flags & bit(5) indicates, if there has already been
  1583. an exponent-digit. */
  1584. if (index>=len)
  1585. return 0; /* string finished -> not a number */
  1586. switch (*attrptr) {
  1587. case a_plus:
  1588. case a_minus:
  1589. attrptr++; index++; /* skip sign of the exponent */
  1590. default:
  1591. break;
  1592. }
  1593. for (; index<len; index++) { /* next character in exponent: */
  1594. /* from now on only digits are allowed: */
  1595. if (!(*attrptr++ == a_digit))
  1596. return 0;
  1597. flags |= bit(5);
  1598. }
  1599. /* Token is finished after exponent */
  1600. if (!(flags & bit(5))) /* no digit in exponent? */
  1601. return 0; /* yes -> not a number */
  1602. return 3; /* Float, info ready. */
  1603. }
  1604. }
  1605. /* Handler: Signals a READER-ERROR with the same error message as the current
  1606. condition. */
  1607. local void signal_reader_error (void* sp, gcv_object_t* frame, object label,
  1608. object condition) {
  1609. var gcv_object_t* stream_ = (gcv_object_t*)sp;
  1610. /* (SYS::ERROR-OF-TYPE 'READER-ERROR :STREAM label "~A" condition) */
  1611. pushSTACK(S(reader_error)); pushSTACK(S(Kstream)); pushSTACK(*stream_);
  1612. pushSTACK(O(tildeA)); pushSTACK(condition);
  1613. funcall(L(error_of_type),5);
  1614. }
  1615. /* UP: checks, if a token consists only of Dots.
  1616. test_dots()
  1617. > O(token_buff_1): read characters
  1618. > O(token_buff_2): their attributcodes
  1619. < result: true, if token is empty or consists only of dots */
  1620. local bool test_dots (void) {
  1621. /* search for attributecode /= a_dot: */
  1622. var object bvec = O(token_buff_2); /* Semi-Simple-Byte-Vector */
  1623. var uintL len = TheIarray(bvec)->dims[1]; /* Fill-Pointer */
  1624. if (len > 0) {
  1625. var uintB* attrptr = &TheSbvector(TheIarray(bvec)->data)->data[0];
  1626. var uintL count;
  1627. dotimespL(count,len, {
  1628. if (!(*attrptr++ == a_dot)) /* Attributcode /= a_dot found? */
  1629. return false; /* yes -> ready, false */
  1630. });
  1631. }
  1632. /* only dots. */
  1633. return true;
  1634. }
  1635. /* UP: converts a number-token into capitals.
  1636. upcase_token();
  1637. > O(token_buff_1): read characters
  1638. > O(token_buff_2): their attributecodes */
  1639. local void upcase_token (void) {
  1640. var object string = O(token_buff_1); /* Semi-Simple-String */
  1641. var uintL len = TheIarray(string)->dims[1]; /* Fill-Pointer */
  1642. if (len > 0) {
  1643. var chart* charptr = &TheSnstring(TheIarray(string)->data)->data[0];
  1644. dotimespL(len,len, { *charptr = up_case(*charptr); charptr++; } );
  1645. }
  1646. }
  1647. /* UP: converts a piece of the read Tokens into upper or lower case letters.
  1648. case_convert_token(start_index,end_index,direction);
  1649. > O(token_buff_1): read characters
  1650. > O(token_buff_2): their attributecodes
  1651. > uintL start_index: startindex of range to be converted
  1652. > uintL end_index: endindex of the range to be converted
  1653. > uintW direction: direction of the conversion */
  1654. local void case_convert_token (uintL start_index, uintL end_index,
  1655. uintW direction) {
  1656. var chart* charptr =
  1657. &TheSnstring(TheIarray(O(token_buff_1))->data)->data[start_index];
  1658. var uintB* attrptr =
  1659. &TheSbvector(TheIarray(O(token_buff_2))->data)->data[start_index];
  1660. var uintL len = end_index - start_index;
  1661. if (len == 0)
  1662. return;
  1663. switch (direction) {
  1664. case case_upcase: /* convert un-escaped characters to upper case: */
  1665. do_upcase:
  1666. dotimespL(len,len, {
  1667. if (!(*attrptr == a_escaped))
  1668. *charptr = up_case(*charptr);
  1669. charptr++; attrptr++;
  1670. });
  1671. break;
  1672. case case_downcase: /* convert un-escaped characters to lower case: */
  1673. do_downcase:
  1674. dotimespL(len,len, {
  1675. if (!(*attrptr == a_escaped))
  1676. *charptr = down_case(*charptr);
  1677. charptr++; attrptr++;
  1678. });
  1679. break;
  1680. case case_preserve: /* do nothing. */
  1681. break;
  1682. case case_invert: {
  1683. /* if there is no un-escaped lower-case-letter,
  1684. convert all un-escaped characters to lower case.
  1685. if there is no un-escaped upper-case-letter,
  1686. convert all un-escaped characters to upper case.
  1687. otherwise do nothing. */
  1688. var bool seen_uppercase = false;
  1689. var bool seen_lowercase = false;
  1690. var const chart* cptr = charptr;
  1691. var const uintB* aptr = attrptr;
  1692. var uintL count;
  1693. dotimespL(count,len, {
  1694. if (!(*aptr == a_escaped)) {
  1695. var chart c = *cptr;
  1696. if (!chareq(c,up_case(c)))
  1697. seen_lowercase = true;
  1698. if (!chareq(c,down_case(c)))
  1699. seen_uppercase = true;
  1700. }
  1701. cptr++; aptr++;
  1702. });
  1703. if (seen_uppercase) {
  1704. if (!seen_lowercase)
  1705. goto do_downcase;
  1706. } else {
  1707. if (seen_lowercase)
  1708. goto do_upcase;
  1709. }
  1710. } break;
  1711. default: NOTREACHED;
  1712. }
  1713. }
  1714. /* UP: converts the whole read token to upper or lower case.
  1715. case_convert_token_1(); */
  1716. local void case_convert_token_1 (void) {
  1717. var object readtable;
  1718. get_readtable(readtable = );
  1719. var uintW direction = RTCase(readtable);
  1720. var uintL len = TheIarray(O(token_buff_1))->dims[1]; /* Length = Fill-Pointer */
  1721. case_convert_token(0,len,direction);
  1722. }
  1723. /* UP: treatment of read-macro-character:
  1724. calls the appropriate macro-function; for dispatch-characters read
  1725. number-argument and subchar first.
  1726. read_macro(ch,&stream)
  1727. > ch: macro-character, a character
  1728. > stream: Stream
  1729. < stream: Stream
  1730. < mv_count/mv_space: one value at most
  1731. can trigger GC */
  1732. local maygc Values read_macro (object ch, const gcv_object_t* stream_) {
  1733. var object readtable;
  1734. get_readtable(readtable = ); /* current readtable (don't need to save ch) */
  1735. var object macrodef = /* fetch macro-definition from table */
  1736. perchar_table_get(TheReadtable(readtable)->readtable_macro_table,
  1737. char_code(ch));
  1738. if (nullp(macrodef)) { /* =NIL ? */
  1739. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  1740. pushSTACK(ch);
  1741. pushSTACK(*stream_);
  1742. pushSTACK(S(read));
  1743. error(reader_error,
  1744. GETTEXT("~S from ~S: ~S has no macro character definition"));
  1745. }
  1746. if (!simple_vector_p(macrodef)) { /* a simple-vector? */
  1747. /* ch normal macro-character, macrodef function */
  1748. pushSTACK(*stream_); /* stream as 1st argument */
  1749. pushSTACK(ch); /* character as 2nd argument */
  1750. funcall(macrodef,2); /* call function */
  1751. if (mv_count > 1) {
  1752. pushSTACK(fixnum(mv_count)); /* value number as Fixnum */
  1753. pushSTACK(ch);
  1754. pushSTACK(*stream_);
  1755. pushSTACK(S(read));
  1756. error(error_condition,GETTEXT("~S from ~S: macro character definition for ~S may not return ~S values, only one value."));
  1757. }
  1758. /* at most one value. */
  1759. return; /* retain mv_space/mv_count */
  1760. } else {
  1761. /* Dispatch-Macro-Character.
  1762. When this changes, keep DISPATCH-READER in defs2.lisp up to date. */
  1763. pushSTACK(macrodef); /* save vector */
  1764. var object arg; /* argument (Integer >=0 or NIL) */
  1765. var object subch; /* sub-char */
  1766. var chart subc; /* sub-char */
  1767. { /* read digits of argument: */
  1768. var bool flag = false; /* flag, if there has been a digit already */
  1769. pushSTACK(Fixnum_0); /* previous Integer := 0 */
  1770. while (1) {
  1771. var object nextch = read_char(stream_); /* read character */
  1772. if (eq(nextch,eof_value)) {
  1773. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  1774. pushSTACK(ch); /* main char */
  1775. pushSTACK(*stream_); /* Stream */
  1776. pushSTACK(S(read));
  1777. error(end_of_file,GETTEXT("~S: input stream ~S ends within read macro beginning to ~S"));
  1778. }
  1779. /* otherwise check for character. */
  1780. if (!charp(nextch))
  1781. error_charread(nextch,stream_);
  1782. var chart ch = char_code(nextch);
  1783. var cint c = as_cint(ch);
  1784. if (!((c>='0') && (c<='9'))) { /* no digit -> loop finished */
  1785. subc = ch;
  1786. break;
  1787. }
  1788. /* multiply Integer by 10 and add digit: */
  1789. STACK_0 = mult_10_plus_x(STACK_0,(uintB)(c-'0'));
  1790. flag = true;
  1791. }
  1792. /* argument in STACK_0 finished (only if flag=true). */
  1793. arg = popSTACK();
  1794. if (!flag)
  1795. arg = NIL; /* there was no digit -> Argument := NIL */
  1796. }
  1797. /* let's continue with Subchar (Character subc) */
  1798. subch = code_char(subc);
  1799. subc = up_case(subc); /* convert Subchar to upper case */
  1800. macrodef = popSTACK(); /* get back Vector */
  1801. macrodef = perchar_table_get(macrodef,subc); /* Subchar-Function or NIL */
  1802. if (nullp(macrodef)) { /* NIL -> undefined */
  1803. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  1804. pushSTACK(subch); /* Subchar */
  1805. pushSTACK(ch); /* Mainchar */
  1806. pushSTACK(*stream_); /* Stream */
  1807. pushSTACK(S(read));
  1808. error(reader_error, /* ANSI CL spec of MAKE-DISPATCH-MACRO-CHARACTER wants a reader-error here */
  1809. GETTEXT("~S from ~S: After ~S is ~S an undefined dispatch macro character"));
  1810. }
  1811. pushSTACK(*stream_); /* Stream as 1. argument */
  1812. pushSTACK(subch); /* Subchar as 2. Argument */
  1813. pushSTACK(arg); /* Argument (NIL or Integer>=0) as 3. Argument */
  1814. funcall(macrodef,3); /* call function */
  1815. if (mv_count > 1) {
  1816. pushSTACK(fixnum(mv_count)); /* value number as Fixnum */
  1817. pushSTACK(ch); /* Mainchar */
  1818. pushSTACK(subch); /* Subchar */
  1819. pushSTACK(*stream_); /* Stream */
  1820. pushSTACK(S(read));
  1821. error(error_condition,GETTEXT("~S from ~S: dispatch macro character definition for ~S after ~S may not return ~S values, only one value."));
  1822. }
  1823. /* at most 1 value. */
  1824. return; /* retain mv_space/mv_count */
  1825. }
  1826. }
  1827. /* --------------------- READ at object-level --------------------------- */
  1828. /* UP: reads an object.
  1829. skip leading whitespace and comment.
  1830. the curren values of SYS::*READ-PRESERVE-WHITESPACE* are definitive
  1831. (for potentially skipping the first Whitespace behind the object)
  1832. also devinitive is SYS::*READ-RECURSIVE-P* (for EOF-treatment).
  1833. read_internal(&stream)
  1834. > stream: Stream
  1835. < stream: Stream
  1836. < result: read object (eof_value at EOF, dot_value for single dot)
  1837. can trigger GC */
  1838. local maygc object read_internal (const gcv_object_t* stream_) {
  1839. wloop: { /* loop for skipping of leading whitespace/comment: */
  1840. var object ch;
  1841. var uintWL scode;
  1842. read_char_syntax(ch = ,scode = ,stream_); /* read character */
  1843. switch(scode) {
  1844. case syntax_whitespace: /* Whitespace -> throw away and continue reading */
  1845. goto wloop;
  1846. case syntax_t_macro:
  1847. case syntax_nt_macro: /* Macro-Character at start of Token */
  1848. read_macro(ch,stream_); /* call Macro-Function */
  1849. if (mv_count==0) /* 0 values -> continue reading */
  1850. goto wloop;
  1851. else /* 1 value -> as result */
  1852. return value1;
  1853. case syntax_eof: { /* EOF at start of Token */
  1854. if (!nullpSv(read_recursive_p)) /* *READ-RECURSIVE-P* /= NIL ? */
  1855. /* yes -> EOF within an object -> error */
  1856. error_eof_inside(stream_);
  1857. /* otherwise eof_value as value: */
  1858. clear_input(*stream_); /* clear the EOF char from the stream */
  1859. return eof_value;
  1860. }
  1861. case syntax_illegal: /* read_token_1 returns Error */
  1862. case syntax_single_esc:
  1863. case syntax_multi_esc:
  1864. case syntax_constituent: /* read Token: A Token starts with character ch. */
  1865. read_token_1(stream_,ch,scode); /* finish reading of Token */
  1866. break;
  1867. default: NOTREACHED;
  1868. }
  1869. }
  1870. /* reading of Token finished */
  1871. if (!nullpSv(read_suppress)) /* *READ-SUPPRESS* /= NIL ? */
  1872. return NIL; /* yes -> don't interprete Token, NIL as value */
  1873. /* Token must be interpreted
  1874. the Token is in O(token_buff_1), O(token_buff_2), token_escape_flag. */
  1875. if ((!token_escape_flag) && test_dots()) {
  1876. /* Token is a sequence of Dots, read without escape-characters
  1877. thus Length is automatically >0. */
  1878. var uintL len = TheIarray(O(token_buff_1))->dims[1]; /* length of Token */
  1879. if (len > 1) { /* Length>1 -> error */
  1880. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  1881. pushSTACK(*stream_);
  1882. pushSTACK(S(read));
  1883. error(reader_error, /* ANSI CL 2.4.9. wants a reader-error here */
  1884. GETTEXT("~S from ~S: a token consisting only of dots cannot be meaningfully read in"));
  1885. }
  1886. /* Length=1 -> dot_value as value */
  1887. return dot_value;
  1888. }
  1889. { /* Token is OK */
  1890. var uintWL base = get_read_base(); /* value of *READ-BASE* */
  1891. /* Token can be interpreted as number? */
  1892. var object string;
  1893. var zahl_info_t info;
  1894. var uintWL numtype = test_number_syntax(&base,&string,&info);
  1895. if (!(numtype==0)) { /* number? */
  1896. upcase_token(); /* convert to upper case */
  1897. var object result;
  1898. /* ANSI CL 2.3.1.1 requires that we transform ARITHMETIC-ERROR
  1899. into READER-ERROR */
  1900. make_HANDLER_frame(O(handler_for_arithmetic_error),
  1901. &signal_reader_error,stream_);
  1902. switch (numtype) {
  1903. case 1: /* Integer */
  1904. result = read_integer(base,info.sign,string,info.index1,info.index2);
  1905. break;
  1906. case 2: /* Rational */
  1907. result = read_rational(base,info.sign,string,info.index1,
  1908. info.index3,info.index2);
  1909. break;
  1910. case 3: /* Float */
  1911. result = read_float(base,info.sign,string,info.index1,
  1912. info.index4,info.index2,info.index3);
  1913. break;
  1914. default: NOTREACHED;
  1915. }
  1916. unwind_HANDLER_frame();
  1917. return result;
  1918. }
  1919. }
  1920. { /* Token cannot be interpreted as number.
  1921. we interprete the Token as Symbol (even, if the Token matches
  1922. Potential-number-Syntax, thus being a 'reserved token' (in the spirit
  1923. of CLTL S. 341 top) ).
  1924. first determine the distribution of colons (Characters with
  1925. Attributecode a_pack_m):
  1926. Beginning at the front, search the first colon. Cases (CLTL S. 343-344):
  1927. 1. no colon -> current Package
  1928. 2. one or two colons at the beginning -> Keyword
  1929. 3. one colon, not at the beginning -> external Symbol
  1930. 4. two colons, not at the beginning -> internal Symbol
  1931. In the last three cases no more colons may occur.
  1932. (It cannot be checked here , that at step 2. the name-part
  1933. respectively at 3. and 4. the package-part and the name-part
  1934. do not have the syntax of a number,
  1935. because TOKEN_ESCAPE_FLAG is valid for the whole Token.
  1936. Compare |USER|:: and |USER|::|| ) */
  1937. var uintW direction; /* direction of the case-conversion */
  1938. {
  1939. var object readtable;
  1940. get_readtable(readtable = );
  1941. direction = RTCase(readtable);
  1942. }
  1943. var object buff_2 = O(token_buff_2); /* Attributecode-Buffer */
  1944. var uintL len = TheIarray(buff_2)->dims[1]; /* length = Fill-Pointer */
  1945. var uintB* attrptr = &TheSbvector(TheIarray(buff_2)->data)->data[0];
  1946. var uintL index = 0;
  1947. /* always attrptr = &TheSbvector(...)->data[index].
  1948. Token is split in Packagename and Name: */
  1949. var uintL pack_end_index;
  1950. var uintL name_start_index;
  1951. var bool external_internal_flag = false; /* preliminary external */
  1952. while (1) {
  1953. if (index>=len)
  1954. goto current; /* found no colon -> current package */
  1955. if (*attrptr == a_illg)
  1956. goto found_illg;
  1957. if (*attrptr++ == a_pack_m)
  1958. break;
  1959. index++;
  1960. }
  1961. /* found first colon at Index index */
  1962. pack_end_index = index; /* Packagename ends here */
  1963. index++;
  1964. name_start_index = index; /* Symbolname starts (preliminary) here */
  1965. /* reached Tokenend -> external Symbol: */
  1966. if (index>=len)
  1967. goto ex_in_ternal;
  1968. /* is a further colon following, immediately? */
  1969. index++;
  1970. if (*attrptr == a_illg)
  1971. goto found_illg;
  1972. if (*attrptr++ == a_pack_m) { /* two colons side by side */
  1973. name_start_index = index; /* Symbolname is starting but now */
  1974. external_internal_flag = true; /* internal */
  1975. } else {
  1976. /* first colon was isolated
  1977. external */
  1978. }
  1979. /* no more colons are to come: */
  1980. while (1) {
  1981. if (index>=len)
  1982. goto ex_in_ternal; /* no further colon found -> ok */
  1983. if (*attrptr == a_illg)
  1984. goto found_illg;
  1985. if (*attrptr++ == a_pack_m)
  1986. break;
  1987. index++;
  1988. }
  1989. { /* error message */
  1990. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  1991. pushSTACK(copy_string(O(token_buff_1))); /* copy Character-Buffer */
  1992. pushSTACK(*stream_); /* Stream */
  1993. pushSTACK(S(read));
  1994. error(reader_error,GETTEXT("~S from ~S: too many colons in token ~S"));
  1995. }
  1996. found_illg: { /* error message */
  1997. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  1998. pushSTACK(copy_string(O(token_buff_1))); /* copy Character-Buffer */
  1999. pushSTACK(*stream_); /* Stream */
  2000. pushSTACK(S(read));
  2001. error(reader_error,GETTEXT("~S from ~S: token ~S contains an invalid constituent character (see ANSI CL 2.1.4.2.)"));
  2002. }
  2003. /* search Symbol or create it: */
  2004. current: { /* search Symbol in the current package. */
  2005. /* Symbolname = O(token_buff_1) = (subseq O(token_buff_1) 0 len)
  2006. is a non-simple String. */
  2007. var object pack = get_current_package();
  2008. if (!pack_casesensitivep(pack))
  2009. case_convert_token(0,len,direction);
  2010. /* intern Symbol (and copy String, if the Symbol must be created freshly): */
  2011. var object sym;
  2012. intern(O(token_buff_1),pack_caseinvertedp(pack),pack,&sym);
  2013. return sym;
  2014. }
  2015. ex_in_ternal: /* build external/internal Symbol */
  2016. /* Packagename = (subseq O(token_buff_1) 0 pack_end_index),
  2017. Symbolname = (subseq O(token_buff_1) name_start_index len). */
  2018. case_convert_token(0,pack_end_index,direction);
  2019. if (pack_end_index==0) {
  2020. /* colon(s) at the beginning -> build Keyword:
  2021. Symbolname = (subseq O(token_buff_1) name_start_index len). */
  2022. case_convert_token(name_start_index,len,direction);
  2023. /* adjust auxiliary-String: */
  2024. var object hstring = O(displaced_string);
  2025. TheIarray(hstring)->data = O(token_buff_1); /* Data-vector */
  2026. TheIarray(hstring)->dims[0] = name_start_index; /* Displaced-Offset */
  2027. TheIarray(hstring)->totalsize =
  2028. TheIarray(hstring)->dims[1] = len - name_start_index; /* length */
  2029. /* intern Symbol in the Keyword-Package (and copy String,
  2030. if the Symbol must be created newly): */
  2031. return intern_keyword(hstring);
  2032. }
  2033. { /* Packagename = (subseq O(token_buff_1) 0 pack_end_index). */
  2034. /* adjust Auxiliary-String: */
  2035. var object hstring = O(displaced_string);
  2036. TheIarray(hstring)->data = O(token_buff_1); /* Data-vector */
  2037. TheIarray(hstring)->dims[0] = 0; /* Displaced-Offset */
  2038. TheIarray(hstring)->totalsize =
  2039. TheIarray(hstring)->dims[1] = pack_end_index; /* length */
  2040. /* search Package with this name: */
  2041. var object pack = find_package(hstring);
  2042. if (nullp(pack)) { /* Package not found? */
  2043. pushSTACK(copy_string(hstring)); /* copy Displaced-String, PACKAGE-ERROR slot PACKAGE */
  2044. pushSTACK(STACK_0);
  2045. pushSTACK(*stream_); /* Stream */
  2046. pushSTACK(S(read));
  2047. error(package_error,
  2048. GETTEXT("~S from ~S: there is no package with name ~S"));
  2049. }
  2050. if (!pack_casesensitivep(pack))
  2051. case_convert_token(name_start_index,len,direction);
  2052. /* adjust Auxiliary-String: */
  2053. TheIarray(hstring)->dims[0] = name_start_index; /* Displaced-Offset */
  2054. TheIarray(hstring)->totalsize =
  2055. TheIarray(hstring)->dims[1] = len - name_start_index; /* Length */
  2056. if (external_internal_flag) { /* internal */
  2057. /* intern Symbol (and copy String,
  2058. if Symbol must be created newly): */
  2059. var object sym;
  2060. intern(hstring,pack_caseinvertedp(pack),pack,&sym);
  2061. return sym;
  2062. } else { /* external */
  2063. /* search external Symbol with this Printnamen: */
  2064. var object sym;
  2065. if (find_external_symbol(hstring,pack_caseinvertedp(pack),pack,&sym)) {
  2066. return sym; /* found sym */
  2067. } else {
  2068. pushSTACK(pack); /* PACKAGE-ERROR slot PACKAGE */
  2069. pushSTACK(copy_string(hstring)); /* copy Displaced-String */
  2070. pushSTACK(STACK_1); /* pack */
  2071. pushSTACK(*stream_); /* Stream */
  2072. pushSTACK(S(read));
  2073. error(package_error,
  2074. GETTEXT("~S from ~S: ~S has no external symbol with name ~S"));
  2075. }
  2076. }
  2077. }
  2078. }
  2079. }
  2080. /* UP: reads an Object, with SYS::*READ-RECURSIVE-P* /= NIL
  2081. (and SYS::*READ-PRESERVE-WHITESPACE* = NIL, cmp. CLTL p. 377 middle).
  2082. reports error at EOF.
  2083. read_recursive(&stream)
  2084. > stream: Stream
  2085. < stream: Stream
  2086. < result: read Object (dot_value at single dot)
  2087. can trigger GC */
  2088. local maygc object read_recursive (const gcv_object_t* stream_) {
  2089. check_SP(); check_STACK(); /* check Stacks for Overflow */
  2090. if (!nullpSv(read_recursive_p)) { /* recursive */
  2091. return read_internal(stream_);
  2092. } else { /* bind SYS::*READ-RECURSIVE-P* to T: */
  2093. dynamic_bind(S(read_recursive_p),T);
  2094. /* and bind SYS::*READ-PRESERVE-WHITESPACE* to NIL: */
  2095. dynamic_bind(S(read_preserve_whitespace),NIL);
  2096. /* and read Object: */
  2097. var object result = read_internal(stream_);
  2098. dynamic_unbind(S(read_preserve_whitespace));
  2099. dynamic_unbind(S(read_recursive_p));
  2100. return result;
  2101. }
  2102. }
  2103. /* error-message because of out-of-place Dot
  2104. error_dot(stream);
  2105. > stream: Stream */
  2106. nonreturning_function(local, error_dot, (object stream)) {
  2107. pushSTACK(stream); /* STREAM-ERROR slot STREAM */
  2108. pushSTACK(stream); /* Stream */
  2109. pushSTACK(S(read));
  2110. error(reader_error, /* ANSI CL 2.3.3. wants a reader-error here. */
  2111. GETTEXT("~S from ~S: token \".\" not allowed here"));
  2112. }
  2113. /* UP: reads an Object, with SYS::*READ-RECURSIVE-P* /= NIL
  2114. (and SYS::*READ-PRESERVE-WHITESPACE* = NIL, cmp. CLTL p. 377 middle).
  2115. reports Error at EOF or Token ".".
  2116. (this complies with the Idiom (read stream t nil t).)
  2117. read_recursive_no_dot(&stream)
  2118. > stream: Stream
  2119. < stream: Stream
  2120. < result: read Object
  2121. can trigger GC */
  2122. local maygc object read_recursive_no_dot (const gcv_object_t* stream_) {
  2123. /* call READ recursively: */
  2124. var object result = read_recursive(stream_);
  2125. /* and report Error at ".": */
  2126. if (eq(result,dot_value))
  2127. error_dot(*stream_);
  2128. return result;
  2129. }
  2130. /* error-message due to an invalid value of an internal variable */
  2131. nonreturning_function(local, error_invalid_value, (object symbol)) {
  2132. pushSTACK(Symbol_value(symbol)); pushSTACK(symbol);
  2133. pushSTACK(TheSubr(subr_self)->name);
  2134. error(error_condition,
  2135. GETTEXT("~S: the value of ~S has been arbitrarily altered to ~S"));
  2136. }
  2137. local object check_read_reference_table (void) {
  2138. var object val = Symbol_value(S(read_reference_table));
  2139. if (boundp(val)) return val;
  2140. pushSTACK(S(read)); pushSTACK(S(read_reference_table));
  2141. pushSTACK(TheSubr(subr_self)->name);
  2142. error(error_condition,GETTEXT("~S: symbol ~S is not bound, it appears that top-level ~S was called with a non-NIL recursive-p argument"));
  2143. }
  2144. /* UP: disentangles #n#-references to #n=-markings in an Object.
  2145. > value of SYS::*READ-REFERENCE-TABLE*:
  2146. Alist of Pairs (marking . marked Object), where
  2147. each marking is an object #<READ-LABEL n>.
  2148. > obj: Object
  2149. < result: destructively modified Object without References */
  2150. local object make_references (object obj) {
  2151. var object alist = check_read_reference_table();
  2152. /* SYS::*READ-REFERENCE-TABLE* = NIL -> nothing to do: */
  2153. if (nullp(alist)) {
  2154. return obj;
  2155. } else {
  2156. { /* Check if SYS::*READ-REFERENCE-TABLE* is an alist: */
  2157. var object alistr = alist; /* run through list */
  2158. while (consp(alistr)) { /* each List-Element must be a Cons: */
  2159. if (!mconsp(Car(alistr)))
  2160. error_invalid_value(S(read_reference_table));
  2161. alistr = Cdr(alistr);
  2162. }
  2163. if (!nullp(alistr))
  2164. error_invalid_value(S(read_reference_table));
  2165. }
  2166. /* Alist alist is OK */
  2167. pushSTACK(obj);
  2168. var object bad_reference =
  2169. subst_circ(&STACK_0,alist); /* substitute References by Objects */
  2170. if (!eq(bad_reference,nullobj)) {
  2171. pushSTACK(unbound); /* STREAM-ERROR slot STREAM */
  2172. pushSTACK(Symbol_value(S(read_reference_table)));
  2173. pushSTACK(S(read_reference_table));
  2174. pushSTACK(obj);
  2175. pushSTACK(bad_reference);
  2176. pushSTACK(S(read));
  2177. error(reader_error,GETTEXT("~S: no entry for ~S from ~S in ~S = ~S"));
  2178. }
  2179. return popSTACK();
  2180. }
  2181. }
  2182. /* UP: Reads an Object, with SYS::*READ-RECURSIVE-P* = NIL .
  2183. (Top-Level-Call of Reader)
  2184. read_top(&stream,whitespace-p)
  2185. > whitespace-p: indicates, if whitespace has to be consumend afterwards
  2186. > stream: Stream
  2187. < stream: Stream
  2188. < result: read Object (eof_value at EOF, dot_value at single dot)
  2189. can trigger GC */
  2190. local maygc object read_top (const gcv_object_t* stream_, object whitespace_p) {
  2191. #if STACKCHECKR
  2192. var gcv_object_t* STACKbefore = STACK; /* retain STACK for later */
  2193. #endif
  2194. /* bind SYS::*READ-RECURSIVE-P* to NIL: */
  2195. dynamic_bind(S(read_recursive_p),NIL);
  2196. /* and bind SYS::*READ-PRESERVE-WHITESPACE* to whitespace_p: */
  2197. dynamic_bind(S(read_preserve_whitespace),whitespace_p);
  2198. /* bind SYS::*READ-REFERENCE-TABLE* to the empty Table NIL: */
  2199. dynamic_bind(S(read_reference_table),NIL);
  2200. /* bind SYS::*BACKQUOTE-LEVEL* to NIL: */
  2201. dynamic_bind(S(backquote_level),NIL);
  2202. /* bind SYS::*READING-ARRAY* to NIL: */
  2203. dynamic_bind(S(reading_array),NIL);
  2204. /* bind SYS::*READING-STRUCT* to NIL: */
  2205. dynamic_bind(S(reading_struct),NIL);
  2206. /* read Object: */
  2207. var object obj = read_internal(stream_);
  2208. /* disentangle references: */
  2209. obj = make_references(obj);
  2210. dynamic_unbind(S(reading_struct));
  2211. dynamic_unbind(S(reading_array));
  2212. dynamic_unbind(S(backquote_level));
  2213. dynamic_unbind(S(read_reference_table));
  2214. dynamic_unbind(S(read_preserve_whitespace));
  2215. dynamic_unbind(S(read_recursive_p));
  2216. #if STACKCHECKR
  2217. /* verify, if Stack is cleaned up: */
  2218. if (!(STACK == STACKbefore))
  2219. abort(); /* if not --> go to Debugger */
  2220. #endif
  2221. return obj;
  2222. }
  2223. /* UP: reads an Object.
  2224. stream_read(&stream,recursive-p,whitespace-p)
  2225. > recursive-p: indicates, if recursive call of READ, with Error at EOF
  2226. > whitespace-p: indicates, if whitespace has to be consumed afterwards
  2227. > stream: Stream
  2228. < stream: Stream
  2229. < result: read Object (eof_value at EOF, dot_value at single dot)
  2230. can trigger GC */
  2231. global maygc object stream_read (const gcv_object_t* stream_,
  2232. object recursive_p, object whitespace_p) {
  2233. if (nullp(recursive_p)) /* inquire recursive-p */
  2234. /* no -> Top-Level-Call */
  2235. return read_top(stream_,whitespace_p);
  2236. else
  2237. /* yes -> recursive Call */
  2238. return read_recursive(stream_);
  2239. }
  2240. /* ------------------------- READ-Macros -------------------------------- */
  2241. /* UP: Read List.
  2242. read_delimited_list(&stream,endch,ifdotted)
  2243. > endch: expected character at the End, a Character
  2244. > ifdotted: #DOT_VALUE if Dotted List is allowed, #EOF_VALUE otherwise
  2245. > stream: Stream
  2246. < stream: Stream
  2247. < result: read Object
  2248. can trigger GC */
  2249. local maygc object read_delimited_list (const gcv_object_t* stream_,
  2250. object endch, object ifdotted);
  2251. /* Dito with set SYS::*READ-RECURSIVE-P* : */
  2252. local maygc object read_delimited_list_recursive
  2253. (const gcv_object_t* stream_, object endch, object ifdotted);
  2254. /* first the general function: */
  2255. local maygc object read_delimited_list(const gcv_object_t* stream_, object endch,
  2256. object ifdotted) {
  2257. #if STACKCHECKR
  2258. var gcv_object_t* STACKbefore = STACK; /* retain STACK for later */
  2259. #endif
  2260. /* bind SYS::*READ-LINE-NUMBER* to (SYS::LINE-NUMBER stream)
  2261. (for error-message, in order to know about the line with the opening parenthese): */
  2262. var bool terminal_read_open_object_bind = terminal_stream_p(*stream_);
  2263. var object lineno = stream_line_number(*stream_);
  2264. dynamic_bind(S(read_line_number),lineno);
  2265. if (terminal_read_open_object_bind)
  2266. dynamic_bind(S(terminal_read_open_object),S(list));
  2267. var object result;
  2268. /* possibly bind SYS::*READ-RECURSIVE-P* to T, first: */
  2269. if (!nullpSv(read_recursive_p)) { /* recursive? */
  2270. result = read_delimited_list_recursive(stream_,endch,ifdotted);
  2271. } else { /* no -> bind SYS::*READ-RECURSIVE-P* to T: */
  2272. dynamic_bind(S(read_recursive_p),T);
  2273. result = read_delimited_list_recursive(stream_,endch,ifdotted);
  2274. dynamic_unbind(S(read_recursive_p));
  2275. }
  2276. /* ANSI CL spec of *READ-SUPPRESS* says that if *READ-SUPPRESS* is true,
  2277. READ-DELIMITED-LIST must return NIL. */
  2278. if (!nullpSv(read_suppress)) /* *READ-SUPPRESS* /= NIL ? */
  2279. result = NIL;
  2280. if (terminal_read_open_object_bind)
  2281. dynamic_unbind(S(terminal_read_open_object));
  2282. dynamic_unbind(S(read_line_number));
  2283. #if STACKCHECKR
  2284. if (STACK != STACKbefore) /* verify if Stack is cleaned up */
  2285. abort(); /* if not --> go to Debugger */
  2286. #endif
  2287. return result;
  2288. }
  2289. /* then the more special Function: */
  2290. local maygc object read_delimited_list_recursive (const gcv_object_t* stream_,
  2291. object endch, object ifdotted)
  2292. {
  2293. /* don't need to save endch and ifdotted. */
  2294. {
  2295. var object object1; /* first List element */
  2296. while (1) { /* loop, in order to read first Listenelement */
  2297. /* next non-whitespace Character: */
  2298. var object ch;
  2299. var uintWL scode;
  2300. wpeek_char_syntax(ch = ,scode = ,stream_);
  2301. if (eq(ch,endch)) { /* is it the expected ending character? */
  2302. /* yes -> empty List as result */
  2303. read_char(stream_); /* consume ending character */
  2304. return NIL;
  2305. }
  2306. if (scode < syntax_t_macro) { /* Macro-Character? */
  2307. /* no -> read 1. Object: */
  2308. object1 = read_recursive_no_dot(stream_);
  2309. break;
  2310. } else { /* yes -> read belonging character and execute Macro-Function: */
  2311. ch = read_char(stream_);
  2312. read_macro(ch,stream_);
  2313. if (!(mv_count==0)) { /* value back? */
  2314. object1 = value1; /* yes -> take as 1. Object */
  2315. break;
  2316. }
  2317. /* no -> skip */
  2318. }
  2319. }
  2320. /* object1 is the 1. Object */
  2321. pushSTACK(object1);
  2322. }
  2323. {
  2324. var object new_cons = allocate_cons(); /* tinker start of the List */
  2325. Car(new_cons) = popSTACK(); /* new_cons = (cons object1 nil) */
  2326. pushSTACK(new_cons);
  2327. pushSTACK(new_cons);
  2328. }
  2329. /* stack layout: entire_list, (last entire_list). */
  2330. while (1) { /* loop over further List elements */
  2331. var object object1; /* further List element */
  2332. while (1) { /* loop in order to read another List element */
  2333. /* next non-whitespace Character: */
  2334. var object ch;
  2335. var uintWL scode;
  2336. wpeek_char_syntax(ch = ,scode = ,stream_);
  2337. if (eq(ch,endch)) { /* Is it the expected Ending character? */
  2338. /* yes -> finish list */
  2339. finish_list:
  2340. read_char(stream_); /* consume Ending character */
  2341. skipSTACK(1); return popSTACK(); /* entire list as result */
  2342. }
  2343. if (scode < syntax_t_macro) { /* Macro-Character? */
  2344. /* no -> read next Object: */
  2345. object1 = read_recursive(stream_);
  2346. if (eq(object1,dot_value))
  2347. goto dot;
  2348. break;
  2349. } else { /* yes -> read belonging character and execute Macro-Function: */
  2350. ch = read_char(stream_);
  2351. read_macro(ch,stream_);
  2352. if (!(mv_count==0)) { /* value back? */
  2353. object1 = value1; /* yes -> take as next Object */
  2354. break;
  2355. }
  2356. /* no -> skip */
  2357. }
  2358. }
  2359. /* insert next Object into List: */
  2360. pushSTACK(object1);
  2361. {
  2362. var object new_cons = allocate_cons(); /* next List-Cons */
  2363. Car(new_cons) = popSTACK(); /* (cons object1 nil) */
  2364. Cdr(STACK_0) = new_cons; /* =: (cdr (last whole-list)) */
  2365. STACK_0 = new_cons;
  2366. }
  2367. }
  2368. dot: /* Dot has been read */
  2369. if (!eq(ifdotted,dot_value)) /* none was allowed? */
  2370. error_dot(*stream_);
  2371. {
  2372. var object object1; /* last List-element */
  2373. while (1) { /* loop, in order to read last List-element */
  2374. /* next non-whitespace Character: */
  2375. var object ch;
  2376. var uintWL scode;
  2377. wpeek_char_syntax(ch = ,scode = ,stream_);
  2378. if (eq(ch,endch)) { /* is it the expected ending-character? */
  2379. /* yes -> error */
  2380. error_dot:
  2381. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  2382. pushSTACK(*stream_); /* Stream */
  2383. pushSTACK(S(read_delimited_list));
  2384. error(reader_error,GETTEXT("~S from ~S: illegal end of dotted list"));
  2385. }
  2386. if (scode < syntax_t_macro) { /* Macro-Character? */
  2387. /* no -> read last Object: */
  2388. object1 = read_recursive_no_dot(stream_);
  2389. break;
  2390. } else { /* yes -> read belonging character and execute Macro-Function: */
  2391. ch = read_char(stream_);
  2392. read_macro(ch,stream_);
  2393. if (!(mv_count==0)) { /* value back? */
  2394. object1 = value1; /* yes -> take as last Object */
  2395. break;
  2396. }
  2397. /* no -> skip */
  2398. }
  2399. }
  2400. /* object1 is the last Object
  2401. insert into list as (cdr (last Gesamtliste)): */
  2402. Cdr(STACK_0) = object1;
  2403. }
  2404. while (1) { /* loop, in order to read comment after the last List-element */
  2405. /* next non-whitespace Character: */
  2406. var object ch;
  2407. var uintWL scode;
  2408. wpeek_char_syntax(ch = ,scode = ,stream_);
  2409. if (eq(ch,endch)) /* Is it the expected Ending-character? */
  2410. goto finish_list; /* yes -> List finished */
  2411. if (scode < syntax_t_macro) /* Macro-Character? */
  2412. /* no -> Dot was there too early, error */
  2413. goto error_dot;
  2414. else { /* yes -> read belonging character and execute Macro-Function: */
  2415. ch = read_char(stream_);
  2416. read_macro(ch,stream_);
  2417. if (!(mv_count==0)) /* value back? */
  2418. goto error_dot; /* yes -> Dot came to early, error */
  2419. /* no -> skip */
  2420. }
  2421. }
  2422. }
  2423. /* stream_ = check_stream_arg(stream_);
  2424. > stream_: Stream-Argument in STACK
  2425. < stream_: &stream
  2426. can trigger GC */
  2427. static inline maygc gcv_object_t* check_stream_arg (gcv_object_t *stream_) {
  2428. *stream_ = check_stream(*stream_); return stream_;
  2429. }
  2430. /* (set-macro-character #\(
  2431. #'(lambda (stream char)
  2432. (read-delimited-list #\) stream t :dot-allowed t))) */
  2433. LISPFUNN(lpar_reader,2) { /* reads ( */
  2434. var gcv_object_t* stream_ = check_stream_arg(&STACK_1);
  2435. /* read List after '(' until ')', Dot allowed: */
  2436. VALUES1(read_delimited_list(stream_,ascii_char(')'),dot_value));
  2437. skipSTACK(2);
  2438. }
  2439. /* #| ( ( |#
  2440. (set-macro-character #\)
  2441. #'(lambda (stream char)
  2442. (error "~S of ~S: ~S at the beginning of object" 'read stream char))) */
  2443. LISPFUNN(rpar_reader,2) { /* reads ) */
  2444. var gcv_object_t* stream_ = check_stream_arg(&STACK_1);
  2445. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  2446. pushSTACK(STACK_(0+1)); /* char */
  2447. pushSTACK(*stream_); /* stream */
  2448. pushSTACK(S(read));
  2449. error(reader_error,GETTEXT("~S from ~S: an object cannot start with ~S"));
  2450. }
  2451. /* (set-macro-character #\"
  2452. #'(lambda (stream char)
  2453. (let ((buffer (make-array 50 :element-type 'character
  2454. :adjustable t :fill-pointer 0)))
  2455. (loop
  2456. (multiple-value-bind (ch sy) (read-char-syntax stream)
  2457. (cond ((eq sy 'eof-code)
  2458. (error "~S: inputstream ~S ends within a String."
  2459. 'read stream))
  2460. ((eql ch char) (return (coerce buffer 'simple-string)))
  2461. ((eq sy 'single-escape)
  2462. (multiple-value-setq (ch sy) (read-char-syntax stream))
  2463. (when (eq sy 'eof-code) (error ...))
  2464. (vector-push-extend ch buffer))
  2465. (t (vector-push-extend ch buffer)))))
  2466. (if *read-suppress* nil (coerce buffer 'simple-string))))) */
  2467. LISPFUNN(string_reader,2) { /* reads " */
  2468. var gcv_object_t* stream_ = check_stream_arg(&STACK_1);
  2469. var object delim_char = STACK_0;
  2470. if (terminal_stream_p(*stream_)) {
  2471. dynamic_bind(S(terminal_read_open_object),S(string));
  2472. pushSTACK(*stream_);
  2473. pushSTACK(delim_char);
  2474. stream_ = &(STACK_1);
  2475. }
  2476. /* stack layout: stream, char. */
  2477. if (!nullpSv(read_suppress)) { /* *READ-SUPPRESS* /= NIL ? */
  2478. /* yes -> only read ahead of string: */
  2479. while (1) {
  2480. /* read next character: */
  2481. var object ch;
  2482. var uintWL scode;
  2483. read_char_syntax(ch = ,scode = ,stream_);
  2484. if (scode == syntax_eof) /* EOF -> error */
  2485. goto error_eof;
  2486. if (eq(ch,STACK_0)) /* same character as char -> finished */
  2487. break;
  2488. if (scode == syntax_single_esc) { /* Single-Escape-Character? */
  2489. /* yes -> read another character: */
  2490. read_char_syntax(ch = ,scode = ,stream_);
  2491. if (scode == syntax_eof) /* EOF -> error */
  2492. goto error_eof;
  2493. }
  2494. }
  2495. VALUES1(NIL);
  2496. } else {
  2497. /* no -> really read String */
  2498. get_buffers(); /* two empty Buffers on the Stack */
  2499. /* stack layout: stream, char, Buffer, anotherBuffer. */
  2500. if (stream_get_fasl(*stream_)) while (1) { /* faithful */
  2501. /* read next character: */
  2502. object ch = read_char(stream_);
  2503. if (eq(ch,eof_value)) goto error_eof;
  2504. if (eq(ch,ascii_char('"')))
  2505. break;
  2506. /* ignore newlines */
  2507. if (!(eq(ch,ascii_char(0x0A)) || eq(ch,ascii_char(0x0D)))) {
  2508. if (eq(ch,ascii_char('\\'))) { /* single-escape-character? */
  2509. /* yes -> read another character: */
  2510. ch = read_char(stream_);
  2511. if (eq(ch,eof_value)) goto error_eof;
  2512. if (eq(ch,ascii_char('n')))
  2513. ch = ascii_char(0x0A); /* "\n" = #\Linefeed */
  2514. else if (eq(ch,ascii_char('r')))
  2515. ch = ascii_char(0x0D); /* "\r" = #\Return */
  2516. }
  2517. /* push character ch into Buffer: */
  2518. ssstring_push_extend(STACK_1,char_code(ch));
  2519. }
  2520. } else while (1) { /* ANSI */
  2521. /* read next character: */
  2522. var object ch;
  2523. var uintWL scode;
  2524. read_char_syntax(ch = ,scode = ,stream_);
  2525. if (scode == syntax_eof) /* EOF -> error */
  2526. goto error_eof;
  2527. if (eq(ch,STACK_2)) /* same character as char -> finished */
  2528. break;
  2529. if (scode == syntax_single_esc) { /* Single-Escape-Character? */
  2530. /* yes -> read another character: */
  2531. read_char_syntax(ch = ,scode = ,stream_);
  2532. if (scode == syntax_eof) /* EOF -> error */
  2533. goto error_eof;
  2534. }
  2535. /* push character ch into Buffer: */
  2536. ssstring_push_extend(STACK_1,char_code(ch));
  2537. }
  2538. /* copy Buffer and convert it into Simple-String: */
  2539. {
  2540. var object string;
  2541. #ifndef TYPECODES
  2542. if (TheStream(*stream_)->strmflags & bit(strmflags_immut_bit_B))
  2543. string = coerce_imm_ss(STACK_1);
  2544. else
  2545. #endif
  2546. string = copy_string(STACK_1);
  2547. VALUES1(string);
  2548. }
  2549. /* free Buffer for reuse: */
  2550. O(token_buff_2) = popSTACK(); O(token_buff_1) = popSTACK();
  2551. }
  2552. if (terminal_stream_p(*stream_)) {
  2553. skipSTACK(2);
  2554. dynamic_unbind(S(terminal_read_open_object));
  2555. }
  2556. skipSTACK(2);
  2557. return;
  2558. error_eof:
  2559. if (terminal_stream_p(*stream_)) {
  2560. skipSTACK(2);
  2561. dynamic_unbind(S(terminal_read_open_object));
  2562. }
  2563. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  2564. pushSTACK(*stream_); /* Stream */
  2565. pushSTACK(S(read));
  2566. error(end_of_file,GETTEXT("~S: input stream ~S ends within a string"));
  2567. }
  2568. /* reads an Object and creates a list with two elements.
  2569. list2_reader(stream_);
  2570. > stack layout: stream, symbol.
  2571. increases STACK by 2
  2572. modifies STACK, can trigger GC
  2573. can trigger GC */
  2574. local maygc Values list2_reader (const gcv_object_t* stream_) {
  2575. dynamic_bind(S(read_recursive_p),T);
  2576. var object obj = read_recursive_no_dot(stream_); /* read Object */
  2577. dynamic_unbind(S(read_recursive_p));
  2578. if (!nullpSv(read_suppress)) { /* *READ-SUPPRESS* /= NIL ? */
  2579. VALUES1(NIL); /* yes -> don't cons up a list, just return NIL */
  2580. } else {
  2581. pushSTACK(obj);
  2582. pushSTACK(allocate_cons()); /* second List-cons */
  2583. var object new_cons1 = allocate_cons(); /* first List-cons */
  2584. var object new_cons2 = popSTACK(); /* second List-cons */
  2585. Car(new_cons2) = popSTACK(); /* new_cons2 = (cons obj nil) */
  2586. Cdr(new_cons1) = new_cons2; Car(new_cons1) = STACK_0; /* new_cons1 = (cons symbol new_cons2) */
  2587. VALUES1(new_cons1);
  2588. }
  2589. skipSTACK(2);
  2590. }
  2591. /* (set-macro-character #\'
  2592. #'(lambda (stream char)
  2593. (list 'QUOTE (read stream t nil t)))) */
  2594. LISPFUNN(quote_reader,2) { /* reads ' */
  2595. var gcv_object_t* stream_ = check_stream_arg(&STACK_1);
  2596. STACK_0 = S(quote); return_Values list2_reader(stream_);
  2597. }
  2598. /* (set-macro-character #\;
  2599. #'(lambda (stream char)
  2600. (loop
  2601. (let ((ch (read-char stream)))
  2602. (when (or (eql ch 'eof-code) (eql ch #\Newline)) (return))))
  2603. (values))) */
  2604. LISPFUNN(line_comment_reader,2) { /* reads ; */
  2605. var gcv_object_t* stream_ = check_stream_arg(&STACK_1);
  2606. while (1) {
  2607. var object ch = read_char(stream_); /* read character */
  2608. if (eq(ch,eof_value) || eq(ch,ascii_char(NL)))
  2609. break;
  2610. }
  2611. VALUES0; skipSTACK(2); /* return no values */
  2612. }
  2613. /* ---------------------- READ-Dispatch-Macros --------------------------- */
  2614. /* error-message due to forbidden number at Dispatch-Macros
  2615. error_dispatch_number()
  2616. > STACK_1: Stream
  2617. > STACK_0: sub-char */
  2618. nonreturning_function(local, error_dispatch_number, (void)) {
  2619. pushSTACK(STACK_1); /* STREAM-ERROR slot STREAM */
  2620. pushSTACK(STACK_(0+1)); /* sub-char */
  2621. pushSTACK(STACK_(1+2)); /* Stream */
  2622. pushSTACK(S(read));
  2623. error(reader_error,
  2624. GETTEXT("~S from ~S: no number allowed between #"" and ~C"));
  2625. }
  2626. /* UP: checks the absence of Infix-Argument n
  2627. test_no_infix()
  2628. > stack layout: Stream, sub-char, n.
  2629. < result: &stream
  2630. increases STACK by 1
  2631. modifies STACK
  2632. can trigger GC */
  2633. local maygc gcv_object_t* test_no_infix (void) {
  2634. var gcv_object_t* stream_ = check_stream_arg(&STACK_2);
  2635. var object n = popSTACK();
  2636. if ((!nullp(n)) && nullpSv(read_suppress))
  2637. /* if n/=NIL and *READ-SUPPRESS*=NIL : report error */
  2638. error_dispatch_number();
  2639. return stream_;
  2640. }
  2641. /* (set-dispatch-macro-character #\##\'
  2642. #'(lambda (stream sub-char n)
  2643. (when n (error ...))
  2644. (list 'FUNCTION (read stream t nil t)))) */
  2645. LISPFUNN(function_reader,3) { /* reads #' */
  2646. var gcv_object_t* stream_ = test_no_infix(); /* n must be NIL */
  2647. STACK_0 = S(function); return_Values list2_reader(stream_);
  2648. }
  2649. /* (set-dispatch-macro-character #\##\|
  2650. #'(lambda (stream sub-char n) ; with (not (eql sub-char #\#))
  2651. (when n (error ...))
  2652. (prog ((depth 0) ch)
  2653. 1
  2654. (setq ch (read-char))
  2655. 2
  2656. (case ch
  2657. (eof-code (error ...))
  2658. (sub-char (case (setq ch (read-char))
  2659. (eof-code (error ...))
  2660. (#\#(when (minusp (decf depth)) (return)))
  2661. (t (go 2))))
  2662. (#\#(case (setq ch (read-char))
  2663. (eof-code (error ...))
  2664. (sub-char (incf depth) (go 1))
  2665. (t (go 2))))
  2666. (t (go 1))))
  2667. (values))) */
  2668. LISPFUNN(comment_reader,3) { /* reads #| */
  2669. var gcv_object_t* stream_ = test_no_infix(); /* n must be NIL */
  2670. var uintL depth = 0;
  2671. var object ch;
  2672. loop1:
  2673. ch = read_char(stream_);
  2674. loop2:
  2675. if (eq(ch,eof_value)) /* EOF -> Error */
  2676. goto error_eof;
  2677. else if (eq(ch,STACK_0)) {
  2678. /* sub-char has been read */
  2679. ch = read_char(stream_); /* next character */
  2680. if (eq(ch,eof_value)) /* EOF -> Error */
  2681. goto error_eof;
  2682. else if (eq(ch,ascii_char('#'))) {
  2683. /* sub-char and '#' has been read -> decrease depth: */
  2684. if (depth==0)
  2685. goto done;
  2686. depth--;
  2687. goto loop1;
  2688. } else
  2689. goto loop2;
  2690. } else if (eq(ch,ascii_char('#'))) {
  2691. /* '#' has been read */
  2692. ch = read_char(stream_); /* next character */
  2693. if (eq(ch,eof_value)) /* EOF -> Error */
  2694. goto error_eof;
  2695. else if (eq(ch,STACK_0)) {
  2696. /* '#' and sub-char has been read -> increase depth: */
  2697. depth++;
  2698. goto loop1;
  2699. } else
  2700. goto loop2;
  2701. } else
  2702. goto loop1;
  2703. error_eof: {
  2704. pushSTACK(STACK_1); /* STREAM-ERROR slot STREAM */
  2705. pushSTACK(STACK_(0+1)); /* sub-char */
  2706. pushSTACK(STACK_(0+2)); /* sub-char */
  2707. pushSTACK(STACK_(1+3)); /* Stream */
  2708. pushSTACK(S(read));
  2709. error(end_of_file,
  2710. GETTEXT("~S: input stream ~S ends within a comment #~C ... ~C#"));
  2711. }
  2712. done:
  2713. VALUES0; skipSTACK(2); /* return no values */
  2714. }
  2715. /* (set-dispatch-macro-character #\##\\
  2716. #'(lambda (stream sub-char n)
  2717. (let ((token (read-token-1 stream #\\ 'single-escape)))
  2718. ; token is a String of Length >=1
  2719. (unless *read-suppress*
  2720. (if n
  2721. (unless (< n char-font-limit) ; n>=0, anyway
  2722. (error "~S of ~S: Font-Number ~S for Character is too big (must be <~S )."
  2723. 'read stream n char-font-limit))
  2724. (setq n 0))
  2725. (let ((pos 0) (bits 0))
  2726. (loop
  2727. (if (= (+ pos 1) (length token))
  2728. (return (make-char (char token pos) bits n))
  2729. (let ((hyphen (position #\- token :start pos)))
  2730. (if hyphen
  2731. (flet ((equalx (name)
  2732. (or (string-equal token name :start1 pos :end1 hyphen)
  2733. (string-equal token name :start1 pos :end1 hyphen :end2 1))))
  2734. (cond ((equalx "CONTROL")
  2735. (setq bits (logior bits char-control-bit)))
  2736. ((equalx "META")
  2737. (setq bits (logior bits char-meta-bit)))
  2738. ((equalx "SUPER")
  2739. (setq bits (logior bits char-super-bit)))
  2740. ((equalx "HYPER")
  2741. (setq bits (logior bits char-hyper-bit)))
  2742. (t (error "~S of ~S: A Character-Bit with Name ~S does not exist."
  2743. 'read stream (subseq token pos hyphen))))
  2744. (setq pos (1+ hyphen)))
  2745. (return
  2746. (make-char
  2747. (cond ((and (< (+ pos 4) (length token))
  2748. (string-equal token "CODE" :start1 pos :end1 (+ pos 4)))
  2749. (code-char (parse-integer token :start (+ pos 4) :junk-allowed nil))) ; without Sign!
  2750. ((and (= (+ pos 2) (length token))
  2751. (eql (char token pos) #\^)
  2752. (<= 64 (char-code (char token (+ pos 1))) 95))
  2753. (code-char (- (char-code (char token (+ pos 1))) 64)))
  2754. ((name-char (subseq token pos)))
  2755. (t (error "~S of ~S: A Character with Name ~S does not exist."
  2756. 'read stream (subseq token pos))))
  2757. bits n))))))))))) */
  2758. LISPFUNN(char_reader,3) { /* reads #\ */ \
  2759. /* stack layout: Stream, sub-char, n. */
  2760. var gcv_object_t* stream_ = check_stream_arg(&STACK_2);
  2761. /* read Token, with Dummy-Character '\' as start of Token: */
  2762. read_token_1(stream_,ascii_char('\\'),syntax_single_esc);
  2763. /* finished at once, when *READ-SUPPRESS* /= NIL: */
  2764. if (!nullpSv(read_suppress)) {
  2765. VALUES1(NIL); skipSTACK(3); /* NIL as value */
  2766. return;
  2767. }
  2768. case_convert_token_1();
  2769. /* determine Font: */
  2770. if (!nullp(STACK_0)) /* n=NIL -> Default-Font 0 */
  2771. if (!eq(STACK_0,Fixnum_0)) {
  2772. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  2773. pushSTACK(STACK_(0+1)); /* n */
  2774. pushSTACK(*stream_); /* Stream */
  2775. pushSTACK(S(read));
  2776. error(reader_error,GETTEXT("~S from ~S: font number ~S for character is too large, should be = 0"));
  2777. }
  2778. /* Font ready. */
  2779. var object token = O(token_buff_1); /* read Token as Semi-Simple-String */
  2780. var uintL len = TheIarray(token)->dims[1]; /* lengh = Fill-Pointer */
  2781. var object hstring = O(displaced_string); /* auxiliary string */
  2782. TheIarray(hstring)->data = token; /* Data-vector := O(token_buff_1) */
  2783. token = TheIarray(token)->data; /* Normal-Simple-String with Token */
  2784. var uintL pos = 0; /* current Position in Token */
  2785. /* do not search for bits since this interferes with
  2786. Unicode names which contain hyphens */
  2787. var uintL sub_len = len-pos; /* Length of Character name */
  2788. if (sub_len == 1) { /* character name consists of one letter */
  2789. var chart code = TheSnstring(token)->data[pos]; /* (char token pos) */
  2790. VALUES1(code_char(code)); skipSTACK(3);
  2791. return;
  2792. }
  2793. TheIarray(hstring)->dims[0] = pos; /* Displaced-Offset := pos */
  2794. /* TheIarray(hstring)->totalsize =
  2795. TheIarray(hstring)->dims[1] = sub_len; - Length := len-pos
  2796. hstring = (subseq token pos hyphen) = remaining Charactername
  2797. Test for Character-Came "CODExxxx" (xxxx Decimalnumber <256): */
  2798. if (sub_len > 4) {
  2799. TheIarray(hstring)->totalsize =
  2800. TheIarray(hstring)->dims[1] = 4;
  2801. /* hstring = (subseq token pos (+ pos 4)) */
  2802. if (!string_equal(hstring,O(charname_prefix))) /* = "Code" ? */
  2803. goto not_codexxxx; /* no -> continue */
  2804. /* decipher Decimal number: */
  2805. var uintL code = 0; /* so far read xxxx (<char_code_limit) */
  2806. var uintL index = pos+4;
  2807. var const chart* charptr = &TheSnstring(token)->data[index];
  2808. for (; index != len; index++) { /* not reached end of Token? */
  2809. var cint c = as_cint(*charptr++); /* next Character */
  2810. /* is to be digit: */
  2811. if (!((c>='0') && (c<='9')))
  2812. goto not_codexxxx;
  2813. code = 10*code + (c-'0'); /* add digit */
  2814. /* code is to be < char_code_limit: */
  2815. if (code >= char_code_limit)
  2816. goto not_codexxxx;
  2817. }
  2818. /* Charactername was of type Typ "Codexxxx" with code = xxxx < char_code_limit */
  2819. VALUES1(code_char(as_chart(code))); skipSTACK(3);
  2820. return;
  2821. }
  2822. not_codexxxx:
  2823. /* Test for Pseudo-Character-Name ^X: */
  2824. if ((sub_len == 2) && chareq(TheSnstring(token)->data[pos],ascii('^'))) {
  2825. var cint code = as_cint(TheSnstring(token)->data[pos+1])-64;
  2826. if (code < 32) {
  2827. VALUES1(ascii_char(code)); skipSTACK(3);
  2828. return;
  2829. }
  2830. }
  2831. /* Test for Charactername like NAME-CHAR: */
  2832. TheIarray(hstring)->totalsize =
  2833. TheIarray(hstring)->dims[1] = sub_len; /* Length := len-pos */
  2834. var object ch = name_char(hstring); /* search Character with this Name */
  2835. if (nullp(ch)) { /* not found -> Error */
  2836. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  2837. pushSTACK(copy_string(hstring)); /* copy Charactername */
  2838. pushSTACK(*stream_); /* Stream */
  2839. pushSTACK(S(read));
  2840. error(reader_error,
  2841. GETTEXT("~S from ~S: there is no character with name ~S"));
  2842. }
  2843. /* found */
  2844. VALUES1(ch); skipSTACK(3);
  2845. return;
  2846. }
  2847. /* (defun radix-1 (stream sub-char n base)
  2848. (let ((token (read-token stream)))
  2849. (unless *read-suppress*
  2850. (when n (error ...))
  2851. (if (case (test-number-syntax token base)
  2852. (integer t) (decimal-integer nil) (rational t) (float nil))
  2853. (read-number token base)
  2854. (error "~S of ~S: The token ~S after #~C cannot be interpreted as rational number in base ~S."
  2855. 'read stream token sub-char base)))))
  2856. UP: for #B #O #X #R
  2857. radix_2(base)
  2858. > base: Basis (>=2, <=36)
  2859. > stack layout: Stream, sub-char, base.
  2860. > O(token_buff_1), O(token_buff_2), token_escape_flag: read Token
  2861. < STACK: cleaned up
  2862. < mv_space/mv_count: values
  2863. can trigger GC */
  2864. local maygc Values radix_2 (uintWL base) {
  2865. /* check, if the Token is a rational number: */
  2866. upcase_token(); /* convert to upper case */
  2867. var object string;
  2868. var zahl_info_t info;
  2869. switch (test_number_syntax(&base,&string,&info)) {
  2870. case 1: /* Integer */
  2871. /* is last Character a dot? */
  2872. if (chareq(TheSnstring(string)->data[info.index2-1],ascii('.')))
  2873. /* yes -> Decimal-Integer, not in Base base */
  2874. goto not_rational;
  2875. /* test_number_syntax finished already in step 3,
  2876. so base is still unchanged. */
  2877. skipSTACK(3);
  2878. VALUES1(read_integer(base,info.sign,string,info.index1,info.index2));
  2879. return;
  2880. case 2: /* Rational */
  2881. /* test_number_syntax finished already in step 3,
  2882. so base is still unchanged. */
  2883. skipSTACK(3);
  2884. VALUES1(read_rational(base,info.sign,string,info.index1,
  2885. info.index3,info.index2));
  2886. return;
  2887. case 0: /* no number */
  2888. case 3: /* Float */
  2889. not_rational: { /* no rational number */
  2890. pushSTACK(STACK_2); /* STREAM-ERROR slot STREAM */
  2891. pushSTACK(STACK_(0+1)); /* base */
  2892. pushSTACK(STACK_(1+2)); /* sub-char */
  2893. pushSTACK(copy_string(O(token_buff_1))); /* Token */
  2894. pushSTACK(STACK_(2+4)); /* Stream */
  2895. pushSTACK(S(read));
  2896. error(reader_error,GETTEXT("~S from ~S: token ~S after #~C is not a rational number in base ~S"));
  2897. }
  2898. default: NOTREACHED;
  2899. }
  2900. }
  2901. /* UP: for #B #O #X
  2902. radix_1(base)
  2903. > base: Base (>=2, <=36)
  2904. > stack layout: Stream, sub-char, n.
  2905. < STACK: cleaned
  2906. < mv_space/mv_count: values
  2907. can trigger GC */
  2908. local maygc Values radix_1 (uintWL base) {
  2909. var gcv_object_t* stream_ = check_stream_arg(&STACK_2);
  2910. read_token(stream_); /* read Token */
  2911. /* finished at once when *READ-SUPPRESS* /= NIL: */
  2912. if (!nullpSv(read_suppress)) {
  2913. VALUES1(NIL); skipSTACK(3); /* NIL as value */
  2914. return;
  2915. }
  2916. if (!nullp(popSTACK())) /* n/=NIL -> Error */
  2917. error_dispatch_number();
  2918. pushSTACK(fixnum(base)); /* base as Fixnum */
  2919. return_Values radix_2(base);
  2920. }
  2921. /* (set-dispatch-macro-character #\##\B
  2922. #'(lambda (stream sub-char n) (radix-1 stream sub-char n 2))) */
  2923. LISPFUNN(binary_reader,3) { /* reads #B */
  2924. return_Values radix_1(2);
  2925. }
  2926. /* (set-dispatch-macro-character #\##\O
  2927. #'(lambda (stream sub-char n) (radix-1 stream sub-char n 8))) */
  2928. LISPFUNN(octal_reader,3) { /* reads #O */
  2929. return_Values radix_1(8);
  2930. }
  2931. /* (set-dispatch-macro-character #\##\X
  2932. #'(lambda (stream sub-char n) (radix-1 stream sub-char n 16))) */
  2933. LISPFUNN(hexadecimal_reader,3) { /* reads #X */
  2934. return_Values radix_1(16);
  2935. }
  2936. /* (set-dispatch-macro-character #\##\R
  2937. #'(lambda (stream sub-char n)
  2938. (if *read-suppress*
  2939. (if (and n (<= 2 n 36))
  2940. (radix-1 stream sub-char nil n)
  2941. (error "~S from ~S: The base ~S given between #"" and R should lie between 2 and 36." 'read stream))
  2942. (progn (read-token stream) nil)))) */
  2943. LISPFUNN(radix_reader,3) { /* reads #R */
  2944. var gcv_object_t* stream_ = check_stream_arg(&STACK_2);
  2945. read_token(stream_); /* read Token */
  2946. /* finished at once when *READ-SUPPRESS* /= NIL: */
  2947. if (!nullpSv(read_suppress)) {
  2948. VALUES1(NIL); skipSTACK(3);
  2949. return;
  2950. }
  2951. /* check n: */
  2952. if (nullp(STACK_0)) {
  2953. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  2954. pushSTACK(*stream_); /* Stream */
  2955. pushSTACK(S(read));
  2956. error(reader_error,GETTEXT("~S from ~S: the number base must be given between #"" and R"));
  2957. }
  2958. var uintV base;
  2959. /* n must be a Fixnum between 2 and 36 (inclusive): */
  2960. if (posfixnump(STACK_0)
  2961. && (base = posfixnum_to_V(STACK_0), (base >= 2) && (base <= 36))) {
  2962. return_Values radix_2(base); /* interprete Token as rational number */
  2963. } else {
  2964. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  2965. pushSTACK(STACK_(0+1)); /* n */
  2966. pushSTACK(*stream_); /* Stream */
  2967. pushSTACK(S(read));
  2968. error(reader_error,
  2969. GETTEXT("~S from ~S: The base ~S given between #"" and R should lie between 2 and 36"));
  2970. }
  2971. }
  2972. /* (set-dispatch-macro-character #\##\C
  2973. #'(lambda (stream sub-char n)
  2974. (declare (ignore sub-char))
  2975. (if *read-suppress*
  2976. (progn (read stream t nil t) nil)
  2977. (if n
  2978. (error "bad syntax")
  2979. (let ((h (read stream t nil t)))
  2980. (if (and (consp h) (consp (cdr h)) (null (cddr h))
  2981. (numberp (first h)) (not (complexp (first h)))
  2982. (numberp (second h)) (not (complexp (second h))))
  2983. (apply #'complex h)
  2984. (error "~S: Wrong Syntax for complex Number: #C~S" 'read h)))))))
  2985. */
  2986. LISPFUNN(complex_reader,3) { /* reads #C */
  2987. var gcv_object_t* stream_ = test_no_infix(); /* n must be NIL */
  2988. var object obj = read_recursive_no_dot(stream_); /* read next Object */
  2989. /* finished at once when *READ-SUPPRESS* /= NIL: */
  2990. if (!nullpSv(read_suppress)) {
  2991. VALUES1(NIL); skipSTACK(2);
  2992. return;
  2993. }
  2994. obj = make_references(obj); /* unentangle references untimely */
  2995. /* check, if this is a 2-elemnt List of real numbers: */
  2996. if (!consp(obj)) goto bad; /* obj must be a Cons ! */
  2997. {
  2998. var object obj2 = Cdr(obj);
  2999. if (!consp(obj2)) goto bad; /* obj2 must be a Cons! */
  3000. if (!nullp(Cdr(obj2))) goto bad; /* with (cdr obj2) = nil ! */
  3001. if_realp(Car(obj), ; , goto bad; ); /* and (car obj) being a real! */
  3002. if_realp(Car(obj2), ; , goto bad; ); /* and (car obj2) being a real! */
  3003. /* execute (apply #'COMPLEX obj): */
  3004. apply(L(complex),0,obj);
  3005. mv_count=1; skipSTACK(2); return; /* value1 as value */
  3006. }
  3007. bad:
  3008. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3009. pushSTACK(obj); /* Object */
  3010. pushSTACK(*stream_); /* Stream */
  3011. pushSTACK(S(read));
  3012. error(reader_error,
  3013. GETTEXT("~S from ~S: bad syntax for complex number: #C~S"));
  3014. }
  3015. /* (set-dispatch-macro-character #\##\:
  3016. #'(lambda (stream sub-char n)
  3017. (declare (ignore sub-char))
  3018. (if *read-suppress*
  3019. (progn (read stream t nil t) nil)
  3020. (let ((name (read-token stream))) ; eine Form, die nur ein Token ist
  3021. (when n (error ...))
  3022. [verify, if also no Package-Marker occurs in the Token.]
  3023. (make-symbol token))))) */
  3024. LISPFUNN(uninterned_reader,3) { /* reads #: */
  3025. var gcv_object_t* stream_ = check_stream_arg(&STACK_2);
  3026. /* when *READ-SUPPRESS* /= NIL, read form and return NIL: */
  3027. if (!nullpSv(read_suppress)) {
  3028. read_recursive(stream_);
  3029. VALUES1(NIL); skipSTACK(3); return;
  3030. }
  3031. { /* read next character: */
  3032. var object ch;
  3033. var uintWL scode;
  3034. read_char_syntax(ch = ,scode = ,stream_);
  3035. if (scode == syntax_eof) /* EOF -> Error */
  3036. error_eof_inside(stream_);
  3037. if (scode > syntax_constituent) {
  3038. /* no character, that is allowed at beginning of Token -> Error */
  3039. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3040. pushSTACK(*stream_); /* Stream */
  3041. pushSTACK(S(read));
  3042. error(reader_error,GETTEXT("~S from ~S: token expected after #:"));
  3043. }
  3044. /* read Token until the end: */
  3045. read_token_1(stream_,ch,scode);
  3046. case_convert_token_1();
  3047. }
  3048. if (!nullp(popSTACK())) /* n/=NIL -> Error */
  3049. error_dispatch_number();
  3050. /* copy Token and convert into Simple-String: */
  3051. var object string = coerce_imm_ss(O(token_buff_1));
  3052. { /* test for Package-Marker: */
  3053. var object buff_2 = O(token_buff_2); /* Attribut-Code-Buffer */
  3054. var uintL len = TheIarray(buff_2)->dims[1]; /* length = Fill-Pointer */
  3055. if (len > 0) {
  3056. var uintB* attrptr = &TheSbvector(TheIarray(buff_2)->data)->data[0];
  3057. /* Test, if one of the len Attribut-Codes starting at attrptr and afterwards is an a_pack_m: */
  3058. dotimespL(len,len, { if (*attrptr++ == a_pack_m) goto error_colon; } );
  3059. }
  3060. }
  3061. /* build uninterned Symbol with this Name: */
  3062. VALUES1(make_symbol(string)); skipSTACK(2); return;
  3063. error_colon:
  3064. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3065. pushSTACK(string); /* Token */
  3066. pushSTACK(*stream_); /* Stream */
  3067. pushSTACK(S(read));
  3068. error(reader_error,
  3069. GETTEXT("~S from ~S: token ~S after #: should contain no colon"));
  3070. }
  3071. /* UP: check that the (bit)vector length specified between #\#and #\( (or #\*)
  3072. is compatible with the token specifying the (bit)vector elements
  3073. > token_length - the number of elements in the content token
  3074. > type - VECTOR or BIT-VECTOR
  3075. > stream_ - the input stream
  3076. > STACK_0 - the (bit)vector length specifier (integer)
  3077. < (bit)vector length to be returned by the reader */
  3078. local uintV read_vector_length_check (uintV token_length,object type,
  3079. gcv_object_t *stream_) {
  3080. if (nullp(STACK_0)) {
  3081. return token_length; /* default value is the token length */
  3082. } else { /* n specified, an Integer >=0. */
  3083. uintV n =
  3084. (posfixnump(STACK_0) ? posfixnum_to_V(STACK_0) /* Fixnum -> value */
  3085. : vbitm(oint_data_len)-1); /* Bignum -> big value */
  3086. if (n < token_length) {
  3087. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3088. pushSTACK(STACK_(0+1)); /* n */
  3089. pushSTACK(type); /* VECTOR or BIT-VECTOR */
  3090. pushSTACK(*stream_); /* Stream */
  3091. pushSTACK(S(read));
  3092. error(reader_error, /* ANSI CL 2.4.8.4. wants a reader-error here */
  3093. GETTEXT("~S from ~S: ~S is longer than the explicitly given length ~S"));
  3094. }
  3095. if ((n>0) && (token_length==0)) {
  3096. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3097. pushSTACK(STACK_(0+1)); /* n */
  3098. pushSTACK(type); /* VECTOR or BIT-VECTOR */
  3099. pushSTACK(*stream_); /* Stream */
  3100. pushSTACK(S(read));
  3101. error(reader_error, /* ANSI CL 2.4.8.4. wants a reader-error here */
  3102. GETTEXT("~S from ~S: must specify elements of ~S of length ~S"));
  3103. }
  3104. #if (intVsize>intLsize)
  3105. if (n >= vbit(intLsize)) {
  3106. /* STACK_0 = n, TYPE-ERROR slot DATUM */
  3107. pushSTACK(O(type_array_length)); /* TYPE-ERROR slot EXPECTED-TYPE */
  3108. pushSTACK(STACK_1); /* n */
  3109. pushSTACK(type); /* VECTOR or BIT-VECTOR */
  3110. pushSTACK(*stream_); /* Stream */
  3111. pushSTACK(S(read));
  3112. error(type_error,GETTEXT("~S from ~S: invalid ~S length ~S"));
  3113. }
  3114. #endif
  3115. return n;
  3116. }
  3117. }
  3118. /* (set-dispatch-macro-character #\##\*
  3119. #'(lambda (stream sub-char n)
  3120. (declare (ignore sub-char))
  3121. (let* ((token (read-token stream)))
  3122. (unless *read-suppress*
  3123. (unless (or [Escape-Zeichen im Token verwendet]
  3124. (every #'(lambda (ch) (member ch '(#\0 #\1))) token))
  3125. (error "~S of ~S: After #* only zeroes and ones may occur."
  3126. 'read stream))
  3127. (let ((l (length token)))
  3128. (if n
  3129. (cond ((< n l)
  3130. (error "~S of ~S: bit vector longer than specified length ~S."
  3131. 'read stream n))
  3132. ((and (plusp n) (zerop l))
  3133. (error "~S of ~S: element for bit vector of length ~S must be specified."
  3134. 'read stream n)))
  3135. (setq n l))
  3136. (let ((bv (make-array n :element-type 'bit))
  3137. (i 0)
  3138. b)
  3139. (loop
  3140. (when (= i n) (return))
  3141. (when (< i l) (setq b (case (char token i) (#\0 0) (#\1 1))))
  3142. (setf (sbit bv i) b)
  3143. (incf i))
  3144. bv)))))) */
  3145. LISPFUNN(bit_vector_reader,3) { /* reads #* */
  3146. var gcv_object_t* stream_ = check_stream_arg(&STACK_2);
  3147. read_token(stream_); /* read Token */
  3148. /* finished at once, if *READ-SUPPRESS* /= NIL: */
  3149. if (!nullpSv(read_suppress)) {
  3150. VALUES1(NIL); skipSTACK(3);
  3151. return;
  3152. }
  3153. /* Test, if no Escape-character and only 0s and 1s are used: */
  3154. if (token_escape_flag) {
  3155. error_only01:
  3156. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3157. pushSTACK(*stream_); /* Stream */
  3158. pushSTACK(S(read));
  3159. error(reader_error, /* ANSI CL 2.4.8.4. wants a reader-error here */
  3160. GETTEXT("~S from ~S: only zeroes and ones are allowed after #*"));
  3161. }
  3162. var object buff_1 = O(token_buff_1); /* Character-Buffer */
  3163. var uintL len = TheIarray(buff_1)->dims[1]; /* length = Fill-Pointer */
  3164. if (len > 0) {
  3165. var const chart* charptr = &TheSnstring(TheIarray(buff_1)->data)->data[0];
  3166. var uintL count;
  3167. dotimespL(count,len, {
  3168. var chart c = *charptr++; /* next Character */
  3169. if (!(chareq(c,ascii('0')) || chareq(c,ascii('1')))) /* only '0' and '1' are OK */
  3170. goto error_only01;
  3171. });
  3172. }
  3173. /* check n (the length of the bit-vector): */
  3174. var uintV n = read_vector_length_check(len,S(bit_vector),stream_);
  3175. /* create new Bit-Vector with length n: */
  3176. var object bv = allocate_bit_vector(Atype_Bit,n);
  3177. /* and fill the Bits into it: */
  3178. buff_1 = O(token_buff_1);
  3179. {
  3180. var const chart* charptr = &TheSnstring(TheIarray(buff_1)->data)->data[0];
  3181. var chart ch; /* last character ('0' or '1') */
  3182. var uintL index = 0;
  3183. for (; index < n; index++) {
  3184. if (index < len)
  3185. ch = *charptr++; /* possibly, fetch next Character */
  3186. if (chareq(ch,ascii('0'))) {
  3187. sbvector_bclr(bv,index); /* Null -> delete Bit */
  3188. } else {
  3189. sbvector_bset(bv,index); /* One -> set Bit */
  3190. }
  3191. }
  3192. }
  3193. VALUES1(bv); skipSTACK(3);
  3194. }
  3195. /* (set-dispatch-macro-character #\##\(
  3196. #'(lambda (stream sub-char n)
  3197. (declare (ignore sub-char))
  3198. (let* ((elements (read-delimited-list #\) stream t)))
  3199. (unless *read-suppress*
  3200. (let ((l (length elements)))
  3201. (if n
  3202. (cond ((< n l)
  3203. (error "~S of ~S: Vector longer than specified length ~S."
  3204. 'read stream n))
  3205. ((and (plusp n) (zerop l))
  3206. (error "~S of ~S: Element for vector of length ~S must be specified."
  3207. 'read stream n)))
  3208. (setq n l))
  3209. (let ((v (make-array n))
  3210. (i 0)
  3211. b)
  3212. (loop
  3213. (when (= i n) (return))
  3214. (when (< i l) (setq b (pop elements)))
  3215. (setf (svref v i) b)
  3216. (incf i))
  3217. v)))))) */
  3218. LISPFUNN(vector_reader,3) { /* reads #( */
  3219. var gcv_object_t* stream_ = check_stream_arg(&STACK_2);
  3220. /* read List until parenthese, Dot is not allowed: */
  3221. var object elements = read_delimited_list(stream_,ascii_char(')'),eof_value);
  3222. /* already finished when *READ-SUPPRESS* /= NIL: */
  3223. if (!nullpSv(read_suppress)) {
  3224. VALUES1(NIL); skipSTACK(3);
  3225. return;
  3226. }
  3227. var uintL len = llength(elements); /* Listlength */
  3228. /* check n (the length of the vector): */
  3229. var uintV n = read_vector_length_check(len,S(vector),stream_);
  3230. /* create new Vector with Length n: */
  3231. pushSTACK(elements); /* save List */
  3232. var object v = allocate_vector(n);
  3233. elements = popSTACK(); /* retrieve List */
  3234. { /* and fill it with the Elements: */
  3235. var gcv_object_t* vptr = &TheSvector(v)->data[0];
  3236. var object el; /* last Element */
  3237. var uintL index = 0;
  3238. for (;index < n; index++) {
  3239. if (index < len) { /* possibly fetch next Element */
  3240. el = Car(elements); elements = Cdr(elements);
  3241. }
  3242. *vptr++ = el;
  3243. }
  3244. }
  3245. VALUES1(v); skipSTACK(3);
  3246. }
  3247. /* (set-dispatch-macro-character #\##\A
  3248. #'(lambda (stream sub-char n)
  3249. (declare (ignore sub-char))
  3250. (if *read-suppress*
  3251. (progn (read stream t nil t) nil)
  3252. (if (null n)
  3253. (let ((h (read stream t nil t)))
  3254. (if (and (consp h) (consp (cdr h)) (consp (cddr h)) (null (cdddr h)))
  3255. (make-array (second h) :element-type (first h) :initial-contents (third h))
  3256. (error "~S: Wrong Syntax for Array: #A~S" 'read h)))
  3257. (let* ((rank n)
  3258. (cont (read stream t nil t))
  3259. (dims '())
  3260. (eltype 't))
  3261. (when (plusp rank)
  3262. (let ((subcont cont) (i 0))
  3263. (loop
  3264. (let ((l (length subcont)))
  3265. (push l dims)
  3266. (incf i) (when (>= i rank) (return))
  3267. (when (plusp l) (setq subcont (elt subcont 0)))))
  3268. (cond ((stringp subcont) (setq eltype 'character))
  3269. ((bit-vector-p subcont) (setq eltype 'bit)))))
  3270. (make-array (nreverse dims) :element-type eltype
  3271. :initial-contents cont)))))) */
  3272. LISPFUNN(array_reader,3) { /* reads #A */
  3273. var gcv_object_t* stream_ = check_stream_arg(&STACK_2);
  3274. /* stack layout: stream, sub-char, n. */
  3275. if (!nullpSv(read_suppress)) { /* *READ-SUPPRESS* /= NIL ? */
  3276. /* yes -> skip next Object: */
  3277. read_recursive_no_dot(stream_);
  3278. VALUES1(NIL); skipSTACK(3); return;
  3279. }
  3280. if (nullp(STACK_0)) { /* n not specified? */
  3281. /* yes -> read List (eltype dims contents): */
  3282. var object obj = read_recursive_no_dot(stream_); /* read List */
  3283. obj = make_references(obj); /* unentangle references */
  3284. /* (this is harmless, since we don't use this #A-Syntax
  3285. for Arrays with element-type T, and Byte-Arrays contain no references.) */
  3286. if (consp(obj)) {
  3287. var object obj2 = Cdr(obj);
  3288. if (!consp(obj2)) goto bad;
  3289. var object obj3 = Cdr(obj2);
  3290. /* type=NIL => no contents, otherwise contents is required */
  3291. if (nullp(Car(obj)) ? !nullp(obj3) : !consp(obj3) || !nullp(Cdr(obj3)))
  3292. goto bad;
  3293. if (consp(obj3)) obj3 = Car(obj3); /* contents */
  3294. /* call (MAKE-ARRAY dims :element-type eltype :initial-contents contents): */
  3295. STACK_2 = Car(obj2); STACK_1 = S(Kelement_type); STACK_0 = Car(obj);
  3296. if (nullp(STACK_0)) obj3 = unbound; /* no initial contents */
  3297. pushSTACK(S(Kinitial_contents)); pushSTACK(obj3);
  3298. goto call_make_array;
  3299. }
  3300. bad:
  3301. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3302. pushSTACK(obj); /* Object */
  3303. pushSTACK(*stream_); /* Stream */
  3304. pushSTACK(S(read));
  3305. error(reader_error,GETTEXT("~S from ~S: bad syntax for array: #A~S"));
  3306. }
  3307. /* n specifies the Rank of the Arrays.
  3308. read content: */
  3309. {
  3310. /* bind SYS::*READING-ARRAY* to T.
  3311. this allows the backquote reader functions to
  3312. distinguish #(...) vectors from #1A(...) vectors. */
  3313. dynamic_bind(S(reading_array),T);
  3314. var object contents = read_recursive_no_dot(stream_);
  3315. contents = make_references(contents); /* disentangle references */
  3316. dynamic_unbind(S(reading_array));
  3317. pushSTACK(contents); pushSTACK(contents);
  3318. }
  3319. { STACK_4 = NIL; } /* dims := '() */
  3320. /* stack layout: dims, -, rank, subcontents, contents.
  3321. determine Dimensions and Element-type: */
  3322. if (eq(STACK_2,Fixnum_0)) { /* rank=0 ? */
  3323. STACK_2 = S(t); /* yes -> eltype := 'T */
  3324. } else {
  3325. var object i = Fixnum_0; /* former nesting depth */
  3326. while (1) {
  3327. pushSTACK(STACK_1); funcall(L(length),1); /* (LENGTH subcontents) */
  3328. /* push on dims: */
  3329. STACK_3 = value1;
  3330. {
  3331. var object new_cons = allocate_cons();
  3332. Car(new_cons) = STACK_3; Cdr(new_cons) = STACK_4;
  3333. STACK_4 = new_cons;
  3334. }
  3335. /* increase depth: */
  3336. i = fixnum_inc(i,1); if (eql(i,STACK_2)) break;
  3337. /* first Element of subcontents for the following Dimensions: */
  3338. if (!eq(STACK_3,Fixnum_0)) { /* (only if (length subcontents) >0) */
  3339. pushSTACK(STACK_1); pushSTACK(Fixnum_0); funcall(L(elt),2);
  3340. STACK_1 = value1; /* subcontents := (ELT subcontents 0) */
  3341. }
  3342. }
  3343. nreverse(STACK_4); /* reverse List dims */
  3344. /* determine eltype according to innermost subcontents: */
  3345. STACK_2 = (stringp(STACK_1) ? S(character) : /* String: CHARACTER */
  3346. bit_vector_p(Atype_Bit,STACK_1) ? S(bit) : /* Bitvector: BIT */
  3347. S(t)); /* else (List): T */
  3348. }
  3349. /* stack layout: dims, -, eltype, -, contents.
  3350. call MAKE-ARRAY: */
  3351. { STACK_3 = S(Kelement_type); STACK_1 = S(Kinitial_contents); }
  3352. call_make_array:
  3353. funcall(L(make_array),5);
  3354. mv_count=1; return;
  3355. }
  3356. /* Errormessage for #. and #, because of *READ-EVAL*.
  3357. error_read_eval_forbidden(&stream,obj); english: erro_read_eval_forbidden(&stream,obj);
  3358. > stream: Stream
  3359. > obj: Object, whose Evaluation was examined */
  3360. nonreturning_function(local, error_read_eval_forbidden, (const gcv_object_t* stream_, object obj)) {
  3361. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3362. pushSTACK(obj); /* Object */
  3363. pushSTACK(NIL); /* NIL */
  3364. pushSTACK(S(read_eval)); /* *READ-EVAL* */
  3365. pushSTACK(*stream_); /* Stream */
  3366. pushSTACK(S(read));
  3367. error(reader_error, /* ANSI CL 2.4.8.6. wants a reader-error here */
  3368. GETTEXT("~S from ~S: ~S = ~S does not allow the evaluation of ~S"));
  3369. }
  3370. /* (set-dispatch-macro-character #\##\.
  3371. #'(lambda (stream sub-char n)
  3372. (declare (ignore sub-char))
  3373. (let ((h (read stream t nil t)))
  3374. (unless *read-suppress*
  3375. (if n
  3376. error_dispatch_number
  3377. (eval h)))))) */
  3378. LISPFUNN(read_eval_reader,3) { /* reads #. */
  3379. var gcv_object_t* stream_ = check_stream_arg(&STACK_2);
  3380. var object obj = read_recursive_no_dot(stream_); /* read Form */
  3381. /* if *READ-SUPPRESS* /= NIL ==> finished immediately: */
  3382. if (!nullpSv(read_suppress)) {
  3383. VALUES1(NIL); skipSTACK(3);
  3384. return;
  3385. }
  3386. if (!nullp(popSTACK())) /* n/=NIL -> Error */
  3387. error_dispatch_number();
  3388. obj = make_references(obj); /* unentangle references */
  3389. /* either *READ-EVAL* or the Stream must allow the Evaluation. */
  3390. if (nullpSv(read_eval)) {
  3391. pushSTACK(obj);
  3392. var bool allowed = stream_get_fasl(*stream_);
  3393. obj = popSTACK();
  3394. if (!allowed)
  3395. error_read_eval_forbidden(stream_,obj);
  3396. }
  3397. eval_noenv(obj); /* evaluate Form */
  3398. mv_count=1; skipSTACK(2); /* only 1 value back */
  3399. }
  3400. /* (set-dispatch-macro-character #\##\,
  3401. #'(lambda (stream sub-char n)
  3402. (declare (ignore sub-char))
  3403. (let ((h (read stream t nil t)))
  3404. (unless *read-suppress*
  3405. (if n
  3406. error_dispatch_number
  3407. (if sys::*compiling* (make-load-time-eval h) (eval h))))))) */
  3408. LISPFUNN(load_eval_reader,3) { /* reads #, */
  3409. var gcv_object_t* stream_ = check_stream_arg(&STACK_2);
  3410. var object obj = read_recursive_no_dot(stream_); /* read Form */
  3411. /* finished immediately, when *READ-SUPPRESS* /= NIL: */
  3412. if (!nullpSv(read_suppress)) {
  3413. VALUES1(NIL); skipSTACK(3);
  3414. return;
  3415. }
  3416. if (!nullp(popSTACK())) /* n/=NIL -> Error */
  3417. error_dispatch_number();
  3418. obj = make_references(obj); /* unentangle references */
  3419. if (!nullpSv(compiling)) { /* In Compiler: */
  3420. /* NB: stream may not be a FASL stream, it may be a Lisp file! */
  3421. pushSTACK(obj);
  3422. var object newobj = allocate_loadtimeeval(); /* Load-time-Eval-Object */
  3423. TheLoadtimeeval(newobj)->loadtimeeval_form = popSTACK(); /* with obj as Form */
  3424. value1 = newobj;
  3425. } else { /* In Interpreter:
  3426. either *READ-EVAL* or the Stream must allow the Evaluation. */
  3427. if (nullpSv(read_eval)) {
  3428. pushSTACK(obj);
  3429. var bool allowed = stream_get_fasl(*stream_);
  3430. obj = popSTACK();
  3431. if (!allowed)
  3432. error_read_eval_forbidden(stream_,obj);
  3433. }
  3434. eval_noenv(obj); /* evaluate Form */
  3435. }
  3436. mv_count=1; skipSTACK(2); /* only 1 value back */
  3437. }
  3438. /* (set-dispatch-macro-character #\##\=
  3439. #'(lambda (stream sub-char n)
  3440. (if *read-suppress*
  3441. (if n
  3442. (let ((h (assoc n sys::*read-reference-table* :test #'read-label-equal)))
  3443. (if (consp h)
  3444. (error "~S of ~S: Label #~S= must not be defined twice." 'read stream n)
  3445. (let ((label (make-read-label n)))
  3446. (push (setq h (cons label label)) sys::*read-reference-table*)
  3447. (let ((obj (read stream t nil t)))
  3448. (if (equal obj label)
  3449. (error "~S of ~S: #~S= #~S#is not allowed." 'read stream n n)
  3450. (setf (cdr h) obj))))))
  3451. (error "~S of ~S: Between #and = a number must be specified." 'read stream))
  3452. (values)))) ; no values (comment)
  3453. (set-dispatch-macro-character #\##\#
  3454. #'(lambda (stream sub-char n)
  3455. (unless *read-suppress*
  3456. (if n
  3457. (let ((h (assoc n sys::*read-reference-table* :test #'read-label-equal)))
  3458. (if (consp h)
  3459. (car h) ; the label, will be disentangled later
  3460. ; (you could also return (cdr h) )
  3461. (error "~S of ~S: Label #~S= is not defined." 'read stream n)))
  3462. (error "~S of ~S: Between #and #a number must be specified."
  3463. 'read stream)))))
  3464. UP: creates an internal Label and looks it up in *READ-REFERENCE-TABLE*.
  3465. lookup_label()
  3466. > stack layout: Stream, sub-char, n.
  3467. < result: (or (assoc n sys::*read-reference-table* :test #'read-label-equal) label)
  3468. can trigger GC */
  3469. local maygc object lookup_label (void) {
  3470. var object n = STACK_0;
  3471. if (nullp(n)) { /* not specified? */
  3472. pushSTACK(STACK_2); /* STREAM-ERROR slot STREAM */
  3473. pushSTACK(STACK_(1+1)); /* sub-char */
  3474. pushSTACK(STACK_(2+2)); /* Stream */
  3475. pushSTACK(S(read));
  3476. error(reader_error,
  3477. GETTEXT("~S from ~S: a number must be given between #"" and ~C"));
  3478. }
  3479. /* n is an Integer >=0. */
  3480. var object alist = /* value of SYS::*READ-REFERENCE-TABLE* */
  3481. check_read_reference_table();
  3482. /* Execute (assoc n alist :test #'read-label-equal): */
  3483. var bool smallp = small_read_label_integer_p(n);
  3484. var object label = (smallp ? make_small_read_label(posfixnum_to_V(n)) : nullobj);
  3485. while (consp(alist)) {
  3486. var object acons = Car(alist); /* List-element */
  3487. if (!consp(acons)) goto bad_reftab; /* must be a Cons ! */
  3488. var object key = Car(acons); /* its CAR is a read-label */
  3489. if (smallp
  3490. ? eq(key,label) /* is it = <READ-LABEL n> ? */
  3491. : big_read_label_p(key) && eql(TheBigReadLabel(key)->brl_value,n))
  3492. return acons; /* yes -> done */
  3493. alist = Cdr(alist);
  3494. }
  3495. if (nullp(alist)) { /* List-end with NIL ? */
  3496. /* yes -> (assoc ...) = NIL -> create read-label with number n: */
  3497. if (smallp)
  3498. return label;
  3499. else {
  3500. /* This is the extremely rare case that n is so large that a BigReadLabel
  3501. is needed. */
  3502. label = allocate_big_read_label();
  3503. TheBigReadLabel(label)->brl_value = STACK_0;
  3504. return label;
  3505. }
  3506. }
  3507. bad_reftab: /* value of SYS::*READ-REFERENCE-TABLE* is no Alist */
  3508. error_invalid_value(S(read_reference_table));
  3509. }
  3510. LISPFUNN(label_definition_reader,3) { /* reads #= */
  3511. /* when *READ-SUPPRESS* /= NIL, #n= is treated as comment: */
  3512. if (!nullpSv(read_suppress)) {
  3513. VALUES0; skipSTACK(3);
  3514. return;
  3515. }
  3516. /* Create label and lookup in table: */
  3517. var object lookup = lookup_label();
  3518. if (consp(lookup)) {
  3519. /* Found -> has already been there -> error: */
  3520. pushSTACK(STACK_2); /* STREAM-ERROR slot STREAM */
  3521. pushSTACK(STACK_(0+1)); /* n */
  3522. pushSTACK(STACK_(2+2)); /* Stream */
  3523. pushSTACK(S(read));
  3524. error(reader_error,
  3525. GETTEXT("~S from ~S: label #~S= may not be defined twice"));
  3526. } else {
  3527. /* lookup = label. */
  3528. pushSTACK(lookup);
  3529. /* Stack layout: stream, sub-char, n, label.
  3530. (push (setq h (cons label label)) sys::*read-reference-table*) : */
  3531. var gcv_object_t* stream_ = check_stream_arg(&STACK_3);
  3532. {
  3533. var object new_cons = allocate_cons();
  3534. Car(new_cons) = Cdr(new_cons) = STACK_0; /* h = (cons label label) */
  3535. pushSTACK(new_cons); /* save h */
  3536. }
  3537. /* Stack layout: stream, sub-char, n, label, h. */
  3538. {
  3539. var object new_cons = allocate_cons(); /* new List-Cons */
  3540. Car(new_cons) = STACK_0;
  3541. Cdr(new_cons) = Symbol_value(S(read_reference_table));
  3542. Symbol_value(S(read_reference_table)) = new_cons;
  3543. }
  3544. var object obj = read_recursive_no_dot(stream_); /* read an object */
  3545. if (eq(obj,STACK_1)) { /* read object = label ? */
  3546. /* yes -> cyclic Definition -> Error */
  3547. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3548. pushSTACK(STACK_(2+1)); /* n */
  3549. pushSTACK(STACK_(2+2)); /* n */
  3550. pushSTACK(*stream_); /* Stream */
  3551. pushSTACK(S(read));
  3552. error(reader_error,GETTEXT("~S from ~S: #~S= #~S#"" is illegal"));
  3553. }
  3554. /* Insert read object as (cdr h): */
  3555. Cdr(STACK_0) = obj;
  3556. VALUES1(obj); skipSTACK(5);
  3557. }
  3558. }
  3559. LISPFUNN(label_reference_reader,3) { /* reads ##*/
  3560. /* when *READ-SUPPRESS* /= NIL, finished immediately: */
  3561. if (!nullpSv(read_suppress)) {
  3562. VALUES1(NIL); skipSTACK(3);
  3563. return;
  3564. }
  3565. /* Lookup in table: */
  3566. var object lookup = lookup_label();
  3567. if (consp(lookup)) {
  3568. /* Found -> return label as read object: */
  3569. VALUES1(Car(lookup)); skipSTACK(3);
  3570. } else { /* not found */
  3571. pushSTACK(STACK_2); /* STREAM-ERROR slot STREAM */
  3572. pushSTACK(STACK_(0+1)); /* n */
  3573. pushSTACK(STACK_(2+2)); /* Stream */
  3574. pushSTACK(S(read));
  3575. error(reader_error,GETTEXT("~S from ~S: undefined label #~S#"));
  3576. }
  3577. }
  3578. /* (set-dispatch-macro-character #\##\<
  3579. #'(lambda (stream sub-char n)
  3580. (error "~S of ~S: Objects printed as #<...> cannot be reread again."
  3581. 'read stream))) */
  3582. LISPFUNN(not_readable_reader,3) { /* reads #< */
  3583. var gcv_object_t* stream_ = check_stream_arg(&STACK_2);
  3584. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3585. pushSTACK(*stream_); /* Stream */
  3586. pushSTACK(S(read));
  3587. error(reader_error, /* ANSI CL 2.4.8.20. wants a reader-error here */
  3588. GETTEXT("~S from ~S: objects printed as #<...> cannot be read back in"));
  3589. }
  3590. /* (dolist (ch '(#\) #\Space #\Newline #\Linefeed #\Backspace #\Rubout #\Tab #\Return #\Page))
  3591. (set-dispatch-macro-character #\#ch
  3592. #'(lambda (stream sub-char n)
  3593. (error "~S of ~S: Because of ~S as #printed Objects cannot be reread."
  3594. 'read stream '*print-level*)))) */
  3595. LISPFUNN(syntax_error_reader,3) { /* reads #) and #whitespace */
  3596. var gcv_object_t* stream_ = check_stream_arg(&STACK_2);
  3597. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3598. pushSTACK(S(print_level));
  3599. pushSTACK(*stream_); /* Stream */
  3600. pushSTACK(S(read));
  3601. error(reader_error, /* ANSI CL 2.4.9. wants a reader-error here */
  3602. GETTEXT("~S from ~S: objects printed as #"" in view of ~S cannot be read back in"));
  3603. }
  3604. /* Auxiliary function for #+ and #- :
  3605. (defun interpret-feature (feature)
  3606. (flet ((eqs (x y) (and (symbolp x) (symbolp y)
  3607. (string= (symbol-name x) (symbol-name y)))))
  3608. (cond ((symbolp feature) (member feature *features* :test #'eq))
  3609. ((atom feature)
  3610. (error "~S: As feature ~S is not allowed." 'read feature))
  3611. ((eqs (car feature) 'and)
  3612. (every #'interpret-feature (cdr feature)))
  3613. ((eqs (car feature) 'or)
  3614. (some #'interpret-feature (cdr feature)))
  3615. ((eqs (car feature) 'not)
  3616. (not (interpret-feature (second feature))))
  3617. (t (error "~S: As feature ~S is not allowed." 'read feature)))))
  3618. UP: checks, if Feature-Expression is satisfied.
  3619. interpret_feature(expr)
  3620. > expr: a Feature-Expresion
  3621. > STACK_1: Stream or unbound
  3622. < result: truth value: 0 if satisfied, ~0 if not. */
  3623. nonreturning_function(local, error_feature, (object expr)) {
  3624. /* Wrong structure of feature expression. */
  3625. if (boundp(STACK_1)) { /* Called from READ. */
  3626. pushSTACK(STACK_1); /* STREAM-ERROR slot STREAM */
  3627. pushSTACK(expr); /* Feature-Expression */
  3628. pushSTACK(STACK_(1+2)); /* Stream */
  3629. pushSTACK(S(read));
  3630. error(reader_error,GETTEXT("~S from ~S: illegal feature ~S"));
  3631. } else { /* Called from FEATUREP. */
  3632. pushSTACK(expr); /* Feature-Expression */
  3633. pushSTACK(TheSubr(subr_self)->name);
  3634. error(error_condition,GETTEXT("~S: illegal feature ~S"));
  3635. }
  3636. }
  3637. local uintWL interpret_feature (object expr);
  3638. local uintWL interpret_features (uintWL and_or_flag, object expr) {
  3639. var object list = Cdr(expr);
  3640. while (consp(list)) { /* interpret one List-element: */
  3641. var uintWL sub_ret = interpret_feature(Car(list));
  3642. if (sub_ret != and_or_flag)
  3643. return sub_ret;
  3644. list = Cdr(list);
  3645. }
  3646. if (nullp(list))
  3647. return and_or_flag;
  3648. error_feature(expr);
  3649. }
  3650. local uintWL interpret_feature (object expr) {
  3651. check_SP();
  3652. if (symbolp(expr)) { /* expr Symbol, search in *FEATURES*: */
  3653. if (nullp(memq(expr,Symbol_value(S(features))))) return ~0; /* no */
  3654. else return 0; /* yes */
  3655. } else if (consp(expr) && symbolp(Car(expr))) {
  3656. var object opname = Symbol_name(Car(expr));
  3657. var uintWL and_or_flag;
  3658. if (string_eq(opname,Symbol_name(S(and)))) /* expr = (AND ...) */
  3659. return interpret_features(0,expr);
  3660. if (string_eq(opname,Symbol_name(S(or)))) /* expr = (OR ...) */
  3661. return interpret_features(~0,expr);
  3662. if (string_eq(opname,Symbol_name(S(not)))) {
  3663. /* expr = (NOT ...) is to be of the shape (NOT obj): */
  3664. var object opargs = Cdr(expr);
  3665. if (consp(opargs) && nullp(Cdr(opargs)))
  3666. return ~interpret_feature(Car(opargs));
  3667. }
  3668. }
  3669. /* expr has an incorrect shape -> error */
  3670. error_feature(expr);
  3671. }
  3672. /* run-time version of #+
  3673. <http://clrfi.alu.org/clrfi/clrfi-1-featurep> */
  3674. LISPFUNNR(featurep,1) {
  3675. pushSTACK(STACK_0); /* interpret_feature checks STACK_1 */
  3676. STACK_1 = unbound;
  3677. VALUES_IF(!interpret_feature(STACK_0));
  3678. skipSTACK(2);
  3679. }
  3680. /* UP: for #+ und #-
  3681. feature(demandvalue)
  3682. > expected value: exprected truth value of Feature-Expression
  3683. > Stack Structure: Stream, sub-char, n.
  3684. < STACK: increased by 3
  3685. < mv_space/mv_count: values
  3686. can trigger GC */
  3687. local maygc Values feature (uintWL demandvalue) {
  3688. var gcv_object_t* stream_ = test_no_infix(); /* n must be NIL */
  3689. dynamic_bind(S(read_suppress),NIL); /* bind *READ-SUPPRESS* to NIL */
  3690. dynamic_bind(S(packagestern),O(keyword_package)); /* bind *PACKAGE* to #<PACKAGE KEYWORD> */
  3691. var object expr = read_recursive_no_dot(stream_); /* read Feature-Expression */
  3692. dynamic_unbind(S(packagestern));
  3693. dynamic_unbind(S(read_suppress));
  3694. /* interpret Feature-Expression: */
  3695. expr = make_references(expr); /* first unentangle references */
  3696. if (interpret_feature(expr) == demandvalue) { /* truth value "true" */
  3697. /* read next Object and set for value: */
  3698. VALUES1(read_recursive_no_dot(stream_));
  3699. } else { /* truth value "false" */
  3700. /* bind *READ-SUPPRESS* to T, read Object, comment */
  3701. dynamic_bind(S(read_suppress),T);
  3702. read_recursive_no_dot(stream_);
  3703. dynamic_unbind(S(read_suppress));
  3704. VALUES0;
  3705. }
  3706. skipSTACK(2);
  3707. }
  3708. /* (set-dispatch-macro-character #\##\+
  3709. #'(lambda (stream sub-char n)
  3710. (declare (ignore sub-char))
  3711. (if n
  3712. (error "~S of ~S: Between #and + no number is allowed." 'read stream)
  3713. (let ((feature (let ((*read-suppress* nil)) (read stream t nil t))))
  3714. (if (interpret-feature feature)
  3715. (read stream t nil t)
  3716. (let ((*read-suppress* t))
  3717. (read stream t nil t)
  3718. (values))))))) */
  3719. LISPFUNN(feature_reader,3) { /* reads #+ */
  3720. return_Values feature(0);
  3721. }
  3722. /* (set-dispatch-macro-character #\##\-
  3723. #'(lambda (stream sub-char n)
  3724. (declare (ignore sub-char))
  3725. (if n
  3726. (error "~S of ~S: Between #and - no number is allowed." 'read stream)
  3727. (let ((feature (let ((*read-suppress* nil)) (read stream t nil t))))
  3728. (if (interpret-feature feature)
  3729. (let ((*read-suppress* t))
  3730. (read stream t nil t)
  3731. (values))
  3732. (read stream t nil t)))))) */
  3733. LISPFUNN(not_feature_reader,3) { /* reads #- */
  3734. return_Values feature(~0);
  3735. }
  3736. /* (set-dispatch-macro-character #\##\S
  3737. #'(lambda (stream char n)
  3738. (declare (ignore char))
  3739. (if *read-suppress*
  3740. (progn (read stream t nil t) nil)
  3741. (if n
  3742. (error "~S: Between #and S no number is allowed." 'read)
  3743. (let ((args (read stream t nil t)))
  3744. (if (consp args)
  3745. (let ((name (first args)))
  3746. (if (symbolp name)
  3747. (let ((class (get name 'CLOS::CLOSCLASS)))
  3748. (if (typep class clos::<structure-class>)
  3749. (if (clos::class-kconstructor class)
  3750. (values
  3751. (apply (clos::class-kconstructor class)
  3752. (structure-arglist-expand name (cdr args))))
  3753. (error "~S: Structures of type ~S cannot be read (constructor function unknown)"
  3754. 'read name))
  3755. ; Support #S syntax also for defstruct types of :type
  3756. ; VECTOR or LIST. A CLISP extension.
  3757. (let ((desc (get name 'DEFSTRUCT-DESCRIPTION)))
  3758. (if desc
  3759. (if (svref desc 2)
  3760. (values
  3761. (apply (svref desc 2)
  3762. (structure-arglist-expand name (cdr args))))
  3763. (error "~S: Structures of type ~S cannot be read (constructor function unknown)"
  3764. 'read name))
  3765. (error "~S: No structure of type ~S has been defined"
  3766. 'read name)))))
  3767. (error "~S: The type of a structure must be a symbol, not ~S"
  3768. 'read name)))
  3769. (error "~S: Behind #S the Type and the contents of the Structure must follow in parenthesis, not ~S"
  3770. 'read args)))))))
  3771. (defun structure-arglist-expand (name args)
  3772. (cond ((null args) nil)
  3773. ((atom args) (error "~S: A structure ~S must not contain a component . " 'read name))
  3774. ((not (symbolp (car args)))
  3775. (error "~S: ~S is no symbol and thus no slot of the structure ~S" 'read (car args) name))
  3776. ((null (cdr args)) (error "~S: Value of the component ~S in structure ~S is missing" 'read (car args) name))
  3777. ((atom (cdr args)) (error "~S: A structure ~S must not contain a component . " 'read name))
  3778. (t (let ((kw (intern (symbol-name (car args)) (find-package "KEYWORD"))))
  3779. (list* kw (cadr args) (structure-arglist-expand name (cddr args))))))) */
  3780. LISPFUNN(structure_reader,3) { /* reads #S */
  3781. var gcv_object_t* stream_ = test_no_infix(); /* n must be NIL */
  3782. /* when *READ-SUPPRESS* /= NIL, only read one object: */
  3783. if (!nullpSv(read_suppress)) {
  3784. read_recursive_no_dot(stream_); /* read Object and throw away, */
  3785. VALUES1(NIL); skipSTACK(2); return;
  3786. }
  3787. /* bind SYS::*READING-STRUCT* to T and read object: */
  3788. dynamic_bind(S(reading_struct),T);
  3789. var object args = read_recursive_no_dot(stream_);
  3790. dynamic_unbind(S(reading_struct));
  3791. /* check read List: */
  3792. if (atomp(args)) {
  3793. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3794. pushSTACK(args); /* Arguments */
  3795. pushSTACK(*stream_); /* Stream */
  3796. pushSTACK(S(read));
  3797. error(reader_error,GETTEXT("~S from ~S: #S must be followed by the type and the contents of the structure, not ~S"));
  3798. }
  3799. {
  3800. var object name = Car(args); /* Type of Structure */
  3801. STACK_0 = args = Cdr(args); /* save Restlist */
  3802. /* Stack Structure: Stream, remaining Args. */
  3803. if (!symbolp(name)) { /* Type must be a Symbol ! */
  3804. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3805. pushSTACK(name);
  3806. pushSTACK(*stream_); /* Stream */
  3807. pushSTACK(S(read));
  3808. error(reader_error,GETTEXT("~S from ~S: the type of a structure should be a symbol, not ~S"));
  3809. }
  3810. pushSTACK(name);
  3811. /* Stack Structure: Stream, remaining Args, name. */
  3812. if (eq(name,S(hash_table))) { /* Symbol HASH-TABLE ? */
  3813. /* yes -> treat specially, no Structure:
  3814. Hash-Tabelle
  3815. Remaining Argumentlist must be a Cons: */
  3816. if (!consp(args)) {
  3817. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3818. pushSTACK(S(hash_table)); pushSTACK(*stream_); pushSTACK(S(read));
  3819. error(reader_error,GETTEXT("~S from ~S: bad ~S"));
  3820. }
  3821. if (symbolp(Car(args)) && keywordp(Car(args))) {
  3822. /* New syntax with implicit :INITIAL-CONTENTS keyword: */
  3823. var uintL argcount = 2;
  3824. while (consp(args) && symbolp(Car(args)) && mconsp(Cdr(args))) {
  3825. get_space_on_STACK(2);
  3826. pushSTACK(Car(args));
  3827. args = Cdr(args);
  3828. pushSTACK(Car(args));
  3829. args = Cdr(args);
  3830. argcount += 2;
  3831. }
  3832. pushSTACK(S(Kinitial_contents)); /* :INITIAL-CONTENTS */
  3833. pushSTACK(args); /* Alist ((Key_1 . Value_1) ... (Key_n . Value_n)) */
  3834. funcall(L(make_hash_table),argcount); /* build Hash-Table */
  3835. } else {
  3836. /* Old syntax with implicit :TEST and :INITIAL-CONTENTS keywords:
  3837. (MAKE-HASH-TABLE :TEST (car args) :INITIAL-CONTENTS (cdr args)) */
  3838. pushSTACK(S(Ktest)); /* :TEST */
  3839. pushSTACK(Car(args)); /* Test (Symbol) */
  3840. pushSTACK(S(Kinitial_contents)); /* :INITIAL-CONTENTS */
  3841. pushSTACK(Cdr(args)); /* Alist ((Key_1 . Value_1) ... (Key_n . Value_n)) */
  3842. funcall(L(make_hash_table),4); /* build Hash-Table */
  3843. }
  3844. mv_count=1; /* value1 as value */
  3845. skipSTACK(3); return;
  3846. }
  3847. if (eq(name,S(random_state))) { /* Symbol RANDOM-STATE ? */
  3848. /* yes -> treat specially, no Structure:
  3849. Random-State
  3850. Remaining Argumentlist must be a Cons with NIL as CDR and
  3851. a Simple-Bit-Vector of length 64 as CAR: */
  3852. if (!(consp(args)
  3853. && nullp(Cdr(args))
  3854. && simple_bit_vector_p(Atype_Bit,Car(args))
  3855. && (Sbvector_length(Car(args)) == 64))) {
  3856. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3857. pushSTACK(name);
  3858. pushSTACK(*stream_); /* Stream */
  3859. pushSTACK(S(read));
  3860. error(reader_error,GETTEXT("~S from ~S: bad ~S"));
  3861. }
  3862. STACK_0 = Car(args); /* save Simple-Bit-Vector */
  3863. var object result = allocate_random_state(); /* new Random-State */
  3864. The_Random_state(result)->random_state_seed = popSTACK(); /* fill */
  3865. VALUES1(result); skipSTACK(2); return;
  3866. }
  3867. if (eq(name,S(pathname))) { /* Symbol PATHNAME ? */
  3868. /* yes -> treat specially, no Structure: */
  3869. STACK_1 = make_references(args); pushSTACK(L(make_pathname));
  3870. }
  3871. #ifdef LOGICAL_PATHNAMES
  3872. else if (eq(name,S(logical_pathname))) { /* Symbol LOGICAL-PATHNAME ? */
  3873. /* yes -> treat specially, no Structure: */
  3874. STACK_1 = make_references(args); pushSTACK(L(make_logical_pathname));
  3875. }
  3876. #endif
  3877. else if (eq(name,S(byte))) { /* Symbol BYTE ? */
  3878. /* yes -> treat specially, no Structure: */
  3879. pushSTACK(S(make_byte));
  3880. }
  3881. else {
  3882. var object constructor;
  3883. { /* execute (GET name 'CLOS::CLOSCLASS): */
  3884. var object clas = get(name,S(closclass));
  3885. if (boundp(clas)) {
  3886. /* clas must be a <structure-class> instance: */
  3887. if_defined_class_p(clas, {
  3888. if (srecord_length(TheClass(clas)) > built_in_class_length)
  3889. if (mconsp(TheClass(clas)->current_version)) {
  3890. /* fetch constructor-function: */
  3891. constructor = /* (clos::class-kconstructor class) */
  3892. (&TheClass(clas)->current_version)[1];
  3893. goto found_constructor;
  3894. }
  3895. }, ; );
  3896. }
  3897. }
  3898. { /* execute (GET name 'SYS::DEFSTRUCT-DESCRIPTION): */
  3899. var object description = get(name,S(defstruct_description));
  3900. if (boundp(description)) {
  3901. /* description must be a Simple-Vector of length 8: */
  3902. if (simple_vector_p(description)
  3903. && (Svector_length(description) == 8)) {
  3904. /* fetch constructor-function: */
  3905. constructor = /* (svref description 2) */
  3906. TheSvector(description)->data[2];
  3907. goto found_constructor;
  3908. } else {
  3909. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3910. pushSTACK(name);
  3911. pushSTACK(S(defstruct_description));
  3912. pushSTACK(*stream_); /* Stream */
  3913. pushSTACK(S(read));
  3914. error(reader_error,GETTEXT("~S from ~S: bad ~S for ~S"));
  3915. }
  3916. }
  3917. }
  3918. { /* Structure of this Type undefined */
  3919. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3920. pushSTACK(name);
  3921. pushSTACK(*stream_); /* Stream */
  3922. pushSTACK(S(read));
  3923. error(reader_error,
  3924. GETTEXT("~S from ~S: no structure of type ~S has been defined"));
  3925. }
  3926. found_constructor:
  3927. if (nullp(constructor)) {
  3928. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3929. pushSTACK(name);
  3930. pushSTACK(*stream_); /* Stream */
  3931. pushSTACK(S(read));
  3932. error(reader_error,
  3933. GETTEXT("~S from ~S: structures of type ~S cannot be read in, missing constructor function"));
  3934. }
  3935. /* call constructor-function with adapted Argumentlist: */
  3936. pushSTACK(constructor);
  3937. }
  3938. }
  3939. /* stack layout: Stream, remaining Args, name, constructor. */
  3940. var uintC argcount = 0; /* number of arguments for constructor */
  3941. while (1) { /* process remaining Argumentlist, */
  3942. /* push Arguments for constructor on STACK: */
  3943. check_STACK();
  3944. args = *(stream_ STACKop -1); /* remaining Args */
  3945. if (nullp(args)) /* no more -> Arguments in STACK are ready */
  3946. break;
  3947. if (atomp(args)) {
  3948. dotted:
  3949. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3950. pushSTACK(*(stream_ STACKop -2)); /* name */
  3951. pushSTACK(*stream_); /* Stream */
  3952. pushSTACK(S(read));
  3953. error(reader_error,
  3954. GETTEXT("~S from ~S: a structure ~S may not contain a component \".\""));
  3955. }
  3956. {
  3957. var object slot = Car(args);
  3958. if (!(symbolp(slot) || stringp(slot) || charp(slot))) {
  3959. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3960. pushSTACK(*(stream_ STACKop -2)); /* name */
  3961. pushSTACK(slot);
  3962. pushSTACK(*stream_); /* Stream */
  3963. pushSTACK(S(read));
  3964. error(reader_error,
  3965. GETTEXT("~S from ~S: ~S is not a symbol, not a slot name of structure ~S"));
  3966. }
  3967. if (nullp(Cdr(args))) {
  3968. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3969. pushSTACK(*(stream_ STACKop -2)); /* name */
  3970. pushSTACK(slot);
  3971. pushSTACK(*stream_); /* Stream */
  3972. pushSTACK(S(read));
  3973. error(reader_error,
  3974. GETTEXT("~S from ~S: missing value of slot ~S in structure ~S"));
  3975. }
  3976. if (matomp(Cdr(args)))
  3977. goto dotted;
  3978. slot = test_stringsymchar_arg(slot,false); /* Slotname as string */
  3979. var object kw = intern_keyword(slot); /* Slotname as Keyword */
  3980. pushSTACK(kw); /* Keyword into STACK */
  3981. }
  3982. args = *(stream_ STACKop -1); /* again the same remaining Args */
  3983. args = Cdr(args);
  3984. pushSTACK(Car(args)); /* Slot-value into STACK */
  3985. *(stream_ STACKop -1) = Cdr(args); /* shorten Arglist */
  3986. argcount += 2; /* and count */
  3987. if (argcount == 0) {
  3988. /* Argument-Counter has become too big */
  3989. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  3990. pushSTACK(*(stream_ STACKop -2)); /* name */
  3991. pushSTACK(*stream_); /* Stream */
  3992. pushSTACK(S(read));
  3993. error(reader_error,GETTEXT("~S from ~S: too many slots for structure ~S"));
  3994. }
  3995. }
  3996. funcall(*(stream_ STACKop -3),argcount); /* call constructor */
  3997. mv_count=1; skipSTACK(4); return; /* value1 as value */
  3998. }
  3999. /* (set-dispatch-macro-character #\##\Y
  4000. #'(lambda (stream sub-char arg)
  4001. (declare (ignore sub-char))
  4002. (if arg
  4003. (if (eql arg 0)
  4004. ; Encoding lesen
  4005. (let ((obj
  4006. (let ((*read-suppress* nil)
  4007. (*package* (find-package "CHARSET")))
  4008. (read stream t nil t))))
  4009. (setf (stream-external-format stream) obj)
  4010. (values))
  4011. ; Codevector lesen
  4012. (let ((obj (let ((*read-base* 16.)) (read stream t nil t))))
  4013. (unless *read-suppress*
  4014. (unless (= (length obj) arg)
  4015. (error "Wrong length of a Closure-Vector: ~S" arg))
  4016. (make-code-vector obj) ; Simple-Bit-Vector, Content: arg Bytes)))
  4017. ; read Closure
  4018. (let ((obj (read stream t nil t)))
  4019. (unless *read-suppress*
  4020. (%make-closure (first obj) (second obj) (cddr obj)))))))
  4021. error-message because of wrong Syntax of a Code-Vector
  4022. error_closure_badchar();
  4023. > stack layout: stream, sub-char, arg. */
  4024. nonreturning_function(local, error_closure_badchar, (void)) {
  4025. pushSTACK(STACK_2); /* STREAM-ERROR slot STREAM */
  4026. pushSTACK(STACK_(0+1)); /* n */
  4027. pushSTACK(STACK_(2+2)); /* Stream */
  4028. pushSTACK(S(read));
  4029. error(reader_error,GETTEXT("~S from ~S: illegal syntax of closure code vector after #~SY"));
  4030. }
  4031. /* UP: checks, if Character ch with Syntaxcode scode is a
  4032. Hexadecimal-Digit, and delivers its value.
  4033. hexziffer(ch,scode) english: hexdigit(ch,scode)
  4034. > ch, scode: Character (or eof_value) and its Syntaxcode
  4035. > stack layout: stream, sub-char, arg.
  4036. < Result: value (>=0, <16) of Hexdigit */
  4037. local uintB hexziffer (object ch, uintWL scode) {
  4038. if (scode == syntax_eof)
  4039. error_eof_inside(&STACK_2);
  4040. /* ch is a Character */
  4041. var cint c = as_cint(char_code(ch));
  4042. if (c<'0') goto badchar; if (c<='9') { return (c-'0'); } /* '0'..'9' */
  4043. if (c<'A') goto badchar; if (c<='F') { return (c-'A'+10); } /* 'A'..'F' */
  4044. if (c<'a') goto badchar; if (c<='f') { return (c-'a'+10); } /* 'a'..'f' */
  4045. badchar: error_closure_badchar();
  4046. }
  4047. LISPFUNN(closure_reader,3) { /* read #Y */
  4048. var gcv_object_t* stream_ = check_stream_arg(&STACK_2);
  4049. /* when n=0 read an Encoding: */
  4050. if (eq(STACK_0,Fixnum_0)) {
  4051. var object ch = read_char(stream_);
  4052. if (eq(ch,eof_value)) { error_eof(stream_); } /* EOF -> Error */
  4053. if (eq(ch,ascii_char('_'))) { /* FASL stream */
  4054. stream_set_fasl(*stream_,true);
  4055. } else if (eq(ch,ascii_char('^'))) { /* non-FASL stream */
  4056. stream_set_fasl(*stream_,false);
  4057. } else {
  4058. unread_char(stream_,ch);
  4059. dynamic_bind(S(read_suppress),NIL); /* bind *READ-SUPPRESS* to NIL */
  4060. dynamic_bind(S(packagestern),O(charset_package)); /* bind *PACKAGE* to #<PACKAGE CHARSET> */
  4061. var object expr = read_recursive_no_dot(stream_); /* read expression */
  4062. dynamic_unbind(S(packagestern));
  4063. dynamic_unbind(S(read_suppress));
  4064. expr = make_references(expr); /* unentangle references */
  4065. pushSTACK(*stream_); pushSTACK(expr); pushSTACK(S(Kinput));
  4066. funcall(L(set_stream_external_format),3); /* (SYS::SET-STREAM-EXTERNAL-FORMAT stream expr :input) */
  4067. }
  4068. VALUES0; skipSTACK(3); return;
  4069. }
  4070. /* when *READ-SUPPRESS* /= NIL, only read one Object: */
  4071. if (!nullpSv(read_suppress)) {
  4072. read_recursive_no_dot(stream_); /* read Object, and throw away */
  4073. VALUES1(NIL); skipSTACK(3); return;
  4074. }
  4075. /* according to n : */
  4076. if (nullp(STACK_0)) {
  4077. /* n=NIL -> read Closure: */
  4078. var object obj = read_recursive_no_dot(stream_); /* read Object */
  4079. if (!(consp(obj) && mconsp(Cdr(obj)))) { /* length >=2 ? */
  4080. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  4081. pushSTACK(obj);
  4082. pushSTACK(*stream_); /* Stream */
  4083. pushSTACK(S(read));
  4084. error(reader_error,
  4085. GETTEXT("~S from ~S: object #Y~S has not the syntax of a compiled closure"));
  4086. }
  4087. skipSTACK(3);
  4088. /* (apply (function SYS::%MAKE-CLOSURE) obj): */
  4089. pushSTACK(Car(obj)); obj = Cdr(obj); /* 1st argument (name) */
  4090. pushSTACK(Car(obj)); obj = Cdr(obj); /* 2nd argument (codevec) */
  4091. pushSTACK(Car(obj)); obj = Cdr(obj); /* 3rd argument (const list) */
  4092. pushSTACK(Car(obj)); obj = Cdr(obj); /* 4th argument (side-effect class) */
  4093. #define OPTARG if (consp(obj)) { pushSTACK(Car(obj)); obj = Cdr(obj); } else pushSTACK(Fixnum_0)
  4094. OPTARG; /* 5th argument (lambda-list) */
  4095. OPTARG; /* 6th argument (documentation) */
  4096. OPTARG; /* 7th argument (jitc_p) */
  4097. #undef OPTARG
  4098. C_make_closure(); /* value1 as value */
  4099. } else {
  4100. /* n specified -> read Codevector:
  4101. Syntax: #nY(b1 ... bn), where n is a Fixnum >=0 and b1,...,bn
  4102. are Fixnums >=0, <256 in Base 16 (with one or two digits).
  4103. e.g. #9Y(0 4 F CD 6B8FD1e4 5)
  4104. n is an Integer >=0. */
  4105. var uintV n =
  4106. (posfixnump(STACK_0) ? posfixnum_to_V(STACK_0) /* Fixnum -> value */
  4107. : vbitm(oint_data_len)-1); /* Bignum -> big value */
  4108. #if (intVsize>intLsize)
  4109. if (n >= vbit(intLsize)) {
  4110. /* STACK_0 = n, TYPE-ERROR slot DATUM */
  4111. pushSTACK(O(type_array_length)); /* TYPE-ERROR slot EXPECTED-TYPE */
  4112. pushSTACK(STACK_1); /* n */
  4113. pushSTACK(*stream_); /* Stream */
  4114. pushSTACK(S(read));
  4115. error(type_error,GETTEXT("~S from ~S: invalid code vector length ~S"));
  4116. }
  4117. #endif
  4118. /* get new Bit-Vector with n Bytes: */
  4119. STACK_1 = allocate_bit_vector(Atype_8Bit,n);
  4120. /* stack layout: Stream, Codevektor, n. */
  4121. var object ch;
  4122. var uintWL scode;
  4123. /* skip Whitespace: */
  4124. do { read_char_syntax(ch = ,scode = ,stream_); /* read character */
  4125. } while (scode == syntax_whitespace);
  4126. /* '(' must follow: */
  4127. if (!eq(ch,ascii_char('(')))
  4128. error_closure_badchar();
  4129. {
  4130. var uintL index = 0;
  4131. for (; index < n; index++) {
  4132. /* skip Whitespace: */
  4133. do { read_char_syntax(ch = ,scode = ,stream_); /* read character */
  4134. } while (scode == syntax_whitespace);
  4135. /* Hex-digit must follow: */
  4136. var uintB zif = hexziffer(ch,scode);
  4137. /* read next Character: */
  4138. read_char_syntax(ch = ,scode = ,stream_);
  4139. if (scode == syntax_eof) /* EOF -> Error */
  4140. error_eof_inside(stream_);
  4141. if ((scode == syntax_whitespace) || eq(ch,ascii_char(')'))) {
  4142. /* Whitespace or closing parenthese
  4143. will be pushed back to Stream: */
  4144. unread_char(stream_,ch);
  4145. } else {
  4146. /* it must be a second Hex-digit */
  4147. zif = 16*zif + hexziffer(ch,scode); /* add to first Hex-digit */
  4148. /* (no whitespace is demanded after the second Hex-digit.) */
  4149. }
  4150. /* zif = read Byte. write into Codevector: */
  4151. TheSbvector(STACK_1)->data[index] = zif;
  4152. }
  4153. }
  4154. /* skip Whitespace: */
  4155. do { read_char_syntax(ch = ,scode = ,stream_); /* read character */
  4156. } while (scode == syntax_whitespace);
  4157. /* ')' must follow: */
  4158. if (!eq(ch,ascii_char(')')))
  4159. error_closure_badchar();
  4160. #if BIG_ENDIAN_P
  4161. { /* convert Header from Little-Endian to Big-Endian: */
  4162. var Sbvector v = TheSbvector(STACK_1);
  4163. swap(uintB, v->data[CCV_SPDEPTH_1], v->data[CCV_SPDEPTH_1+1]);
  4164. swap(uintB, v->data[CCV_SPDEPTH_JMPBUFSIZE], v->data[CCV_SPDEPTH_JMPBUFSIZE+1]);
  4165. swap(uintB, v->data[CCV_NUMREQ], v->data[CCV_NUMREQ+1]);
  4166. swap(uintB, v->data[CCV_NUMOPT], v->data[CCV_NUMOPT+1]);
  4167. if (v->data[CCV_FLAGS] & bit(7)) {
  4168. swap(uintB, v->data[CCV_NUMKEY], v->data[CCV_NUMKEY+1]);
  4169. swap(uintB, v->data[CCV_KEYCONSTS], v->data[CCV_KEYCONSTS+1]);
  4170. }
  4171. }
  4172. #endif
  4173. /* Codevector as value: */
  4174. VALUES1(STACK_1); skipSTACK(3);
  4175. }
  4176. }
  4177. /* (set-dispatch-macro-character #\##\"
  4178. #'(lambda (stream sub-char n)
  4179. (unless *read-suppress*
  4180. (if n error_dispatch_number))
  4181. (unread-char sub-char stream)
  4182. (let ((obj (read stream t nil t))) ; String read
  4183. (unless *read-suppress* (pathname obj))))) */
  4184. LISPFUNN(clisp_pathname_reader,3) { /* reads #" */
  4185. test_no_infix(); /* n must be NIL */
  4186. /* stack layout: Stream, sub-char #\". */
  4187. var object string = /* read String, that starts with " */
  4188. (funcall(L(string_reader),2),value1);
  4189. /* when *READ-SUPPRESS* /= NIL, finished immediately: */
  4190. if (!nullpSv(read_suppress)) {
  4191. VALUES1(NIL); return;
  4192. }
  4193. /* construct (pathname string) = (values (parse-namestring string)) : */
  4194. pushSTACK(string); funcall(L(parse_namestring),1); /* (PARSE-NAMESTRING string) */
  4195. mv_count=1; /* only one value */
  4196. }
  4197. /* (set-dispatch-macro-character #\##\P
  4198. (lambda (stream sub-char n)
  4199. (declare (ignore sub-char))
  4200. (if *read-suppress*
  4201. (progn (read stream t nil t) nil)
  4202. (if n
  4203. (error "~S of ~S: no infix for #P" (quote read) stream)
  4204. (let ((obj (read stream t nil t)))
  4205. (if (stringp obj)
  4206. (values (parse-namestring obj))
  4207. (if (listp obj)
  4208. (apply (function make-pathname) obj)
  4209. (error "~S of ~S: Wrong syntax for pathname: #P~S"
  4210. (quote read) stream obj)))))))) */
  4211. LISPFUNN(ansi_pathname_reader,3) { /* reads #P */
  4212. var gcv_object_t* stream_ = test_no_infix(); /* n must be NIL */
  4213. var object obj = read_recursive_no_dot(stream_); /* read next Object */
  4214. /* when *READ-SUPPRESS* /= NIL, finished immediately: */
  4215. if (!nullpSv(read_suppress)) {
  4216. VALUES1(NIL); skipSTACK(2); return;
  4217. }
  4218. obj = make_references(obj); /* and unentangle references untimely */
  4219. if (stringp(obj)) {
  4220. /* create (pathname obj) = (values (parse-namestring obj)) : */
  4221. pushSTACK(obj); funcall(L(parse_namestring),1); /* (PARSE-NAMESTRING obj) */
  4222. mv_count=1; skipSTACK(2); /* only one value */
  4223. } else if (listp(obj)) {
  4224. apply(L(make_pathname),0,obj); /* (APPLY (FUNCTION MAKE-PATHNAME) OBJ) */
  4225. mv_count=1; skipSTACK(2); /* only one value */
  4226. } else {
  4227. pushSTACK(*stream_); /* STREAM-ERROR slot STREAM */
  4228. pushSTACK(obj); /* Object */
  4229. pushSTACK(*stream_); /* Stream */
  4230. pushSTACK(S(read));
  4231. error(reader_error,GETTEXT("~S from ~S: bad syntax for pathname: #P~S"));
  4232. }
  4233. }
  4234. #if defined(UNIX) || defined(WIN32_NATIVE)
  4235. /* (set-dispatch-macro-character #\##\!
  4236. #'(lambda (stream sub-char n)
  4237. (declare (ignore sub-char))
  4238. (when n (error ...))
  4239. (read-line stream)
  4240. (values))) */
  4241. LISPFUNN(unix_executable_reader,3) { /* reads #! */
  4242. var gcv_object_t* stream_ = test_no_infix(); /* n must be NIL */
  4243. /* stack layout: Stream, sub-char #\!. */
  4244. while (1) {
  4245. var object ch = read_char(stream_); /* read character */
  4246. if (eq(ch,eof_value) || eq(ch,ascii_char(NL)))
  4247. break;
  4248. }
  4249. VALUES0; skipSTACK(2);
  4250. }
  4251. #endif
  4252. /* --------------------- LISP-Functions of the Reader -------------------- */
  4253. /* UP: checks an Input-Stream-Argument.
  4254. Default is the value of *STANDARD-INPUT*.
  4255. check_istream(&stream);
  4256. > stream: Input-Stream-Argument
  4257. < stream: Input-Stream (a Stream)
  4258. can trigger GC */
  4259. local maygc void check_istream (gcv_object_t* stream_) {
  4260. var object stream = *stream_;
  4261. if (missingp(stream)) {
  4262. /* instead of #<UNBOUND> or NIL: value of *STANDARD-INPUT* */
  4263. *stream_ = var_stream(S(standard_input),strmflags_rd_ch_B);
  4264. } else if (eq(stream,T)) { /* instead of T: value of *TERMINAL-IO* */
  4265. *stream_ = var_stream(S(terminal_io),strmflags_rd_ch_B);
  4266. } else
  4267. *stream_ = check_stream(stream);
  4268. }
  4269. /* EOF-Handling, ends Reader-Functions.
  4270. eof_handling()
  4271. > STACK_3: Input-Stream
  4272. > STACK_2: eof-error-p
  4273. > STACK_1: eof-value
  4274. > STACK_0: recursive-p
  4275. < mv_space/mv_count: values */
  4276. local Values eof_handling (int mvc) {
  4277. if (!nullp(STACK_2)) { /* eof-error-p /= NIL (e.g. = #<UNBOUND>) ? */
  4278. /* report Error: */
  4279. var object recursive_p = STACK_0;
  4280. if (missingp(recursive_p))
  4281. error_eof_outside(&STACK_3); /* report EOF */
  4282. else
  4283. error_eof_inside(&STACK_3); /* report EOF within Object */
  4284. } else { /* handle EOF: */
  4285. var object eofval = STACK_1;
  4286. if (!boundp(eofval))
  4287. eofval = NIL; /* Default is NIL */
  4288. value1 = eofval; mv_count=mvc; skipSTACK(4); /* eofval as value */
  4289. }
  4290. }
  4291. /* UP: for READ and READ-PRESERVING-WHITESPACE
  4292. read_w(whitespace-p)
  4293. > whitespace-p: indicates, if whitespace has to be consumed afterwards
  4294. > stack layout: input-stream, eof-error-p, eof-value, recursive-p.
  4295. < STACK: cleaned up
  4296. < mv_space/mv_count: values
  4297. can trigger GC */
  4298. local maygc Values read_w (object whitespace_p) {
  4299. check_istream(&STACK_3); /* check input-stream */
  4300. /* check for recursive-p-Argument: */
  4301. var object recursive_p = STACK_0;
  4302. if (missingp(recursive_p)) { /* non-recursive call */
  4303. var object obj = read_top(&STACK_3,whitespace_p);
  4304. if (eq(obj,dot_value))
  4305. error_dot(STACK_3); /* Dot -> Error */
  4306. if (eq(obj,eof_value)) {
  4307. return_Values eof_handling(1); /* EOF-treatment */
  4308. } else {
  4309. VALUES1(obj); skipSTACK(4);
  4310. }
  4311. } else { /* recursive call */
  4312. VALUES1(read_recursive_no_dot(&STACK_3)); skipSTACK(4);
  4313. }
  4314. }
  4315. /* (READ [input-stream [eof-error-p [eof-value [recursive-p]]]]),
  4316. CLTL p. 375 */
  4317. LISPFUN(read,seclass_default,0,4,norest,nokey,0,NIL) {
  4318. return_Values read_w(NIL); /* whitespace-p := NIL */
  4319. }
  4320. /* (READ-PRESERVING-WHITESPACE [input-stream [eof-error-p [eof-value [recursive-p]]]]),
  4321. CLTL p. 376 */
  4322. LISPFUN(read_preserving_whitespace,seclass_default,0,4,norest,nokey,0,NIL) {
  4323. return_Values read_w(T); /* whitespace-p := T */
  4324. }
  4325. /* (READ-DELIMITED-LIST char [input-stream [recursive-p]]), CLTL p. 377 */
  4326. LISPFUN(read_delimited_list,seclass_default,1,2,norest,nokey,0,NIL) {
  4327. /* check char: */
  4328. var object ch = check_char(STACK_2);
  4329. check_istream(&STACK_1); /* check input-stream */
  4330. /* check for recursive-p-Argument: */
  4331. var object recursive_p = popSTACK();
  4332. /* stack layout: char, input-stream. */
  4333. if (missingp(recursive_p)) {
  4334. /* non-recursive call */
  4335. var gcv_object_t* stream_ = &STACK_0;
  4336. /* bind SYS::*READ-REFERENCE-TABLE* to empty Table NIL: */
  4337. dynamic_bind(S(read_reference_table),NIL);
  4338. /* bind SYS::*BACKQUOTE-LEVEL* to NIL: */
  4339. dynamic_bind(S(backquote_level),NIL);
  4340. var object obj = read_delimited_list(stream_,ch,eof_value); /* read List */
  4341. obj = make_references(obj); /* unentangle references */
  4342. dynamic_unbind(S(backquote_level));
  4343. dynamic_unbind(S(read_reference_table));
  4344. VALUES1(obj); /* List as value */
  4345. } else {
  4346. /* recursive call */
  4347. VALUES1(read_delimited_list(&STACK_0,ch,eof_value));
  4348. }
  4349. /* (read List both times, no Dotted List allowed.) */
  4350. skipSTACK(2);
  4351. }
  4352. /* (READ-LINE [input-stream [eof-error-p [eof-value [recursive-p]]]]),
  4353. CLTL p. 378
  4354. This implementation always returns a simple string, if end-of-stream
  4355. is not encountered immediately. Code in debug.d depends on this. */
  4356. LISPFUN(read_line,seclass_default,0,4,norest,nokey,0,NIL) {
  4357. var gcv_object_t* stream_ = &STACK_3;
  4358. check_istream(stream_); /* check input-stream */
  4359. get_buffers(); /* two empty Buffers on Stack */
  4360. if (!read_line(stream_,&STACK_1)) { /* read line */
  4361. /* End of Line
  4362. copy Buffer and convert into Simple-String: */
  4363. VALUES2(copy_string(STACK_1), NIL); /* NIL as 2nd value */
  4364. /* free Buffer for reuse: */
  4365. O(token_buff_2) = popSTACK(); O(token_buff_1) = popSTACK();
  4366. skipSTACK(4); return;
  4367. } else {
  4368. /* End of File
  4369. Buffer empty? */
  4370. if (TheIarray(STACK_1)->dims[1] == 0) { /* Length (Fill-Pointer) = 0 ? */
  4371. /* free Buffer for reuse: */
  4372. O(token_buff_2) = popSTACK(); O(token_buff_1) = popSTACK();
  4373. /* treat EOF specially: */
  4374. value2 = T;
  4375. return_Values eof_handling(2);
  4376. } else {
  4377. /* copy Buffer and convert into Simple-String: */
  4378. VALUES2(copy_string(STACK_1), T); /* T as 2nd value */
  4379. /* free Buffer for reuse: */
  4380. O(token_buff_2) = popSTACK(); O(token_buff_1) = popSTACK();
  4381. skipSTACK(4); return;
  4382. }
  4383. }
  4384. }
  4385. /* (READ-CHAR [input-stream [eof-error-p [eof-value [recursive-p]]]]),
  4386. CLTL p. 379 */
  4387. LISPFUN(read_char,seclass_default,0,4,norest,nokey,0,NIL) {
  4388. var gcv_object_t* stream_ = &STACK_3;
  4389. check_istream(stream_); /* check input-stream */
  4390. var object ch = read_char(stream_); /* read Character */
  4391. if (eq(ch,eof_value)) {
  4392. return_Values eof_handling(1);
  4393. } else {
  4394. VALUES1(ch); skipSTACK(4); return;
  4395. }
  4396. }
  4397. /* (UNREAD-CHAR char [input-stream]), CLTL p. 379 */
  4398. LISPFUN(unread_char,seclass_default,1,1,norest,nokey,0,NIL) {
  4399. var gcv_object_t* stream_ = &STACK_0;
  4400. check_istream(stream_); /* check input-stream */
  4401. var object ch = check_char(STACK_1); /* char */
  4402. unread_char(stream_,ch); /* push back char to Stream */
  4403. VALUES1(NIL); skipSTACK(2);
  4404. }
  4405. /* (PEEK-CHAR [peek-type [input-stream [eof-error-p [eof-value [recursive-p]]]]]),
  4406. CLTL p. 379 */
  4407. LISPFUN(peek_char,seclass_default,0,5,norest,nokey,0,NIL) {
  4408. var gcv_object_t* stream_ = &STACK_3;
  4409. check_istream(stream_); /* check input-stream */
  4410. /* distinction of cases by peek-type: */
  4411. var object peek_type = STACK_4;
  4412. if (missingp(peek_type)) {
  4413. /* Default NIL: peek one character */
  4414. var object ch = peek_char(stream_);
  4415. if (eq(ch,eof_value))
  4416. goto eof;
  4417. VALUES1(ch); skipSTACK(5); return;
  4418. } else if (eq(peek_type,T)) {
  4419. /* T: Whitespace-Peek */
  4420. var object ch = wpeek_char_eof(stream_);
  4421. if (eq(ch,eof_value))
  4422. goto eof;
  4423. VALUES1(ch); skipSTACK(5); return;
  4424. } else if (charp(peek_type)) {
  4425. /* peek-type is a Character */
  4426. var object ch;
  4427. while (1) {
  4428. ch = peek_char(stream_); /* what next? */
  4429. if (eq(ch,eof_value))
  4430. goto eof;
  4431. if (eq(ch,peek_type)) /* the preset End-character? */
  4432. break;
  4433. read_char(stream_); /* not done yet - skip this char */
  4434. }
  4435. VALUES1(ch); skipSTACK(5); return;
  4436. } else {
  4437. pushSTACK(peek_type); /* TYPE-ERROR slot DATUM */
  4438. pushSTACK(O(type_peektype)); /* TYPE-ERROR slot EXPECTED-TYPE */
  4439. pushSTACK(peek_type);
  4440. pushSTACK(TheSubr(subr_self)->name);
  4441. error(type_error,
  4442. GETTEXT("~S: peek type should be NIL or T or a character, not ~S"));
  4443. }
  4444. eof: /* EOF */
  4445. eof_handling(1); skipSTACK(1); return;
  4446. }
  4447. /* (LISTEN [input-stream]), CLTL p. 380 */
  4448. LISPFUN(listen,seclass_default,0,1,norest,nokey,0,NIL) {
  4449. check_istream(&STACK_0); /* check input-stream */
  4450. if (builtin_stream_p(STACK_0))
  4451. VALUES_IF(ls_avail_p(listen_char(popSTACK())));
  4452. else funcall(S(stream_listen),1);
  4453. }
  4454. /* (READ-CHAR-WILL-HANG-P input-stream)
  4455. tests whether READ-CHAR-NO-HANG will return immediately without reading a
  4456. character, but accomplishes this without actually calling READ-CHAR-NO-HANG,
  4457. thus avoiding the need for UNREAD-CHAR and preventing side effects. */
  4458. LISPFUNN(read_char_will_hang_p,1) {
  4459. check_istream(&STACK_0); /* check input-stream */
  4460. VALUES_IF(ls_wait_p(listen_char(popSTACK())));
  4461. }
  4462. /* (READ-CHAR-NO-HANG [input-stream [eof-error-p [eof-value [recursive-p]]]]),
  4463. CLTL p. 380 */
  4464. LISPFUN(read_char_no_hang,seclass_default,0,4,norest,nokey,0,NIL) {
  4465. var gcv_object_t* stream_ = &STACK_3;
  4466. check_istream(stream_); /* check input-stream */
  4467. var object stream = *stream_;
  4468. if (builtin_stream_p(stream)
  4469. ? !(TheStream(stream)->strmflags & bit(strmflags_rd_ch_bit_B))
  4470. : !instanceof(stream,O(class_fundamental_input_stream)))
  4471. error_illegal_streamop(S(read_char_no_hang),stream);
  4472. var signean status = listen_char(stream);
  4473. if (ls_eof_p(status)) { /* EOF ? */
  4474. return_Values eof_handling(1);
  4475. } else if (ls_avail_p(status)) { /* character available */
  4476. var object ch = read_char(stream_); /* read Character */
  4477. if (eq(ch,eof_value)) { /* query for EOF, for safety reasons */
  4478. return_Values eof_handling(1);
  4479. } else {
  4480. VALUES1(ch); skipSTACK(4); return;
  4481. }
  4482. } else { /* ls_wait_p(status) - no character available */
  4483. /* instead of waiting, return NIL as value, immediately: */
  4484. VALUES1(NIL); skipSTACK(4); return;
  4485. }
  4486. }
  4487. /* (CLEAR-INPUT [input-stream]), CLTL p. 380 */
  4488. LISPFUN(clear_input,seclass_default,0,1,norest,nokey,0,NIL) {
  4489. check_istream(&STACK_0); /* check input-stream */
  4490. clear_input(popSTACK());
  4491. VALUES1(NIL);
  4492. }
  4493. /* (READ-FROM-STRING string [eof-error-p [eof-value [:preserve-whitespace]
  4494. [:start] [:end]]]),
  4495. CLTL p. 380
  4496. Method:
  4497. (defun read-from-string (string &optional (eof-error-p t) (eof-value nil)
  4498. &key (start 0) (end nil) (preserve-whitespace nil)
  4499. &aux index)
  4500. (values
  4501. (with-input-from-string (stream string :start start :end end :index index)
  4502. (funcall (if preserve-whitespace #'read-preserving-whitespace #'read)
  4503. stream eof-error-p eof-value nil))
  4504. index))
  4505. or macroexpanded:
  4506. (defun read-from-string (string &optional (eof-error-p t) (eof-value nil)
  4507. &key (start 0) (end nil) (preserve-whitespace nil))
  4508. (let ((stream (make-string-input-stream string start end)))
  4509. (values
  4510. (unwind-protect
  4511. (funcall (if preserve-whitespace #'read-preserving-whitespace #'read)
  4512. stream eof-error-p eof-value nil)
  4513. (close stream))
  4514. (system::string-input-stream-index stream))))
  4515. or simplified:
  4516. (defun read-from-string (string &optional (eof-error-p t) (eof-value nil)
  4517. &key (start 0) (end nil) (preserve-whitespace nil))
  4518. (let ((stream (make-string-input-stream string start end)))
  4519. (values
  4520. (funcall (if preserve-whitespace #'read-preserving-whitespace #'read)
  4521. stream eof-error-p eof-value nil)
  4522. (system::string-input-stream-index stream)))) */
  4523. LISPFUN(read_from_string,seclass_default,1,2,norest,key,3,
  4524. (kw(preserve_whitespace),kw(start),kw(end)) ) {
  4525. /* stack layout: string, eof-error-p, eof-value, preserve-whitespace, start, end.
  4526. process :preserve-whitespace-Argument: */
  4527. var object preserve_whitespace = STACK_2;
  4528. if (!boundp(preserve_whitespace))
  4529. preserve_whitespace = NIL;
  4530. /* call MAKE-STRING-INPUT-STREAM with Arguments string, start, end: */
  4531. STACK_2 = STACK_5; /* string */
  4532. if (!boundp(STACK_1))
  4533. STACK_1 = Fixnum_0; /* start has Default 0 */
  4534. if (!boundp(STACK_0))
  4535. STACK_0 = NIL; /* end has Default NIL */
  4536. STACK_5 = preserve_whitespace;
  4537. funcall(L(make_string_input_stream),3);
  4538. /* stack layout: preserve-whitespace, eof-error-p, eof-value. */
  4539. pushSTACK(STACK_1); pushSTACK(STACK_1);
  4540. STACK_3 = STACK_2 = value1;
  4541. /* stack layout: preserve-whitespace, stream, stream, eof-error-p, eof-value. */
  4542. pushSTACK(NIL); read_w(STACK_5); /* READ respectively READ-PRESERVE-WHITESPACE */
  4543. /* stack layout: preserve-whitespace, stream. */
  4544. STACK_1 = value1; /* read Object */
  4545. funcall(L(string_input_stream_index),1); /* (SYS::STRING-INPUT-STREAM-INDEX stream) */
  4546. value2 = value1; value1 = popSTACK(); /* Index as 2nd, Object as 1st value */
  4547. mv_count=2;
  4548. }
  4549. /* (PARSE-INTEGER string [:start] [:end] [:radix] [:junk-allowed]),
  4550. CLTL p. 381 */
  4551. LISPFUN(parse_integer,seclass_read,1,0,norest,key,4,
  4552. (kw(start),kw(end),kw(radix),kw(junk_allowed)) ) {
  4553. /* process :junk-allowed-Argument: */
  4554. var bool junk_allowed;
  4555. {
  4556. var object arg = popSTACK();
  4557. junk_allowed = !missingp(arg);
  4558. }
  4559. /* junk_allowed = value of :junk-allowed-Argument.
  4560. process :radix-Argument: */
  4561. var uintV base;
  4562. {
  4563. var object arg = popSTACK();
  4564. if (!boundp(arg))
  4565. base = 10; /* Default 10 */
  4566. else
  4567. while (!(posfixnump(arg)
  4568. && (base = posfixnum_to_V(arg), ((base >= 2) && (base <= 36))))) {
  4569. pushSTACK(NIL); /* no PLACE */
  4570. pushSTACK(arg); /* TYPE-ERROR slot DATUM */
  4571. pushSTACK(O(type_radix)); /* TYPE-ERROR slot EXPECTED-TYPE */
  4572. pushSTACK(arg); /* base */
  4573. pushSTACK(S(Kradix));
  4574. pushSTACK(TheSubr(subr_self)->name);
  4575. check_value(type_error,GETTEXT("~S: ~S argument ~S is not an integer between 2 and 36"));
  4576. arg = value1;
  4577. }
  4578. }
  4579. /* base = value of :radix-argument.
  4580. check string, :start and :end: */
  4581. var stringarg arg;
  4582. var object string = test_string_limits_ro(&arg);
  4583. /* STACK is not cleared up. */
  4584. var uintL start = arg.index; /* value of :start-argument */
  4585. var uintL len = arg.len; /* number of the addressed characters */
  4586. var const chart* charptr;
  4587. unpack_sstring_alloca(arg.string,arg.len,arg.offset+arg.index, charptr=);
  4588. /* loop variables: */
  4589. var uintL index = start;
  4590. var uintL count = len;
  4591. var uintL start_offset;
  4592. var uintL end_offset;
  4593. /* and now:
  4594. string : the string,
  4595. arg.string : its data-vector (a simple-string),
  4596. start : index of the first character in the string
  4597. charptr : pointer in the data-vector of the next character,
  4598. index : index in the string,
  4599. count : the number of remaining characters. */
  4600. var signean sign;
  4601. {
  4602. var chart c; /* the last character read */
  4603. /* step 1: skip whitespace */
  4604. while (1) {
  4605. if (count==0) /* the string has already ended? */
  4606. goto badsyntax;
  4607. c = *charptr; /* the next character */
  4608. if (!(orig_syntax_table_get(c) == syntax_whitespace)) /* no whitespace? */
  4609. break;
  4610. charptr++; index++; count--; /* skip whitespace */
  4611. }
  4612. /* step 2: read the sign */
  4613. sign = 0; /* sign := positive */
  4614. switch (as_cint(c)) {
  4615. case '-': sign = -1; /* sign := negative */
  4616. case '+': /* sign found */
  4617. charptr++; index++; count--; /* skip */
  4618. if (count==0) /* the string has already ended? */
  4619. goto badsyntax;
  4620. default: break;
  4621. }
  4622. }
  4623. /* done with sign, still should be (count>0). */
  4624. start_offset = arg.offset + index;
  4625. /* now: start_offset = offset of the first digit in the data vector
  4626. step 3: read digits */
  4627. while (1) {
  4628. var cint c = as_cint(*charptr); /* the next character */
  4629. /* check the digits: (digit-char-p (code-char c) base) ?
  4630. (cf. DIGIT-CHAR-P in CHARSTRG.D) */
  4631. if (c > 'z') break; /* too large -> no */
  4632. if (c >= 'a') { c -= 'a'-'A'; } /* upcase 'a'<= char <='z' */
  4633. /* now $00 <= c <= $60. */
  4634. if (c < '0') break;
  4635. /* $30 <= c <= $60 convert to the numeric value */
  4636. if (c <= '9')
  4637. c = c - '0';
  4638. else if (c >= 'A')
  4639. c = c - 'A' + 10;
  4640. else
  4641. break;
  4642. /* now 0 =< c <=41 is the numeric value of the digit */
  4643. if (c >= (uintB)base) /* only valid if 0 <= c < base. */
  4644. break;
  4645. /* *charptr is a valid digit. */
  4646. charptr++; index++; count--; /* skip */
  4647. if (count==0)
  4648. break;
  4649. }
  4650. /* done with the digit. */
  4651. end_offset = arg.offset + index;
  4652. /* now: end_offset = offset after the last digit in the data-vector. */
  4653. if (start_offset == end_offset) /* there were no digits? */
  4654. goto badsyntax;
  4655. /* step 4: skip the final whitespace */
  4656. if (!junk_allowed) { /* if junk_allowed, nothing is to be done */
  4657. while (count!=0) {
  4658. var chart c = *charptr; /* the next character */
  4659. if (orig_syntax_table_get(c) != syntax_whitespace) /* no whitespace? */
  4660. goto badsyntax;
  4661. charptr++; index++; count--; /* skip whitespace */
  4662. }
  4663. }
  4664. /* step 5: convert the sequence of digits into a number */
  4665. VALUES2(read_integer(base,sign,arg.string,start_offset,end_offset),
  4666. fixnum(index));
  4667. return;
  4668. badsyntax: /* illegal character */
  4669. if (!junk_allowed) { /* signal an error */
  4670. pushSTACK(fixnum(index-arg.index));
  4671. pushSTACK(subsstring(arg.string,arg.offset+arg.index,
  4672. arg.offset+arg.index+arg.len));
  4673. pushSTACK(TheSubr(subr_self)->name);
  4674. error(parse_error,GETTEXT("~S: substring ~S does not have integer syntax at position ~S"));
  4675. }
  4676. VALUES2(NIL,fixnum(index));
  4677. return;
  4678. }
  4679. /* ==========================================================================
  4680. P R I N T
  4681. ===========================================================================
  4682. The basic idea of the printer:
  4683. Depending on the datatype, the external representation of the
  4684. object is output to the stream, recursively.
  4685. The difference between PRINT and PPRINT is, that on a few occasions
  4686. a Space is emitted instead of a Newline and a few Spaces.
  4687. In order to achieve this, the external representation of the sub-objects
  4688. is output to a auxiliary Pretty-Printer-(PPHELP-)Stream, then checked
  4689. whether several lines are needed or one is sufficient, and finally
  4690. (depending on this) Whitespace is inserted.
  4691. The more detailed specification of the prin_object-routine:
  4692. > Stream,
  4693. > Line length L,
  4694. > Left border for single-liner L1,
  4695. > Left border for mulit-liner LM,
  4696. > Number of parentheses that remain to be closed on the last line at the end
  4697. K (Fixnum >=0) and Flag, if the last closing parentheses of multi-liners
  4698. are to be printed on a separate line, placed below the corresponding
  4699. opening parentheses.
  4700. [For simplicity, K=0 and Flag=True, i.e. all
  4701. closing parentheses of multi-liners appear on their own line.]
  4702. < Stream, to which the object was output,
  4703. either as single-liner (of length <=L-L1-K)
  4704. or as multiliner (with Newline and LM Spaces instead of Space between
  4705. subobjects), each line (if possible) of length <=L, last line
  4706. (if possible) of length <=L-K.
  4707. < if stream is a PPHELP-Stream, it contains the mode (state) and a
  4708. non-empty list of the output lines (in reversed order).
  4709. a pr_xxx-Routine receives &stream und obj as argument: */
  4710. typedef maygc void pr_routine_t (const gcv_object_t* stream_, object obj);
  4711. /* ---------------------- common sub-routines ----------------------------
  4712. UP: Outputs an unsigned integer with max. 32 Bit decimally to the Stream.
  4713. pr_uint(&stream,uint);
  4714. > uint: Unsigned Integer
  4715. > stream: Stream
  4716. < stream: Stream
  4717. can trigger GC */
  4718. local maygc void pr_uint (const gcv_object_t* stream_, uintL x) {
  4719. var uintB ziffern[10]; /* max. 10 digits, as 0 <= x < 2^32 <= 10^10 */
  4720. var uintB* ziffptr = &ziffern[0];
  4721. var uintC ziffcount = 0; /* number of digits */
  4722. /* produce digits: */
  4723. do {
  4724. var uintB zif;
  4725. divu_3216_3216(x,10,x=,zif=); /* x := floor(x/10), zif := Rest */
  4726. *ziffptr++ = zif; ziffcount++; /* save digit */
  4727. } while (x != 0);
  4728. /* ouput digits in reversed order: */
  4729. dotimespC(ziffcount,ziffcount, {
  4730. write_ascii_char(stream_,'0' + *--ziffptr);
  4731. });
  4732. }
  4733. /* UP: outputs a Nibble hexadecimally (with 1 hex-digit) to stream.
  4734. pr_hex1(&stream,x);
  4735. > x: Nibble (>=0,<16)
  4736. > stream: Stream
  4737. < stream: Stream
  4738. can trigger GC */
  4739. local maygc void pr_hex1 (const gcv_object_t* stream_, uint4 x) {
  4740. write_ascii_char(stream_, ( x<10 ? '0'+(uintB)x : 'A'+(uintB)x-10 ) );
  4741. }
  4742. /* UP: outputs a byte hexadecimally (with 2 hex-digits) to stream.
  4743. pr_hex2(&stream,x);
  4744. > x: Byte
  4745. > stream: Stream
  4746. < stream: Stream
  4747. can trigger GC */
  4748. local maygc void pr_hex2 (const gcv_object_t* stream_, uint8 x) {
  4749. pr_hex1(stream_,(uint4)(x>>4)); /* output Bits 7..4 */
  4750. pr_hex1(stream_,(uint4)(x & (bit(4)-1))); /* output Bits 3..0 */
  4751. }
  4752. /* UP: outputs an address with 24 Bit hexadecimally (with 6 hex-digits)
  4753. to Stream.
  4754. pr_hex6(&stream,obj);
  4755. > addressbits of obj: unsigned integer
  4756. > stream: Stream
  4757. < stream: Stream
  4758. can trigger GC */
  4759. local maygc void pr_hex6 (const gcv_object_t* stream_, object obj) {
  4760. var oint x = (as_oint(obj) >> oint_addr_shift) << addr_shift;
  4761. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'x'); /* Prefix for "Hexadecimal" */
  4762. #define pr_hexpart(k) /* output bits k+7..k: */ \
  4763. if (((oint_addr_mask>>oint_addr_shift)<<addr_shift) & minus_wbit(k)) \
  4764. { pr_hex2(stream_,(uint8)((x >> k) & (((oint_addr_mask>>oint_addr_shift)<<addr_shift) >> k) & 0xFF)); }
  4765. #ifdef WIDE_HARD
  4766. pr_hexpart(56);
  4767. pr_hexpart(48);
  4768. pr_hexpart(40);
  4769. pr_hexpart(32);
  4770. #endif
  4771. pr_hexpart(24);
  4772. pr_hexpart(16);
  4773. pr_hexpart(8);
  4774. pr_hexpart(0);
  4775. #undef pr_hexpart
  4776. }
  4777. #ifdef FOREIGN
  4778. /* UP: outputs an address with 32 bit hexadecimally (with 8 hex-digits)
  4779. to Stream.
  4780. pr_hex8(&stream,x);
  4781. > x: address
  4782. > stream: Stream
  4783. < stream: Stream
  4784. can trigger GC */
  4785. local maygc void pr_hex8 (const gcv_object_t* stream_, uintP x) {
  4786. /* Prefix for "Hexadecimal" */
  4787. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'x');
  4788. var sintC k = (sizeof(uintP)-1)*8;
  4789. do { pr_hex2(stream_,(uint8)(x >> k));
  4790. } while ((k -= 8) >= 0);
  4791. }
  4792. #endif
  4793. /* *PRINT-READABLY* /= NIL causes among other things implicitely the same as
  4794. *PRINT-ESCAPE* = T, *PRINT-BASE* = 10, *PRINT-RADIX* = T,
  4795. *PRINT-CIRCLE* = T, *PRINT-LEVEL* = NIL, *PRINT-LENGTH* = NIL,
  4796. *PRINT-LINES* = NIL,
  4797. *PRINT-GENSYM* = T, *PRINT-ARRAY* = T, *PRINT-CLOSURE* = T.
  4798. error-message when *PRINT-READABLY* /= NIL.
  4799. error_print_readably(obj); */
  4800. nonreturning_function(local, error_print_readably, (object obj)) {
  4801. /* (error-of-type 'print-not-readable
  4802. "~S: Despite ~S, ~S cannot be printed readably."
  4803. 'print '*print-readably* obj) */
  4804. dynamic_bind(S(print_readably),NIL); /* bind *PRINT-READABLY* to NIL */
  4805. pushSTACK(obj); /* PRINT-NOT-READABLE slot OBJECT */
  4806. pushSTACK(obj);
  4807. pushSTACK(S(print_readably));
  4808. pushSTACK(S(print));
  4809. error(print_not_readable,
  4810. GETTEXT("~S: Despite ~S, ~S cannot be printed readably."));
  4811. }
  4812. #define CHECK_PRINT_READABLY(obj) \
  4813. if (!nullpSv(print_readably)) \
  4814. error_print_readably(obj);
  4815. /* error message for inadmissible value of *PRINT-CASE*.
  4816. error_print_case(); */
  4817. nonreturning_function(local, error_print_case, (void)) {
  4818. /* (error "~S: the value ~S of ~S is neither ~S nor ~S nor ~S.
  4819. it is reset to ~S."
  4820. 'print *print-case* '*print-case* ':upcase ':downcase ':capitalize
  4821. ':upcase
  4822. ) */
  4823. var object print_case = S(print_case);
  4824. pushSTACK(Symbol_value(print_case)); /* TYPE-ERROR slot DATUM */
  4825. pushSTACK(O(type_printcase)); /* TYPE-ERROR slot EXPECTED-TYPE */
  4826. pushSTACK(S(Kupcase)); /* :UPCASE */
  4827. pushSTACK(S(Kcapitalize)); /* :CAPITALIZE */
  4828. pushSTACK(S(Kdowncase)); /* :DOWNCASE */
  4829. pushSTACK(S(Kupcase)); /* :UPCASE */
  4830. pushSTACK(print_case);
  4831. pushSTACK(Symbol_value(print_case));
  4832. pushSTACK(S(print));
  4833. Symbol_value(print_case) = S(Kupcase); /* (setq *PRINT-CASE* ':UPCASE) */
  4834. error(type_error,
  4835. GETTEXT("~S: the value ~S of ~S is neither ~S nor ~S nor ~S.\n"
  4836. "It is reset to ~S."));
  4837. }
  4838. /* Macro: retrieves value of *PRINT-CASE* and branches appropriately.
  4839. switch_print_case(upcase_statement,downcase_statement,capitalize_statement); */
  4840. #define switch_print_case(upcase_statement,downcase_statement,capitalize_statement) \
  4841. {var object print_case = Symbol_value(S(print_case)); /* value of *PRINT-CASE* */ \
  4842. if (eq(print_case,S(Kupcase))) /* = :UPCASE ? */ \
  4843. { upcase_statement } \
  4844. else if (eq(print_case,S(Kdowncase))) /* = :DOWNCASE ? */ \
  4845. { downcase_statement } \
  4846. else if (eq(print_case,S(Kcapitalize))) /* = :CAPITALIZE ? */ \
  4847. { capitalize_statement } \
  4848. else /* none of the three -> Error */ \
  4849. { error_print_case(); } \
  4850. }
  4851. /* UP: prints a part of a simple-string elementwise to stream.
  4852. write_sstring_ab(&stream,string,start,len);
  4853. > string: not-reallocated simple-string or (only if len==0) NIL
  4854. > start: startindex
  4855. > len: number of to-be-printed characters
  4856. > stream: Stream
  4857. < stream: Stream
  4858. can trigger GC */
  4859. local maygc void write_sstring_ab (const gcv_object_t* stream_, object string,
  4860. uintL start, uintL len) {
  4861. if (len==0) return;
  4862. pushSTACK(string);
  4863. write_char_array(stream_,&STACK_0,start,len);
  4864. skipSTACK(1);
  4865. }
  4866. /* UP: prints simple-string elementwise to stream.
  4867. write_sstring(&stream,string);
  4868. > string: simple-string
  4869. > stream: Stream
  4870. < stream: Stream
  4871. can trigger GC */
  4872. global maygc void write_sstring (const gcv_object_t* stream_, object string) {
  4873. sstring_un_realloc(string);
  4874. write_sstring_ab(stream_,string,0,Sstring_length(string));
  4875. }
  4876. /* UP: prints string elementwise to stream.
  4877. write_string(&stream,string);
  4878. > string: String
  4879. > stream: Stream
  4880. < stream: Stream
  4881. can trigger GC */
  4882. global maygc void write_string (const gcv_object_t* stream_, object string) {
  4883. if (simple_string_p(string)) { /* Simple-String */
  4884. sstring_un_realloc(string);
  4885. write_sstring(stream_,string);
  4886. } else { /* non-simpler String */
  4887. var uintL len = vector_length(string); /* length */
  4888. var uintL offset = 0; /* offset of string in the data-vector */
  4889. var object sstring = iarray_displace_check(string,len,&offset); /* data-vector */
  4890. if (len > 0 && simple_nilarray_p(sstring)) error_nilarray_retrieve();
  4891. write_sstring_ab(stream_,sstring,offset,len);
  4892. }
  4893. }
  4894. /* UP: prints simple-string in opposite case
  4895. write_sstring_invert(&stream,string);
  4896. > string: Simple-String
  4897. > stream: Stream
  4898. < stream: Stream
  4899. can trigger GC */
  4900. local maygc void write_sstring_invert(const gcv_object_t* stream_,
  4901. object string) {
  4902. sstring_un_realloc(string);
  4903. var uintL len = Sstring_length(string);
  4904. if (len > 0) {
  4905. pushSTACK(string); /* save string */
  4906. SstringDispatch(string,X, {
  4907. var uintL index = 0;
  4908. do {
  4909. var chart c = as_chart(((SstringX)TheVarobject(STACK_0))->data[index]); /* the next character */
  4910. write_code_char(stream_,invert_case(c)); /* print inverted character */
  4911. index++;
  4912. } while (index < len);
  4913. });
  4914. skipSTACK(1);
  4915. }
  4916. }
  4917. /* UP: prints simple-string according to case_sensitive, case_inverted,
  4918. (READTABLE-CASE *READTABLE*) and *PRINT-CASE* to stream.
  4919. write_sstring_case_ext(&stream,string,case_sensitive,case_inverted);
  4920. > string: Simple-String
  4921. > case_sensitive: Flag, whether to assume a case-sensitive reader
  4922. > case_inverted: Flag, whether to implicitly case-invert the string
  4923. > stream: Stream
  4924. < stream: Stream
  4925. can trigger GC */
  4926. local maygc void write_sstring_case_ext (const gcv_object_t* stream_,
  4927. object string, bool case_sensitive,
  4928. bool case_inverted) {
  4929. if (case_sensitive) {
  4930. if (case_inverted)
  4931. write_sstring_invert(stream_,string);
  4932. else
  4933. write_sstring(stream_,string);
  4934. } else {
  4935. /* If (READTABLE-CASE *READTABLE*) is :UPCASE or :DOWNCASE, the reader will
  4936. act case-insensitively; this gives freedom to the printer, and the variable
  4937. *PRINT-CASE* customizes the printer's behaviour.
  4938. If (READTABLE-CASE *READTABLE*) is :PRESERVE or :INVERT, the reader will
  4939. be case-sensitive, therefore the output is already determined without
  4940. looking at *PRINT-CASE*.
  4941. Retrieve (READTABLE-CASE *READTABLE*): */
  4942. sstring_un_realloc(string);
  4943. var object readtable;
  4944. get_readtable(readtable = ); /* current readtable */
  4945. switch (RTCase(readtable)) {
  4946. do_downcase:
  4947. {
  4948. var uintL count = Sstring_length(string);
  4949. if (count > 0) {
  4950. var uintL index = 0;
  4951. pushSTACK(string); /* save simple-string */
  4952. SstringDispatch(string,X, {
  4953. dotimespL(count,count, {
  4954. write_code_char(stream_,down_case(as_chart(((SstringX)TheVarobject(STACK_0))->data[index])));
  4955. index++;
  4956. });
  4957. });
  4958. skipSTACK(1);
  4959. }
  4960. }
  4961. break;
  4962. do_upcase:
  4963. {
  4964. var uintL count = Sstring_length(string);
  4965. if (count > 0) {
  4966. var uintL index = 0;
  4967. pushSTACK(string); /* save simple-string */
  4968. SstringDispatch(string,X, {
  4969. dotimespL(count,count, {
  4970. write_code_char(stream_,up_case(as_chart(((SstringX)TheVarobject(STACK_0))->data[index])));
  4971. index++;
  4972. });
  4973. });
  4974. skipSTACK(1);
  4975. }
  4976. }
  4977. break;
  4978. case case_upcase:
  4979. /* retrieve *PRINT-CASE* - determines how the upper case characters
  4980. are printed; lower case characters are always printed lower case. */
  4981. switch_print_case(
  4982. /* :UPCASE -> print upper case characters in Upcase: */
  4983. {
  4984. if (case_inverted)
  4985. write_sstring_invert(stream_,string);
  4986. else
  4987. write_sstring(stream_,string);
  4988. },
  4989. /* :DOWNCASE -> print upper case characters in Downcase: */
  4990. {
  4991. goto do_downcase;
  4992. },
  4993. /* :CAPITALIZE -> print the first uppercase letter of word
  4994. as upper case letter, all other letters as lower case.
  4995. (cf. NSTRING_CAPITALIZE in CHARSTRG.D)
  4996. First Version:
  4997. (lambda (s &aux (l (length s)))
  4998. (prog ((i 0) c)
  4999. 1 ; search from here the next beginning of a word
  5000. (if (= i l) (return))
  5001. (setq c (char s i))
  5002. (unless (alphanumericp c) (write-char c) (incf i) (go 1))
  5003. ; found beginning of word
  5004. (write-char c) (incf i) ; upper case --> upper case
  5005. 2 ; within a word
  5006. (if (= i l) (return))
  5007. (setq c (char s i))
  5008. (unless (alphanumericp c) (write-char c) (incf i) (go 1))
  5009. (write-char (char-downcase c)) ; upper case --> lower case
  5010. (incf i) (go 2)))
  5011. Exactly those characters are printed with char-downcase, which
  5012. were preceded by an alphanumeric character and which are
  5013. alphanumeric themselves.
  5014. [As all Uppercase-Characters (according to CLTL p. 236 top) are
  5015. alphabetic and thus also alphanumeric and char-downcase does not
  5016. change anything on the other characters:
  5017. Exactly those characters are printed with char-downcase,
  5018. which were preceded by an alphanumeric character.
  5019. We don't use this.]
  5020. Second version:
  5021. (lambda (s &aux (l (length s)))
  5022. (prog ((i 0) c (flag nil))
  5023. 1 (if (= i l) (return))
  5024. (setq c (char s i))
  5025. (let ((newflag (alphanumericp c)))
  5026. (when (and flag newflag) (setq c (char-downcase c)))
  5027. (setq flag newflag))
  5028. (write-char c) (incf i) (go 1)))
  5029. Third Version:
  5030. (lambda (s &aux (l (length s)))
  5031. (prog ((i 0) c (flag nil))
  5032. 1 (if (= i l) (return))
  5033. (setq c (char s i))
  5034. (when (and (shiftf flag (alphanumericp c)) flag)
  5035. (setq c (char-downcase c)))
  5036. (write-char c) (incf i) (go 1))) */
  5037. {
  5038. var uintL count = Sstring_length(string);
  5039. if (count > 0) {
  5040. var bool flag = false;
  5041. var uintL index = 0;
  5042. pushSTACK(string); /* save simple-string */
  5043. SstringDispatch(string,X, {
  5044. dotimespL(count,count, {
  5045. /* flag indicates whether within a word */
  5046. var bool oldflag = flag;
  5047. var chart c = as_chart(((SstringX)TheVarobject(STACK_0))->data[index]); /* next character */
  5048. if ((flag = alphanumericp(c)) && oldflag)
  5049. /* alphanumeric character in word: */
  5050. c = down_case(c); /* upper case --> lower case */
  5051. write_code_char(stream_,c); /* and print */
  5052. index++;
  5053. });
  5054. });
  5055. skipSTACK(1);
  5056. }
  5057. });
  5058. break;
  5059. case case_downcase:
  5060. /* retrieve *PRINT-CASE* - determines how the lower case characters
  5061. are printed; upper case characters are always printed upper case. */
  5062. switch_print_case(
  5063. /* :UPCASE -> print lower case letters in Upcase: */
  5064. {
  5065. goto do_upcase;
  5066. },
  5067. /* :DOWNCASE -> print lower case letters in Downcase: */
  5068. {
  5069. if (case_inverted)
  5070. write_sstring_invert(stream_,string);
  5071. else
  5072. write_sstring(stream_,string);
  5073. },
  5074. /* :CAPITALIZE -> print the first lower case letter of word
  5075. as upper case letter, all other letters as lower case.
  5076. (ref. NSTRING_CAPITALIZE in CHARSTRG.D)
  5077. first Version:
  5078. (lambda (s &aux (l (length s)))
  5079. (prog ((i 0) c)
  5080. 1 ; search from here the next beginning of a word
  5081. (if (= i l) (return))
  5082. (setq c (char s i))
  5083. (unless (alphanumericp c) (write-char c) (incf i) (go 1))
  5084. ; found beginning of word
  5085. (write-char (char-upcase c)) ; lower case --> upper case
  5086. (incf i)
  5087. 2 ; within a word
  5088. (if (= i l) (return))
  5089. (setq c (char s i))
  5090. (unless (alphanumericp c) (write-char c) (incf i) (go 1))
  5091. (write-char c) ; lower case --> lower case
  5092. (incf i) (go 2)))
  5093. Exactly those characters are printed with char-upcase,
  5094. which were not preceded by an alphanumeric character but
  5095. which are alphanumeric themselves.
  5096. Second version:
  5097. (lambda (s &aux (l (length s)))
  5098. (prog ((i 0) c (flag nil))
  5099. 1 (if (= i l) (return))
  5100. (setq c (char s i))
  5101. (when (and (not (shiftf flag (alphanumericp c))) flag)
  5102. (setq c (char-upcase c))
  5103. )
  5104. (write-char c) (incf i) (go 1))) */
  5105. {
  5106. var uintL count = Sstring_length(string);
  5107. if (count > 0) {
  5108. var bool flag = false;
  5109. var uintL index = 0;
  5110. pushSTACK(string); /* save simple-string */
  5111. SstringDispatch(string,X, {
  5112. dotimespL(count,count, {
  5113. /* flag indicates whether within a word */
  5114. var bool oldflag = flag;
  5115. var chart c = as_chart(((SstringX)TheVarobject(STACK_0))->data[index]); /* next character */
  5116. if ((flag = alphanumericp(c)) && !oldflag)
  5117. /* alphanumeric character at the beginning of word: */
  5118. c = up_case(c); /* lower case --> upper case */
  5119. write_code_char(stream_,c); /* and print */
  5120. index++;
  5121. });
  5122. });
  5123. skipSTACK(1);
  5124. }
  5125. });
  5126. break;
  5127. case case_preserve:
  5128. /* ignore *PRINT-CASE*. */
  5129. if (case_inverted)
  5130. write_sstring_invert(stream_,string);
  5131. else
  5132. write_sstring(stream_,string);
  5133. break;
  5134. case case_invert: { /* ignore *PRINT-CASE*. */
  5135. var bool seen_uppercase = false;
  5136. var bool seen_lowercase = false;
  5137. var uintL count = Sstring_length(string);
  5138. if (count > 0) {
  5139. SstringDispatch(string,X, {
  5140. var const cintX* cptr = &((SstringX)TheVarobject(string))->data[0];
  5141. dotimespL(count,count, {
  5142. var chart c = as_chart(*cptr++);
  5143. if (case_inverted)
  5144. c = invert_case(c);
  5145. if (!chareq(c,up_case(c)))
  5146. seen_lowercase = true;
  5147. if (!chareq(c,down_case(c)))
  5148. seen_uppercase = true;
  5149. });
  5150. });
  5151. }
  5152. if (seen_uppercase) {
  5153. if (!seen_lowercase)
  5154. goto do_downcase;
  5155. } else {
  5156. if (seen_lowercase)
  5157. goto do_upcase;
  5158. }
  5159. if (case_inverted)
  5160. write_sstring_invert(stream_,string);
  5161. else
  5162. write_sstring(stream_,string);
  5163. } break;
  5164. default: NOTREACHED;
  5165. }
  5166. }
  5167. }
  5168. /* UP: prints simple-string according to the current package,
  5169. (READTABLE-CASE *READTABLE*) and *PRINT-CASE* to stream.
  5170. write_sstring_case(&stream,string);
  5171. > string: Simple-String
  5172. > stream: Stream
  5173. < stream: Stream
  5174. can trigger GC */
  5175. local maygc void write_sstring_case (const gcv_object_t* stream_, object string)
  5176. {
  5177. pushSTACK(string); /* save */
  5178. var object curr_pack = get_current_package();
  5179. write_sstring_case_ext(stream_,popSTACK()/*string*/,
  5180. pack_casesensitivep(curr_pack),
  5181. pack_caseinvertedp(curr_pack));
  5182. }
  5183. /* UP: prints a number of Spaces to stream.
  5184. spaces(&stream,scount)
  5185. > scount: number of Spaces (Fixnum>=0)
  5186. > stream: Stream
  5187. < stream: Stream
  5188. can trigger GC */
  5189. local maygc void spaces (const gcv_object_t* stream_, object scount) {
  5190. var uintV count;
  5191. #ifdef IO_DEBUG
  5192. ASSERT(posfixnump(scount));
  5193. #endif
  5194. dotimesV(count,posfixnum_to_V(scount), {
  5195. write_ascii_char(stream_,' ');
  5196. });
  5197. }
  5198. /* ------------------- Sub-Routines for Pretty-Print -----------------------
  5199. Variables:
  5200. ==========
  5201. line-length L value of SYS::*PRIN-LINELENGTH*,
  5202. Fixnum>=0 or NIL
  5203. line-position in PPHELP-Stream, Fixnum>=0
  5204. Left border L1 for single-liner value of SYS::*PRIN-L1*, Fixnum>=0
  5205. Left border LM for multi-liner value of SYS::*PRIN-LM*, Fixnum>=0
  5206. Mode in PPHELP-Stream:
  5207. NIL for single-liner (einzeiler)
  5208. T for multi-liner (mehrzeiler) */
  5209. #define einzeiler NIL
  5210. #define mehrzeiler T
  5211. /* components of a Pretty-Print-Help-Streams:
  5212. strm_pphelp_lpos Line Position (Fixnum>=0)
  5213. strm_pphelp_strings non-empty list of
  5214. Semi-Simple-Strings and
  5215. (newline-keyword . indentation) and
  5216. tab_spec = #(colon atsig col_num col_inc)
  5217. They contain the recent output (in reversed
  5218. order: last line as CAR);
  5219. strm_pphelp_modus Mode: single-liner, if there is only 1 String and
  5220. it contains no NL, otherwise it's a multi-liner.
  5221. WRITE-CHAR always pushes its Character only to the last line
  5222. and updates lpos and modus.
  5223. during Justify:
  5224. previous content of the Streams values of SYS::*PRIN-JBSTRINGS*,
  5225. SYS::*PRIN-JBMODUS*, SYS::*PRIN-JBLPOS*
  5226. previous blocks (list of blocks,
  5227. multiline block = non-empty list of Semi-Simple-Strings,
  5228. single-line block = Semi-Simple-String)
  5229. value of SYS::*PRIN-JBLOCKS*
  5230. for compliance/adherence to *PRINT-LEVEL*:
  5231. SYS::*PRIN-LEVEL* current output-depth (Fixnum>=0)
  5232. for readability of backquote-expressions:
  5233. SYS::*PRIN-BQLEVEL* current backquote-depth (Fixnum>=0)
  5234. when thread-of-control leaves the printer:
  5235. SYS::*PRIN-STREAM* current Stream (Default: NIL),
  5236. in order to recognize a recursive PRINT or WRITE.
  5237. for compliance/adherence to *PRINT-LENGTH*:
  5238. limitation of length (uintL >=0 oder ~0) local
  5239. previous length (uintL >=0) local
  5240. for pretty printing of parentheses:
  5241. *PRINT-RPARS* (T or NIL) indicates, if parentheses are to be printed
  5242. in an extra line as " ) ) )" or not.
  5243. SYS::*PRIN-RPAR* = position of the last opening parenthesis (Fixnum>=0,
  5244. or NIL if the closing parenthesis should be moved to the
  5245. end of the line and not below the opening parenthesis)
  5246. UP: this is a PPHELP helper - used here and in stream.d
  5247. (setf (strm-pphelp-strings *stream_)
  5248. (list* (make-Semi-Simple-String 50)
  5249. (cons nl_type *PRIN-INDENTATION*)
  5250. (strm-pphelp-strings *stream_))
  5251. can trigger GC */
  5252. global maygc object cons_ssstring (const gcv_object_t* stream_, object nl_type)
  5253. {
  5254. var object indent = Symbol_value(S(prin_indentation));
  5255. if (!boundp(indent)) indent = Fixnum_0;
  5256. pushSTACK(indent);
  5257. pushSTACK(nl_type);
  5258. var object new_cons = allocate_cons();
  5259. Car(new_cons) = popSTACK();
  5260. Cdr(new_cons) = popSTACK();
  5261. pushSTACK(new_cons); /* = (nl . ident) */
  5262. new_cons = allocate_cons();
  5263. Car(new_cons) = popSTACK(); /* new_cons = ((nl . ident) . nil) */
  5264. if ((stream_ != NULL)
  5265. && stringp(Car(TheStream(*stream_)->strm_pphelp_strings))
  5266. && vector_length(Car(TheStream(*stream_)->strm_pphelp_strings)) == 0) {
  5267. Cdr(new_cons) = Cdr(TheStream(*stream_)->strm_pphelp_strings);
  5268. Cdr(TheStream(*stream_)->strm_pphelp_strings) = new_cons;
  5269. new_cons = TheStream(*stream_)->strm_pphelp_strings;
  5270. } else {
  5271. pushSTACK(new_cons);
  5272. pushSTACK(make_ssstring(SEMI_SIMPLE_DEFAULT_SIZE));
  5273. new_cons = allocate_cons();
  5274. Car(new_cons) = popSTACK();
  5275. Cdr(new_cons) = popSTACK(); /* new_cons = ("" (nl . ident)) */
  5276. if (stream_ != NULL) {
  5277. Cdr(Cdr(new_cons)) = TheStream(*stream_)->strm_pphelp_strings;
  5278. TheStream(*stream_)->strm_pphelp_strings = new_cons;
  5279. }
  5280. }
  5281. #if IO_DEBUG > 1
  5282. PPH_OUT(cons_ssstring,*stream_);
  5283. #endif
  5284. return new_cons;
  5285. }
  5286. /* access the NL type and indentation */
  5287. #ifdef IO_DEBUG
  5288. #define PPHELP_NL_TYPE(o) (mconsp(o) ? Car(o) : (NOTREACHED,nullobj))
  5289. #define PPHELP_INDENTN(o) (mconsp(o) ? Cdr(o) : (NOTREACHED,nullobj))
  5290. #else
  5291. #define PPHELP_NL_TYPE Car
  5292. #define PPHELP_INDENTN Cdr
  5293. #endif
  5294. /* UP: tabulation (see format-tabulate here in io.d and in format.lisp) */
  5295. #define PPH_TAB_COLON(tab_spec) TheSvector(tab_spec)->data[0]
  5296. #define PPH_TAB_ATSIG(tab_spec) TheSvector(tab_spec)->data[1]
  5297. #define PPH_TAB_COL_N(tab_spec) TheSvector(tab_spec)->data[2]
  5298. #define PPH_TAB_COL_I(tab_spec) TheSvector(tab_spec)->data[3]
  5299. #ifdef IO_DEBUG
  5300. #define PPH_FORMAT_TAB(out,spec) \
  5301. (!vectorp(spec) || 4 != vector_length(spec) ? NOTREACHED,0 : \
  5302. format_tab(out,PPH_TAB_COLON(spec),PPH_TAB_ATSIG(spec), \
  5303. PPH_TAB_COL_N(spec),PPH_TAB_COL_I(spec)))
  5304. #else
  5305. #define PPH_FORMAT_TAB(out,spec) \
  5306. format_tab(out,PPH_TAB_COLON(spec),PPH_TAB_ATSIG(spec), \
  5307. PPH_TAB_COL_N(spec),PPH_TAB_COL_I(spec))
  5308. #endif
  5309. local uintL format_tab (object stream, object colon_p, object atsig_p,
  5310. object col_num, object col_inc) {
  5311. var uintL col_num_i;
  5312. if (nullp(col_num)) col_num_i = 1;
  5313. else if (posfixnump(col_num)) col_num_i = posfixnum_to_V(col_num);
  5314. else NOTREACHED; /* error_posfixnum(col_num); */
  5315. var uintL col_inc_i;
  5316. if (nullp(col_inc)) col_inc_i = 1;
  5317. else if (posfixnump(col_inc)) col_inc_i = posfixnum_to_V(col_inc);
  5318. else NOTREACHED; /* error_posfixnum(col_inc); */
  5319. var uintL new_col_i = col_num_i +
  5320. (!nullp(colon_p) && boundp(Symbol_value(S(prin_indentation)))
  5321. ? posfixnum_to_V(Symbol_value(S(prin_indentation))) : 0);
  5322. var uintL new_inc_i = (col_inc_i == 0 ? 1 : col_inc_i);
  5323. var object pos = get_line_position(stream);
  5324. var uintL pos_i = (nullp(pos) ? (uintL)-1 : posfixnum_to_V(pos));
  5325. #if IO_DEBUG > 1
  5326. printf("format_tab[%s%s]: cn=%d ci=%d nc=%d ni=%d p=%d ==> ",
  5327. (nullp(atsig_p)?"":"@"),(nullp(colon_p)?"":":"),col_num_i,
  5328. col_inc_i,new_col_i,new_inc_i,pos_i);
  5329. #endif
  5330. var uintL ret;
  5331. /* MSVC6 has broken %, so both arguments to % must be non-negative! */
  5332. if (nullp(atsig_p)) {
  5333. if (nullp(pos)) ret = 2;
  5334. else if (pos_i < new_col_i) ret = new_col_i - pos_i;
  5335. else if (col_inc_i == 0) ret = 0;
  5336. else ret = col_inc_i - (pos_i - new_col_i) % col_inc_i;
  5337. } else {
  5338. if (nullp(pos)) ret = new_col_i;
  5339. else ret = new_col_i +
  5340. (new_inc_i - (pos_i + new_col_i) % new_inc_i) % new_inc_i;
  5341. }
  5342. #if IO_DEBUG > 1
  5343. printf("%d\n",ret);
  5344. #endif
  5345. return ret;
  5346. }
  5347. /* Sub-Routines:
  5348. =============
  5349. These work on the stream and must be undone in the right order,
  5350. because they can modify the STACK.
  5351. print the pretty prefix (prefix string and indentation)
  5352. and compute its length
  5353. can trigger GC when stream_ is non-NULL */
  5354. local /*maygc*/ uintV pprint_prefix (const gcv_object_t* stream_, object indent)
  5355. {
  5356. GCTRIGGER_IF(stream_ != NULL, GCTRIGGER1(indent));
  5357. var uintV len = 0;
  5358. var object prefix = Symbol_value(S(prin_line_prefix));
  5359. if (stringp(prefix)) {
  5360. var uintL add = vector_length(prefix);
  5361. len += add;
  5362. if ((stream_ != NULL) && (add != 0))
  5363. write_string(stream_,prefix);
  5364. }
  5365. if (posfixnump(indent)) {
  5366. var uintV add = posfixnum_to_V(indent);
  5367. len += add;
  5368. if ((stream_ != NULL) && (add != 0))
  5369. spaces(stream_,indent);
  5370. }
  5371. #if IO_DEBUG > 1
  5372. printf("pprint_prefix(%s): %u\n",(stream_==NULL?"null":"valid"),len);
  5373. #endif
  5374. return len;
  5375. }
  5376. /* return
  5377. (- (or *print-right-margin* sys::*prin-linelength*) (pprint_prefix)) */
  5378. local object right_margin (void) {
  5379. var uintV pp_pref_len = pprint_prefix(NULL,Fixnum_0);
  5380. var object prm = Symbol_value(S(print_right_margin));
  5381. if (nullp(prm))
  5382. prm = Symbol_value(S(prin_linelength));
  5383. else if (posfixnump(prm))
  5384. ; /* okay */
  5385. else if (posbignump(prm))
  5386. prm = fixnum(vbitm(oint_data_len)-1);
  5387. else {
  5388. pushSTACK(prm); pushSTACK(S(print_right_margin));
  5389. error(error_condition,GETTEXT("~S: must be a positive integer or NIL, not ~S"));
  5390. }
  5391. if (nullp(prm)) return prm; /* *PRIN-LINELENGTH* is NIL */
  5392. var uintV margin = posfixnum_to_V(prm);
  5393. if (margin <= pp_pref_len) return Fixnum_0;
  5394. else return fixnum(margin - pp_pref_len);
  5395. }
  5396. /* Returns the string-width of a PPHELP stream block. */
  5397. local uintL pphelp_string_width (object string) {
  5398. var uintL width = 0;
  5399. var uintL len = TheIarray(string)->dims[1]; /* length = fill-pointer */
  5400. if (len > 0) {
  5401. string = TheIarray(string)->data; /* mutable simple-string */
  5402. var const chart* charptr = &TheSnstring(string)->data[0];
  5403. dotimespL(len,len, {
  5404. width += char_width(*charptr); charptr++;
  5405. });
  5406. }
  5407. return width;
  5408. }
  5409. /* UP: Starts a new line in PPHELP-Stream A5.
  5410. pphelp_newline(&stream);
  5411. > stream: Stream
  5412. < stream: Stream
  5413. can trigger GC */
  5414. #define LINES_INC \
  5415. do { \
  5416. var object pl = Symbol_value(S(prin_lines)); \
  5417. if (!posfixnump(pl)) error_posfixnum(pl); \
  5418. if (!nullpSv(print_lines)) \
  5419. Symbol_value(S(prin_lines)) = fixnum_inc(pl,1); \
  5420. } while(0)
  5421. local maygc void pphelp_newline (const gcv_object_t* stream_) {
  5422. /* (push (make-ssstring 50) (strm-pphelp-strings stream)) : */
  5423. cons_ssstring(stream_,NIL);
  5424. var object stream = *stream_;
  5425. /* Line-Position := 0, Modus := multi-liner : */
  5426. TheStream(stream)->strm_pphelp_lpos = Fixnum_0;
  5427. TheStream(stream)->strm_pphelp_modus = mehrzeiler;
  5428. LINES_INC;
  5429. }
  5430. #define PPHELP_STREAM_P(str) \
  5431. (builtin_stream_p(str) && (TheStream(str)->strmtype == strmtype_pphelp))
  5432. /* open parenthesis (paren_open) and close parenthesis (paren_close)
  5433. --------------------------
  5434. to be nested correctly. */
  5435. #define PAREN_OPEN paren_open(stream_);
  5436. #define PAREN_CLOSE paren_close(stream_);
  5437. /* UP: prints parenthesis '(' to the stream and possibly memorizes
  5438. the position.
  5439. paren_open(&stream);
  5440. > stream: Stream
  5441. < stream: Stream
  5442. changes STACK
  5443. can trigger GC */
  5444. local maygc void paren_open (const gcv_object_t* stream_) {
  5445. var object stream = *stream_;
  5446. if (!PPHELP_STREAM_P(stream)) { /* normal Stream */
  5447. write_ascii_char(stream_,'(');
  5448. } else { /* Pretty-Print-Help-Stream */
  5449. var object pos = /* position for closing parenthesis */
  5450. (!nullpSv(print_rpars) /* *PRINT-RPARS* /= NIL ? */
  5451. ? (object)TheStream(stream)->strm_pphelp_lpos /* yes -> current Position (Fixnum>=0) */
  5452. : NIL); /* no -> NIL */
  5453. dynamic_bind(S(prin_rpar),pos); /* bind SYS::*PRIN-RPAR* to it */
  5454. write_ascii_char(stream_,'(');
  5455. }
  5456. }
  5457. /* UP: Prints parenthesis ')' to the Stream, possibly at the memorized
  5458. position.
  5459. paren_close(&stream);
  5460. > stream: Stream
  5461. < stream: Stream
  5462. changes STACK
  5463. can trigger GC */
  5464. local maygc void paren_close (const gcv_object_t* stream_) {
  5465. var object stream = *stream_;
  5466. if (!PPHELP_STREAM_P(stream)) { /* normal Stream */
  5467. write_ascii_char(stream_,')');
  5468. } else { /* Pretty-Print-Help-Stream */
  5469. /* fetch desired position of the parenthesis: */
  5470. var object pos = Symbol_value(S(prin_rpar)); /* SYS::*PRIN-RPAR* */
  5471. if (nullp(pos)) { /* none -> print parenthesis behind */
  5472. write_ascii_char(stream_,')');
  5473. } else { /* print parenthesis at Position pos: */
  5474. if (eq(TheStream(stream)->strm_pphelp_modus,mehrzeiler)
  5475. && !nullp(Cdr(TheStream(stream)->strm_pphelp_strings))) {
  5476. /* multi-liner with more than one line ("real" multi-liner)
  5477. print parenthesis at desired Position.
  5478. Therefore test, if the last line in the stream contains
  5479. 1. only Spaces up to the desired Position (inclusively)
  5480. and
  5481. 2. only Spaces and ')' , otherwise.
  5482. if yes, put parenthesis to the desired position.
  5483. if no, start new line, print Spaces and the parenthesis. */
  5484. var object lastline = /* last line */
  5485. Car(TheStream(stream)->strm_pphelp_strings);
  5486. if (!stringp(lastline)) { /* drop the newline / indentation / tab */
  5487. do { TheStream(stream)->strm_pphelp_strings =
  5488. Cdr(TheStream(stream)->strm_pphelp_strings);
  5489. } while (!stringp(TheStream(stream)->strm_pphelp_strings));
  5490. goto new_line;
  5491. }
  5492. var uintL len = TheIarray(lastline)->dims[1]; /* lendgh = Fill-Pointer of line */
  5493. var uintV need = posfixnum_to_V(pos) + 1; /* necessary number of Spaces */
  5494. if (len < need) /* line too short ? */
  5495. goto new_line; /* yes -> start new line */
  5496. lastline = TheIarray(lastline)->data; /* last line, Normal-Simple-String */
  5497. var chart* charptr = &TheSnstring(lastline)->data[0];
  5498. { /* test, if (need) number of spaces are ahead: */
  5499. var uintV count;
  5500. dotimespV(count,need, {
  5501. if (!chareq(*charptr++,ascii(' '))) /* Space ? */
  5502. goto new_line; /* no -> start new line */
  5503. });
  5504. }
  5505. var chart* charptr1 = charptr; /* memorize position */
  5506. /* test, if (len-need) times Space or ')' is ahead: */
  5507. {
  5508. var uintL count;
  5509. dotimesL(count,len-need, {
  5510. var chart c = *charptr++;
  5511. if (!(chareq(c,ascii(' ')) || chareq(c,ascii(')')))) /* Space or ')' ? */
  5512. goto new_line; /* no -> start new line */
  5513. });
  5514. }
  5515. /* put parenthesis to the desired position pos = need-1: */
  5516. *--charptr1 = ascii(')');
  5517. } else {
  5518. /* single-liner.
  5519. parenthesis must be printed behind.
  5520. Exception: if Line-Position = SYS::*PRIN-LINELENGTH*,
  5521. printing would occur past the end of the line;
  5522. instead, a new line is started.
  5523. Max Right Margin == Line-Position ? */
  5524. if (eq(right_margin(),TheStream(stream)->strm_pphelp_lpos)) {
  5525. new_line: /* start enw line */
  5526. pphelp_newline(stream_); spaces(stream_,pos);
  5527. }
  5528. /* print parenthesis behind */
  5529. write_ascii_char(stream_,')');
  5530. }
  5531. }
  5532. dynamic_unbind(S(prin_rpar));
  5533. }
  5534. }
  5535. /* forward declarations for *PRINT-LINES* */
  5536. local bool check_lines_limit (void);
  5537. local void double_dots (const gcv_object_t* stream_);
  5538. #define CHECK_LINES_LIMIT(finally) \
  5539. if (check_lines_limit()) { double_dots(stream_); finally; }
  5540. /* Justify
  5541. -------
  5542. to be nested correctly,
  5543. each time, JUSTIFY_START once,
  5544. then arbitrary output, separated by JUSTIFY_SPACE,
  5545. then once either
  5546. JUSTIFY_END_FILL (collects short blocks even in multi-liners into one line)
  5547. or
  5548. JUSTIFY_END_LINEAR (in multi-liners each block occupies its own line). */
  5549. #define JUSTIFY_START(n) justify_start(stream_,n)
  5550. #define JUSTIFY_SPACE justify_space(stream_)
  5551. #define JUSTIFY_END_FILL justify_end_fill(stream_)
  5552. #define JUSTIFY_END_LINEAR justify_end_linear(stream_)
  5553. /* SYS::*PRIN-TRAILLENGTH* = number of columns that need to be reserved for
  5554. closing parentheses on the current line; bound
  5555. to 0 for all objects immediately followed by
  5556. JUSTIFY_SPACE. Used only if *PRINT-RPARS* = NIL.
  5557. Preparation of an item to be justified. */
  5558. #define JUSTIFY_LAST(is_last) \
  5559. { if (is_last) justify_last(); }
  5560. /* UP: empties a Pretty-Print-Help-Stream.
  5561. justify_empty_1(&stream);
  5562. > stream: Stream
  5563. < stream: Stream
  5564. can trigger GC */
  5565. local maygc void justify_empty_1 (const gcv_object_t* stream_) {
  5566. var object new_cons = cons_ssstring(NULL,NIL);
  5567. var object stream = *stream_;
  5568. TheStream(stream)->strm_pphelp_strings = new_cons; /* new, empty line */
  5569. TheStream(stream)->strm_pphelp_modus = einzeiler; /* Modus := single-liner */
  5570. }
  5571. /* UP: starts a Justify-Block.
  5572. justify_start(&stream,traillength);
  5573. > stream: Stream
  5574. > traillength: additional width that needs to be reserved
  5575. for closing brackets on this level
  5576. < stream: Stream
  5577. changes STACK */
  5578. local void justify_start (const gcv_object_t* stream_, uintL traillength) {
  5579. var object stream = *stream_;
  5580. /* Bind SYS::*PRIN-TRAILLENGTH* to 0 and save its previous value,
  5581. incremented by traillength, in SYS::*PRIN-PREV-TRAILLENGTH*. */
  5582. dynamic_bind(S(prin_prev_traillength),fixnum_inc(Symbol_value(S(prin_traillength)),traillength));
  5583. dynamic_bind(S(prin_traillength),Fixnum_0);
  5584. if (!PPHELP_STREAM_P(stream)) { /* normal Stream -> nothing to do */
  5585. } else { /* Pretty-Print-Help-Stream */
  5586. /* bind SYS::*PRIN-JBSTRINGS* to the content of the stream: */
  5587. dynamic_bind(S(prin_jbstrings),TheStream(stream)->strm_pphelp_strings);
  5588. /* bind SYS::*PRIN-JBMODUS* to the Modus of the Stream: */
  5589. dynamic_bind(S(prin_jbmodus),TheStream(stream)->strm_pphelp_modus);
  5590. /* bind SYS::*PRIN-JBLPOS* to the Line-Position of the Stream: */
  5591. dynamic_bind(S(prin_jblpos),TheStream(stream)->strm_pphelp_lpos);
  5592. /* bind SYS::*PRIN-JBLOCKS* to () : */
  5593. dynamic_bind(S(prin_jblocks),NIL);
  5594. /* empty the Stream: */
  5595. justify_empty_1(stream_);
  5596. }
  5597. }
  5598. /* UP: empties the content of Pretty-Print-Hilfsstream into the Variable
  5599. SYS::*PRIN-JBLOCKS*.
  5600. justify_empty_2(&stream);
  5601. > stream: Stream
  5602. < stream: Stream
  5603. can trigger GC */
  5604. local maygc void justify_empty_2 (const gcv_object_t* stream_) {
  5605. var object stream = *stream_;
  5606. var object new_cons;
  5607. /* extend SYS::*PRIN-JBLOCKS* by the content of the Stream: */
  5608. if (eq(TheStream(stream)->strm_pphelp_modus,mehrzeiler)) { /* multi-liner. */
  5609. /* (push strings SYS::*PRIN-JBLOCKS*) */
  5610. new_cons = allocate_cons(); /* new Cons */
  5611. Car(new_cons) = TheStream(*stream_)->strm_pphelp_strings;
  5612. } else { /* single-liner. */
  5613. /* (push (first strings) SYS::*PRIN-JBLOCKS*), or shorter:
  5614. (setq SYS::*PRIN-JBLOCKS* (rplacd strings SYS::*PRIN-JBLOCKS*)) */
  5615. new_cons = TheStream(stream)->strm_pphelp_strings;
  5616. }
  5617. Cdr(new_cons) = Symbol_value(S(prin_jblocks));
  5618. Symbol_value(S(prin_jblocks)) = new_cons;
  5619. }
  5620. /* UP: prints space, which can be stretched with Justify.
  5621. justify_space(&stream);
  5622. > stream: Stream
  5623. < stream: Stream
  5624. can trigger GC */
  5625. local maygc void justify_space (const gcv_object_t* stream_) {
  5626. if (!PPHELP_STREAM_P(*stream_)) { /* normal Stream -> only one Space */
  5627. write_ascii_char(stream_,' ');
  5628. } else { /* Pretty-Print-Help-Stream */
  5629. justify_empty_2(stream_); /* save content of Stream */
  5630. justify_empty_1(stream_); /* empty Stream */
  5631. /* Line-Position := SYS::*PRIN-LM* (Fixnum>=0) */
  5632. TheStream(*stream_)->strm_pphelp_lpos = Symbol_value(S(prin_lm));
  5633. }
  5634. }
  5635. local maygc void multi_line_sub_block_out (object block, const gcv_object_t* stream_)
  5636. {
  5637. block = nreverse(block); /* bring lines into the right order */
  5638. while (!stringp(Car(block))) /* drop the initial indentations */
  5639. block = Cdr(block);
  5640. /* print first line on the PPHELP-stream: */
  5641. pushSTACK(block);
  5642. write_string(stream_,Car(block));
  5643. block = popSTACK();
  5644. /* append remaining lines to the lines in front of the stream: */
  5645. var object stream = *stream_;
  5646. TheStream(stream)->strm_pphelp_strings =
  5647. nreconc(Cdr(block),TheStream(stream)->strm_pphelp_strings);
  5648. }
  5649. /* UP: Finalizes a Justify-Block, determines the shape of the Block and
  5650. prints its content to the old Stream.
  5651. justify_end_fill(&stream);
  5652. > stream: Stream
  5653. < stream: Stream
  5654. can trigger GC */
  5655. local maygc void justify_end_fill (const gcv_object_t* stream_) {
  5656. if (!PPHELP_STREAM_P(*stream_)) { /* normal Stream -> nothing to do */
  5657. } else { /* Pretty-Print-Help-Stream */
  5658. justify_empty_2(stream_); /* save stream-content */
  5659. /* restore stream-content, i.e values of SYS::*PRIN-JBSTRINGS*,
  5660. SYS::*PRIN-JBMODUS*, SYS::*PRIN-JBLPOS* back to the Stream: */
  5661. var object stream = *stream_;
  5662. /* save current Line-Position: */
  5663. pushSTACK(TheStream(stream)->strm_pphelp_lpos);
  5664. /* restore old stream-content: */
  5665. TheStream(stream)->strm_pphelp_strings = Symbol_value(S(prin_jbstrings));
  5666. TheStream(stream)->strm_pphelp_modus = Symbol_value(S(prin_jbmodus));
  5667. TheStream(stream)->strm_pphelp_lpos = Symbol_value(S(prin_jblpos));
  5668. /* print (non-empty) list of blocks to stream: */
  5669. pushSTACK(nreverse(Symbol_value(S(prin_jblocks)))); /* (nreverse SYS::*PRIN-JBLOCKS*) */
  5670. /* The blocks are printed one by one. Multi-liners are separated from
  5671. themselves and from the single-liners by Newline.
  5672. But as many consecutive single-liners as possible are packed
  5673. (separated by Space) into one line. */
  5674. while (1) { /* Run through Blocklist STACK_0: */
  5675. var object block = Car(STACK_0); /* next block */
  5676. STACK_0 = Cdr(STACK_0); /* shorten blocklist */
  5677. if (consp(block)) { /* Sub-Block with several lines */
  5678. multi_line_sub_block_out(block,stream_);
  5679. /* Modus := multi-liner: */
  5680. stream = *stream_;
  5681. TheStream(stream)->strm_pphelp_modus = mehrzeiler;
  5682. if (matomp(STACK_0)) { /* Restlist empty? */
  5683. /* yes -> reset Line-Position, finished */
  5684. TheStream(stream)->strm_pphelp_lpos = STACK_1;
  5685. break;
  5686. }
  5687. /* start new line and proceed: */
  5688. goto new_line;
  5689. } else {
  5690. /* sub-block consisting of one line
  5691. print to PPHELP-stream: */
  5692. write_string(stream_,block);
  5693. if (matomp(STACK_0)) /* remaining list empty? */
  5694. break; /* yes -> finished */
  5695. /* is next block a multi-liner? */
  5696. block = Car(STACK_0); /* next block */
  5697. if (atomp(block)) { /* a multi-liner or a single-liner? */
  5698. /* it is a single-liner.
  5699. Does it still fit on the same line, i.e
  5700. line-position + 1 + string_width(single-liner) + traillength <= L ? */
  5701. var object linelength = right_margin();
  5702. if (nullp(linelength) /* =NIL -> yes, it fits */
  5703. || (posfixnum_to_V(TheStream(*stream_)->strm_pphelp_lpos) /* line-position */
  5704. + pphelp_string_width(block) /* width of the single-liner */
  5705. + (nullpSv(print_rpars) && matomp(Cdr(STACK_0))
  5706. ? posfixnum_to_V(Symbol_value(S(prin_prev_traillength))) /* SYS::*PRIN-PREV-TRAILLENGTH* */
  5707. : 0)
  5708. < posfixnum_to_V(linelength))) { /* < linelength ? */
  5709. /* stil fits.
  5710. print Space instead of Newline: */
  5711. write_ascii_char(stream_,' ');
  5712. } else { /* does not fit anymore. */
  5713. goto new_line;
  5714. }
  5715. } else { /* multi-liner -> new line and proceed */
  5716. new_line: /* start new line */
  5717. pphelp_newline(stream_); /* new line with Modus:=multi-liner */
  5718. spaces(stream_,Symbol_value(S(prin_lm))); /* SYS::*PRIN-LM* Spaces */
  5719. }
  5720. }
  5721. CHECK_LINES_LIMIT(break);
  5722. }
  5723. skipSTACK(2); /* forget empty remaining list and the old line-position */
  5724. /* unbind bindings of JUSTIFY_START: */
  5725. dynamic_unbind(S(prin_jblocks));
  5726. dynamic_unbind(S(prin_jblpos));
  5727. dynamic_unbind(S(prin_jbmodus));
  5728. dynamic_unbind(S(prin_jbstrings));
  5729. }
  5730. /* unbind bindings of JUSTIFY_START: */
  5731. dynamic_unbind(S(prin_traillength));
  5732. dynamic_unbind(S(prin_prev_traillength));
  5733. }
  5734. /* UP: finalizes a justify-block, determines the shape of the block and
  5735. prints its content to the old stream.
  5736. justify_end_linear(&stream);
  5737. > stream: stream
  5738. < stream: stream
  5739. can trigger GC */
  5740. local maygc void justify_end_linear (const gcv_object_t* stream_) {
  5741. if (!PPHELP_STREAM_P(*stream_)) { /* normal stream -> nothing to do */
  5742. } else { /* Pretty-Print-Help-Stream */
  5743. justify_empty_2(stream_); /* save stream content */
  5744. /* restore stream content, i.e. move the values of SYS::*PRIN-JBSTRINGS*,
  5745. SYS::*PRIN-JBMODUS*, SYS::*PRIN-JBLPOS* back into the stream: */
  5746. var object stream = *stream_;
  5747. /* save present line-position: */
  5748. pushSTACK(TheStream(stream)->strm_pphelp_lpos);
  5749. /* restore old stream content: */
  5750. TheStream(stream)->strm_pphelp_strings = Symbol_value(S(prin_jbstrings));
  5751. TheStream(stream)->strm_pphelp_modus = Symbol_value(S(prin_jbmodus));
  5752. TheStream(stream)->strm_pphelp_lpos = Symbol_value(S(prin_jblpos));
  5753. { /* check, if all the blocks in SYS::*PRIN-JBLOCKS* are single-liners: */
  5754. var object blocks = Symbol_value(S(prin_jblocks)); /* SYS::*PRIN-JBLOCKS* */
  5755. do { /* peruse (non-empty) block list: */
  5756. if (mconsp(Car(blocks))) /* is sub-block a multi-liner ? */
  5757. goto gesamt_mehrzeiler; /* yes -> block is a multi-liner altogether */
  5758. blocks = Cdr(blocks);
  5759. } while (consp(blocks));
  5760. }
  5761. /* check, if the blocks in SYS::*PRIN-JBLOCKS*
  5762. (each block is a single-liner) can result in a single-liner altogether:
  5763. Is L=NIL (no boundary restriction) or
  5764. L1 + (total width of blocks) + (number of blocks-1) + Traillength <= L ? */
  5765. {
  5766. var object linelength = right_margin();
  5767. if (nullp(linelength)) goto gesamt_einzeiler; /* =NIL -> single-liner */
  5768. var uintV totalneed = posfixnum_to_V(Symbol_value(S(prin_l1))); /* Sum := L1 = SYS::*PRIN-L1* */
  5769. var object blocks = Symbol_value(S(prin_jblocks)); /* SYS::*PRIN-JBLOCKS* */
  5770. do { /* peruse (non-empty) block list: */
  5771. var object block = Car(blocks); /* Block (single-liner) */
  5772. totalneed += pphelp_string_width(block) + 1; /* plus its width+1 */
  5773. blocks = Cdr(blocks);
  5774. } while (consp(blocks));
  5775. if (nullpSv(print_rpars))
  5776. totalneed += posfixnum_to_V(Symbol_value(S(prin_prev_traillength))); /* SYS::*PRIN-PREV-TRAILLENGTH* */
  5777. /* totalneed = L1 + (total width of blocks) + (number of blocks) + Traillength
  5778. compare this with linelength + 1 : */
  5779. if (totalneed <= posfixnum_to_V(linelength)+1)
  5780. goto gesamt_einzeiler;
  5781. else
  5782. goto gesamt_mehrzeiler;
  5783. }
  5784. gesamt_einzeiler: { /* a single-liner, altogether. */
  5785. /* print blocks apartly, separated by Spaces, to the stream: */
  5786. pushSTACK(nreverse(Symbol_value(S(prin_jblocks)))); /* (nreverse SYS::*PRIN-JBLOCKS*) */
  5787. while (1) { /* peruse (non-empty) block list STACK_0: */
  5788. var object block = Car(STACK_0); /* next block */
  5789. /* (a single-liner, string without #\Newline) */
  5790. STACK_0 = Cdr(STACK_0); /* shorten block list */
  5791. write_string(stream_,block); /* print block to the stream */
  5792. if (matomp(STACK_0)) /* remaining list empty -> done */
  5793. break;
  5794. write_ascii_char(stream_,' '); /* print #\Space */
  5795. }
  5796. } goto done;
  5797. gesamt_mehrzeiler: { /* a multi-liner, altogether. */
  5798. /* print blocks apartly, separated by Newline, to the stream: */
  5799. pushSTACK(nreverse(Symbol_value(S(prin_jblocks)))); /* (nreverse SYS::*PRIN-JBLOCKS*) */
  5800. while (1) { /* peruse (non-empty) block list STACK_0: */
  5801. var object block = Car(STACK_0); /* next block */
  5802. STACK_0 = Cdr(STACK_0); /* shorten block list */
  5803. if (consp(block)) { /* multi-line sub-block */
  5804. multi_line_sub_block_out(block,stream_);
  5805. } else { /* single-line sub-block */
  5806. /* print it on the PPHELP-stream: */
  5807. write_string(stream_,block);
  5808. }
  5809. if (matomp(STACK_0)) /* remaining list empty? */
  5810. break;
  5811. pphelp_newline(stream_); /* start new line */
  5812. spaces(stream_,Symbol_value(S(prin_lm))); /* SYS::*PRIN-LM* Spaces */
  5813. CHECK_LINES_LIMIT(break);
  5814. }
  5815. stream = *stream_;
  5816. /* restore line-position: */
  5817. TheStream(stream)->strm_pphelp_lpos = STACK_1;
  5818. /* GesamtModus := multi-liner: */
  5819. TheStream(stream)->strm_pphelp_modus = mehrzeiler;
  5820. } goto done;
  5821. done: /* line-position is now correct. */
  5822. skipSTACK(2); /* forget empty remaining list and the old line-position */
  5823. /* unbind bindings of JUSTIFY_START: */
  5824. dynamic_unbind(S(prin_jblocks));
  5825. dynamic_unbind(S(prin_jblpos));
  5826. dynamic_unbind(S(prin_jbmodus));
  5827. dynamic_unbind(S(prin_jbstrings));
  5828. }
  5829. /* unbind bindings of JUSTIFY_START: */
  5830. dynamic_unbind(S(prin_traillength));
  5831. dynamic_unbind(S(prin_prev_traillength));
  5832. }
  5833. /* Prepares the justification of the last item in a sequence of JUSTIFY_SPACE
  5834. separated items.
  5835. justify_last(); */
  5836. local void justify_last (void) {
  5837. /* SYS::*PRIN-TRAILLENGTH* := SYS::*PRIN-PREV-TRAILLENGTH* */
  5838. Symbol_value(S(prin_traillength)) = Symbol_value(S(prin_prev_traillength));
  5839. }
  5840. /* Indent
  5841. ------
  5842. in order to nest correctly, alway use INDENT_START and
  5843. INDENT_END each once at a time. */
  5844. #define INDENT_START(delta) indent_start(stream_,delta);
  5845. #define INDENT_END indent_end(stream_);
  5846. /* UP: Binds the left boundaries SYS::*PRIN-L1* and SYS::*PRIN-LM* to
  5847. values increased by delta.
  5848. indent_start(&stream,delta);
  5849. > delta: indentation value
  5850. > stream: stream
  5851. < stream: stream
  5852. changes STACK */
  5853. local void indent_start (const gcv_object_t* stream_, uintV delta) {
  5854. if (!PPHELP_STREAM_P(*stream_)) { /* normal stream -> nothing to do */
  5855. } else { /* Pretty-Print-Help-Stream */
  5856. { /* bind SYS::*PRIN-L1*: */
  5857. var object new_L1 = fixnum_inc(Symbol_value(S(prin_l1)),delta);
  5858. dynamic_bind(S(prin_l1),new_L1);
  5859. }
  5860. { /* bind SYS::*PRIN-LM*: */
  5861. var object new_LM = fixnum_inc(Symbol_value(S(prin_lm)),delta);
  5862. dynamic_bind(S(prin_lm),new_LM);
  5863. }
  5864. }
  5865. }
  5866. /* UP: finalizes an indent-block.
  5867. indent_end(&stream);
  5868. > stream: stream
  5869. < stream: stream
  5870. changes STACK */
  5871. local void indent_end (const gcv_object_t* stream_) {
  5872. if (!PPHELP_STREAM_P(*stream_)) { /* normal Stream -> nothing to do */
  5873. } else { /* Pretty-Print-Help-Stream */
  5874. /* unbind the two bindings of INDENT_START: */
  5875. dynamic_unbind(S(prin_lm));
  5876. dynamic_unbind(S(prin_l1));
  5877. }
  5878. }
  5879. /* Indent Preparation
  5880. ------------------
  5881. serves to indent a variable number of characters.
  5882. in order to nest correctly,
  5883. first INDENTPREP_START once,
  5884. then a couple of characters (no #\Newline!)
  5885. and then INDENTPREP_END once.
  5886. After that you can continue immediately with INDENT_START. */
  5887. #define INDENTPREP_START indentprep_start(stream_);
  5888. #define INDENTPREP_END indentprep_end(stream_);
  5889. /* UP: memorizes the present position.
  5890. indentprep_start(&stream);
  5891. > stream: stream
  5892. < stream: stream
  5893. changes STACK */
  5894. local void indentprep_start (const gcv_object_t* stream_) {
  5895. var object stream = *stream_;
  5896. if (!PPHELP_STREAM_P(stream)) { /* normal stream -> nothing to do */
  5897. } else { /* Pretty-Print-Help-Stream */
  5898. /* memorize line-position: */
  5899. pushSTACK(TheStream(stream)->strm_pphelp_lpos);
  5900. }
  5901. }
  5902. /* UP: subtracts the positions, returns the indentation width.
  5903. indentprep_end(&stream)
  5904. > stream: stream
  5905. < stream: stream
  5906. < result: indentation width
  5907. changes STACK */
  5908. local uintV indentprep_end (const gcv_object_t* stream_) {
  5909. var object stream = *stream_;
  5910. if (!PPHELP_STREAM_P(stream)) { /* normal stream -> nothing to do */
  5911. return 0;
  5912. } else { /* Pretty-Print-Help-Stream */
  5913. var uintV lpos_now = /* current line-position */
  5914. posfixnum_to_V(TheStream(stream)->strm_pphelp_lpos);
  5915. var uintV lpos_before = /* memorized line-position */
  5916. posfixnum_to_V(popSTACK());
  5917. return (lpos_now>=lpos_before ? lpos_now-lpos_before : 0);
  5918. }
  5919. }
  5920. /* ------------------ sub-routines for *PRINT-LEVEL* -----------------------
  5921. Level
  5922. -----
  5923. in order to nest correctly,
  5924. once LEVEL_CHECK at the beginning of a pr_xxx-routine
  5925. and once LEVEL_END at the end. */
  5926. #define LEVEL_CHECK { if (level_check(stream_)) return; }
  5927. #define LEVEL_END level_end(stream_);
  5928. /* UP: prints the representation of a LISP-object when
  5929. *PRINT-LEVEL* is exceeded.
  5930. pr_level(&stream);
  5931. > stream: stream
  5932. < stream: stream
  5933. can trigger GC */
  5934. #define pr_level(stream_) write_ascii_char(stream_,'#')
  5935. /* UP: tests, if SYS::*PRIN-LEVEL* has reached the value of *PRINT-LEVEL*.
  5936. if yes, only print '#' and jump back out of the calling sub-routine (!).
  5937. if no, bind incremented value of SYS::*PRIN-LEVEL*.
  5938. if (level_check(&stream)) return;
  5939. > stream: Stream
  5940. < stream: Stream
  5941. if yes: can trigger GC
  5942. if no: changes STACK */
  5943. local /*maygc*/ bool level_check (const gcv_object_t* stream_) {
  5944. var object level = Symbol_value(S(prin_level)); /* SYS::*PRIN-LEVEL*, a Fixnum >=0 */
  5945. var object limit = Symbol_value(S(print_level)); /* *PRINT-LEVEL* */
  5946. if (nullpSv(print_readably)
  5947. && posfixnump(limit) /* is there a limit? */
  5948. && (posfixnum_to_V(level) >= posfixnum_to_V(limit))) { /* reached it or exceeded it? */
  5949. /* yes -> print '#' and return: */
  5950. pr_level(stream_); return true;
  5951. } else { /* no -> *PRINT-LEVEL* not yet reached. */
  5952. /* bind SYS::*PRIN-LEVEL* to (1+ SYS::*PRIN-LEVEL*) : */
  5953. level = fixnum_inc(level,1); /* (incf level) */
  5954. dynamic_bind(S(prin_level),level);
  5955. return false;
  5956. }
  5957. }
  5958. /* UP: finalizes a block with increased SYS::*PRIN-LEVEL*.
  5959. level_end(&stream);
  5960. > stream: stream
  5961. < stream: stream
  5962. changes STACK */
  5963. local void level_end (const gcv_object_t* stream_) {
  5964. dynamic_unbind(S(prin_level));
  5965. }
  5966. /* ------------------ sub-routines for *PRINT-LENGTH* ----------------------
  5967. Length
  5968. ------
  5969. UP: returns the length limit for structured objects like e.g. lists.
  5970. get_print_length()
  5971. < result: length limit */
  5972. local uintL get_print_length (void) {
  5973. var object limit = Symbol_value(S(print_length)); /* *PRINT-LENGTH* */
  5974. return (nullpSv(print_readably)
  5975. && posfixnump(limit) /* a Fixnum >=0 ? */
  5976. #if (intVsize>intLsize)
  5977. && (posfixnum_to_V(limit) <= vbitm(intLsize)-1)
  5978. #endif
  5979. ? posfixnum_to_V(limit) /* yes */
  5980. : ~(uintL)0); /* no -> limit "infinite" */
  5981. }
  5982. /* UP: abbreviate the remainder with "..."
  5983. triple_dots(&stream);
  5984. > stream: stream
  5985. < stream: stream
  5986. can trigger GC */
  5987. local maygc void triple_dots (const gcv_object_t* stream_) {
  5988. JUSTIFY_LAST(true);
  5989. write_ascii_char(stream_,'.');
  5990. write_ascii_char(stream_,'.');
  5991. write_ascii_char(stream_,'.');
  5992. }
  5993. #define CHECK_LENGTH_LIMIT(test,finally) \
  5994. if (test) { triple_dots(stream_); finally; }
  5995. /* ------------------ sub-routines for *PRINT-LINES* ----------------------
  5996. UP: check whether we are the end of the rope for *PRINT-LINES*
  5997. check_lines_limit()
  5998. < result: true if it is time to print ".." and bail out */
  5999. local bool check_lines_limit (void) {
  6000. var object limit = Symbol_value(S(print_lines)); /* *PRINT-LINES* */
  6001. if (!nullpSv(print_readably) || !posfixnump(limit))
  6002. return false;
  6003. var object now = Symbol_value(S(prin_lines)); /* SYS::*PRIN-LINES* */
  6004. if (!posfixnump(now))
  6005. return true;
  6006. var uintV max_lines = posfixnum_to_V(limit);
  6007. var uintV cur_lines = posfixnum_to_V(now);
  6008. return max_lines <= cur_lines;
  6009. }
  6010. /* UP: abbreviate the remainder with ".."
  6011. double_dots(&stream);
  6012. > stream: stream
  6013. < stream: stream
  6014. can trigger GC */
  6015. local maygc void double_dots (const gcv_object_t* stream_) {
  6016. JUSTIFY_LAST(true);
  6017. /* if (!eq(Symbol_value(S(prin_lines)),S(Kend))) { */
  6018. write_ascii_char(stream_,'.');
  6019. write_ascii_char(stream_,'.');
  6020. /* Symbol_value(S(prin_lines)) = S(Kend); - do not print anything else
  6021. } */
  6022. }
  6023. /* ------------------ sub-routines for *PRINT-CIRCLE* ------------------------
  6024. UP: finds out, if an object has to be printed in #n= or #n#-
  6025. notation because of *PRINT-CIRCLE*.
  6026. circle_p(obj,circle_info_p)
  6027. > obj: object
  6028. < circle_info_p:
  6029. < return: false, if obj is to be printed normally
  6030. true, if obj is to be printed ABnormally
  6031. in the latter case, circle_info_p, if non-NULL, will contain
  6032. else: circle_info_p->flag: true, if obj is to be printed as #n=...
  6033. false, if obj is to be printed as #n#
  6034. circle_info_p->n: n
  6035. circle_info_p->ptr: in case of #n=... the fixnum *ptr has to be
  6036. incremented before output takes place. */
  6037. typedef struct {
  6038. bool flag;
  6039. uintL n;
  6040. gcv_object_t* ptr;
  6041. } circle_info_t;
  6042. local bool circle_p (object obj,circle_info_t* ci) {
  6043. /* check *PRINT-CIRCLE*: */
  6044. if (!nullpSv(print_circle)) {
  6045. var object table = Symbol_value(S(print_circle_table)); /* SYS::*PRINT-CIRCLE-TABLE* */
  6046. if (nullp(table)) /* no circularities were detected in object */
  6047. goto normal;
  6048. if (!simple_vector_p(table)) { /* should be a simple-vector! */
  6049. bad_table:
  6050. dynamic_bind(S(print_circle),NIL); /* bind *PRINT-CIRCLE* to NIL */
  6051. error_invalid_value(S(print_circle_table));
  6052. }
  6053. /* loop through the vector table = #(i ...) with m+1 (0<=i<=m) elements:
  6054. if obj is among the elements 1,...,i -> case false, n:=Index.
  6055. if obj is among the elements i+1,...,m -> move
  6056. obj to position i+1, case true, n:=i+1, afterwards i:=i+1.
  6057. else case NULL. */
  6058. var uintL m1 = Svector_length(table); /* length m+1 */
  6059. if (m1==0) goto bad_table; /* should be >0! */
  6060. var gcv_object_t* ptr = &TheSvector(table)->data[0]; /* pointer in the vector */
  6061. var uintV i = posfixnum_to_V(*ptr++); /* first element i */
  6062. var uintL index = 1;
  6063. for (; index < m1; index++) { /* run through the loop m times */
  6064. if (eq(*ptr++,obj)) /* compare obj with the next vector-element */
  6065. goto found;
  6066. }
  6067. /* not found -> done */
  6068. goto normal;
  6069. found: /* foundobj as vector-element index, 1 <= index <= m, */
  6070. /* ptr = &TheSvector(table)->data[index+1] . */
  6071. if (index <= i) { /* obj is to be printed as #n#, n=index. */
  6072. if (ci) { ci->flag = false; ci->n = index; }
  6073. return true;
  6074. } else { /* move obj to position i+1: */
  6075. i = i+1;
  6076. /* (rotatef (svref Vektor i) (svref Vektor index)) : */
  6077. {
  6078. var gcv_object_t* ptr_i = &TheSvector(table)->data[i];
  6079. *--ptr = *ptr_i; *ptr_i = obj;
  6080. }
  6081. /* obj is to be printed as #n=..., n=i. */
  6082. if (ci) {
  6083. ci->flag = true; ci->n = i;
  6084. ci->ptr = &TheSvector(table)->data[0]; /* increase i in the vector, afterwards */
  6085. }
  6086. return true;
  6087. }
  6088. }
  6089. normal: /* obj is to be printed normally */
  6090. return false;
  6091. }
  6092. /* UP: verifies, if an object is circular, and prints it in
  6093. this case as #n#or with #n=-prefix (and otherwise normally).
  6094. pr_circle(&stream,obj,&pr_xxx);
  6095. > obj: object
  6096. > pr_xxx: printing-routine, which receives &stream und obj as arguments
  6097. > stream: stream
  6098. < stream: stream
  6099. can trigger GC */
  6100. local maygc void pr_circle (const gcv_object_t* stream_, object obj, pr_routine_t* pr_xxx) {
  6101. /* determine, if circular: */
  6102. var circle_info_t info;
  6103. if (!circle_p(obj,&info)) { /* not circular, print obj normally: */
  6104. (*pr_xxx)(stream_,obj);
  6105. } else { /* circular */
  6106. if (info.flag) { /* print obj as #n=...: */
  6107. { /* first increment the fixnum in the vector for circle_p: */
  6108. var gcv_object_t* ptr = info.ptr;
  6109. *ptr = fixnum_inc(*ptr,1);
  6110. }
  6111. {
  6112. var uintL n = info.n;
  6113. pushSTACK(obj); /* save obj */
  6114. /* print prefix and calculate indentation depth: */
  6115. INDENTPREP_START;
  6116. write_ascii_char(stream_,'#');
  6117. pr_uint(stream_,n);
  6118. write_ascii_char(stream_,'=');
  6119. }
  6120. {
  6121. var uintV indent = INDENTPREP_END;
  6122. obj = popSTACK(); /* return obj */
  6123. /* print obj (indented): */
  6124. INDENT_START(indent);
  6125. (*pr_xxx)(stream_,obj);
  6126. INDENT_END;
  6127. }
  6128. } else { /* print obj as #n#: */
  6129. var uintL n = info.n;
  6130. write_ascii_char(stream_,'#');
  6131. pr_uint(stream_,n);
  6132. write_ascii_char(stream_,'#');
  6133. }
  6134. }
  6135. }
  6136. /* ------------------------ Entering the printer ------------------------------- */
  6137. /* UP: return the number of spaces available on the current line in this stream
  6138. NIL means unlimited
  6139. can trigger GC */
  6140. local maygc object space_available (object stream) {
  6141. var object line_pos = get_line_position(stream);
  6142. if (!posfixnump(line_pos)) return NIL;
  6143. var uintV pos = posfixnum_to_V(line_pos);
  6144. var object prm = right_margin();
  6145. if (!posfixnump(prm)) return NIL;
  6146. var uintV mar = posfixnum_to_V(prm);
  6147. if (mar < pos) return Fixnum_0;
  6148. return fixnum(mar-pos);
  6149. }
  6150. /* UP: return the total length of all the strings in the PPHELP stream
  6151. return NIL if this is a multi-liner */
  6152. local object pphelp_length (object pph_stream) {
  6153. #if IO_DEBUG > 0
  6154. PPH_OUT(pphelp_length,pph_stream);
  6155. #endif
  6156. if (eq(TheStream(pph_stream)->strm_pphelp_modus,mehrzeiler))
  6157. return NIL;
  6158. var uintL ret = 0;
  6159. var object list = Cdr(TheStream(pph_stream)->strm_pphelp_strings);
  6160. while (mconsp(list)) {
  6161. var object top = Car(list); list = Cdr(list); /* (pop list) */
  6162. if (stringp(top)) ret += vector_length(top);
  6163. else if (vectorp(top)) ret += PPH_FORMAT_TAB(pph_stream,top);
  6164. else if (mconsp(top)) {
  6165. if (nullp(Car(top))) { /* mandatory newline */
  6166. TheStream(pph_stream)->strm_pphelp_modus = mehrzeiler;
  6167. return NIL;
  6168. }
  6169. } /* else if (posfixnump(top)) ret += posfixnum_to_V(top); */
  6170. else NOTREACHED;
  6171. }
  6172. return fixnum(ret);
  6173. }
  6174. /* UP: check whether the string fits into the current line in the stream
  6175. return true iff the next object does fit
  6176. can trigger GC */
  6177. local maygc inline bool string_fit_line_p (const gcv_object_t *stream_,
  6178. object list, uintL offset) {
  6179. pushSTACK(list); /* save list*/
  6180. var object avail = space_available(*stream_);
  6181. list = popSTACK(); /* restore list */
  6182. if (nullp(avail)) return true; /* unlimited space available */
  6183. var uintL len;
  6184. var object top = Car(list); list = Cdr(list); /* (pop list) */
  6185. if (stringp(top)) len = vector_length(top);
  6186. else if (mconsp(top)) return true;
  6187. else if (vectorp(top)) {
  6188. len = PPH_FORMAT_TAB(*stream_,top);
  6189. while (mconsp(list) && !stringp(Car(list))) list = Cdr(list);
  6190. if (mconsp(list)) len += vector_length(Car(list)); /* string! */
  6191. else return false; /* do not need to print this tab */
  6192. } else NOTREACHED;
  6193. return posfixnum_to_V(avail) >= len + offset;
  6194. }
  6195. /* UP: Binds the variables of the printer and then calls a printer-routine.
  6196. pr_enter(&stream,obj,&pr_xxx);
  6197. > obj: object
  6198. > pr_xxx: printing-routine, which receives &stream and obj as arguments
  6199. > stream: stream
  6200. < stream: stream
  6201. can trigger GC
  6202. first of all only treatment of *PRINT-PRETTY*: */
  6203. local maygc void pr_enter_1 (const gcv_object_t* stream_, object obj,
  6204. pr_routine_t* pr_xxx) {
  6205. /* Streamtype (PPHELP-stream or not) must fit to *PRINT-PRETTY* . */
  6206. if (!nullpSv(print_pretty)) {
  6207. /* *PRINT-PRETTY* /= NIL.
  6208. if *stream_ is no PPHELP-Stream,
  6209. it must be replaced by a PPHELP-stream: */
  6210. if (!PPHELP_STREAM_P(*stream_)) { /* still a normal stream */
  6211. dynamic_bind(S(prin_l1),Fixnum_0); /* bind SYS::*PRIN-L1* to 0 */
  6212. dynamic_bind(S(prin_lm),Fixnum_0); /* bind SYS::*PRIN-LM* to 0 */
  6213. pushSTACK(obj); /* save object */
  6214. { /* Place SYS::*PRIN-L1* to its line-position: */
  6215. var object linepos = get_line_position(*stream_);
  6216. if (!posfixnump(linepos))
  6217. linepos = Fixnum_0;
  6218. Symbol_value(S(prin_l1)) = linepos;
  6219. }
  6220. pushSTACK(make_pphelp_stream()); /* new PPHELP-Stream, line-position = 0 */
  6221. if (stream_get_fasl(*stream_)) /* adopt FASL-Bit */
  6222. TheStream(STACK_0)->strmflags |= bit(strmflags_fasl_bit_B);
  6223. /* print object to the new stream: */
  6224. pr_xxx(&STACK_0,STACK_1);
  6225. var bool skip_first_nl = false;
  6226. var bool modus_single_p;
  6227. { /* print content of the new stream to the old stream: */
  6228. var object ppstream = popSTACK(); /* the new stream */
  6229. STACK_0 = nreverse(TheStream(ppstream)->strm_pphelp_strings);
  6230. TheStream(ppstream)->strm_pphelp_strings = STACK_0;
  6231. /* if it has become a multi-liner that does not start with a
  6232. Newline, and the old line-position is >0 ,
  6233. print a Newline to the old stream first: */
  6234. { var object firststring = Car(Cdr(STACK_0)); /* first line */
  6235. if (stringp(firststring)
  6236. && ((TheIarray(firststring)->dims[1] == 0) /* empty? */
  6237. || chareq(TheSnstring(TheIarray(firststring)->data)->data[0],
  6238. ascii(NL)))) /* or Newline at the beginning? */
  6239. skip_first_nl = true;
  6240. }
  6241. if (eq(Symbol_value(S(prin_l1)),Fixnum_0)) /* or at position 0 ? */
  6242. skip_first_nl = true;
  6243. if (nullpSv(pprint_first_newline)) /* use asked: no first newlines */
  6244. skip_first_nl = true;
  6245. if (nullp(Cdr(Cdr(STACK_0)))) { /* DEFINITELY a single-liner */
  6246. skip_first_nl = true;
  6247. } else { /* several lines, maybe still a single-liner? */
  6248. /* if modus is mehrzeiler, we KNOW it is so
  6249. if it is einzeiler, it might have :LINEAR newlines */
  6250. var object pphs_len = pphelp_length(ppstream);
  6251. var object prm = right_margin();
  6252. var bool fit_this_line = !nullp(pphs_len);
  6253. if (posfixnump(pphs_len) /* could POSSIBLY be a single-liner */
  6254. && posfixnump(prm)) { /* have right margin */
  6255. var uintV pphs_len_i = posfixnum_to_V(pphs_len);
  6256. var uintV prm_i = posfixnum_to_V(prm);
  6257. var uintV pos_i = posfixnum_to_V(Symbol_value(S(prin_l1)));
  6258. fit_this_line = (pphs_len_i <= (prm_i - pos_i));
  6259. if (pphs_len_i > prm_i)
  6260. TheStream(ppstream)->strm_pphelp_modus = mehrzeiler;
  6261. if (fit_this_line)
  6262. skip_first_nl = true;
  6263. }
  6264. if (skip_first_nl && !fit_this_line)
  6265. TheStream(ppstream)->strm_pphelp_modus = mehrzeiler;
  6266. }
  6267. modus_single_p = eq(TheStream(ppstream)->strm_pphelp_modus,einzeiler);
  6268. #if IO_DEBUG > 0
  6269. PPH_OUT(pr_enter_1,ppstream);
  6270. #endif
  6271. }
  6272. if (skip_first_nl) {
  6273. pprint_prefix(stream_,PPHELP_INDENTN(Car(STACK_0)));
  6274. STACK_0 = Cdr(STACK_0);
  6275. goto skip_NL;
  6276. } else STACK_0 = Cdr(STACK_0);
  6277. /* Symbol_value(S(prin_lines)) = Fixnum_0; */
  6278. do { /* NL & indent */
  6279. { var object top = Car(STACK_0);
  6280. var object indent = Fixnum_0;
  6281. if (mconsp(top)) { /* if :FILL and the next string fits the line */
  6282. if (modus_single_p
  6283. || (eq(PPHELP_NL_TYPE(top),S(Kfill))
  6284. && string_fit_line_p(stream_,Cdr(STACK_0),0))) {
  6285. STACK_0 = Cdr(STACK_0);
  6286. goto skip_NL;
  6287. }
  6288. indent = PPHELP_INDENTN(Car(STACK_0)/*top*/);
  6289. STACK_0 = Cdr(STACK_0);
  6290. if (!mconsp(STACK_0)) break; /* end of stream */
  6291. } else if (!stringp(top)) { /* tab - a vector but not a string */
  6292. STACK_0 = Cdr(STACK_0);
  6293. if (!mconsp(STACK_0)) break; /* end of stream */
  6294. /* if the next object is not a NL then indent */
  6295. var uintL num_space = PPH_FORMAT_TAB(*stream_,top);
  6296. if (modus_single_p || stringp(Car(STACK_0))
  6297. || (mconsp(Car(STACK_0)) /* ignored NL */
  6298. && (eq(PPHELP_NL_TYPE(Car(STACK_0)),S(Kfill))
  6299. && string_fit_line_p(stream_,Cdr(STACK_0),num_space)))){
  6300. spaces(stream_,fixnum(num_space));
  6301. goto skip_NL;
  6302. } else if (mconsp(Car(STACK_0))) /* set indent */
  6303. indent = PPHELP_INDENTN(Car(STACK_0));
  6304. }
  6305. write_ascii_char(stream_,NL); /* #\Newline as the line separator */
  6306. pprint_prefix(stream_,indent); /* line prefix & indentation, if any */
  6307. /* LINES_INC; */
  6308. /* CHECK_LINES_LIMIT(break); */
  6309. }
  6310. skip_NL: { /* print first element, if string */
  6311. var object top = Car(STACK_0);
  6312. if (stringp(top)) {
  6313. write_string(stream_,top); /* print single String */
  6314. STACK_0 = Cdr(STACK_0);
  6315. }
  6316. }
  6317. } while (mconsp(STACK_0));
  6318. /* if we are here because of *PRINT-LINES*, we should print the suffix
  6319. if (mconsp(STACK_0)) {
  6320. while (!nullp(Cdr(STACK_0))) STACK_0 = Cdr(STACK_0);
  6321. if (stringp(Car(STACK_0))) write_string(stream_,Car(STACK_0));
  6322. } */
  6323. skipSTACK(1); /* strm_pphelp_strings */
  6324. dynamic_unbind(S(prin_lm));
  6325. dynamic_unbind(S(prin_l1));
  6326. } else { /* already a PPHELP-stream */
  6327. pr_xxx(stream_,obj);
  6328. }
  6329. } else { /* *PRINT-PRETTY* = NIL. */
  6330. /* if *stream_ is a PPHELP-Stream, it must be replaced by a
  6331. single-element broadcast-stream : */
  6332. if (!PPHELP_STREAM_P(*stream_)) { /* normal stream */
  6333. (*pr_xxx)(stream_,obj);
  6334. } else { /* a PPHELP-stream */
  6335. pushSTACK(obj);
  6336. pushSTACK(make_broadcast1_stream(*stream_)); /* broadcast-stream to the stream *stream_ */
  6337. (*pr_xxx)(&STACK_0,STACK_1);
  6338. skipSTACK(2);
  6339. }
  6340. }
  6341. }
  6342. /* the same procedure with treatment of *PRINT-CIRCLE* and *PRINT-PRETTY* : */
  6343. local void pr_enter_2 (const gcv_object_t* stream_, object obj, pr_routine_t* pr_xxx) {
  6344. /* if *PRINT-CIRCLE* /= NIL, search in obj for circularities. */
  6345. if (!nullpSv(print_circle) || !nullpSv(print_readably)) {
  6346. /* search circularities: */
  6347. pushSTACK(obj);
  6348. var object circularities = /* table of circularities */
  6349. get_circularities(obj,
  6350. !nullpSv(print_array) || !nullpSv(print_readably), /* /= 0 if, and only if *PRINT-ARRAY* /= NIL */
  6351. !nullpSv(print_closure) || !nullpSv(print_readably)); /* /= 0 and only if *PRINT-CLOSURE* /= NIL */
  6352. obj = popSTACK();
  6353. if (nullp(circularities) /* no circularities found */
  6354. && nullpSv(print_readably)) { /* no need for printable output */
  6355. /* can bind *PRINT-CIRCLE* to NIL. */
  6356. dynamic_bind(S(print_circle),NIL);
  6357. pr_enter_1(stream_,obj,pr_xxx);
  6358. dynamic_unbind(S(print_circle));
  6359. } else if (eq(circularities,T)) { /* stack overflow occurred */
  6360. /* handle overflow of the GET_CIRCULARITIES-routine: */
  6361. dynamic_bind(S(print_circle),NIL); /* bind *PRINT-CIRCLE* to NIL */
  6362. pushSTACK(S(print));
  6363. error(storage_condition,
  6364. GETTEXT("~S: not enough stack space for carrying out circularity analysis"));
  6365. } else { /* circularity vector */
  6366. /* Bind SYS::*PRINT-CIRCLE-TABLE* to the Simple-Vector: */
  6367. dynamic_bind(S(print_circle_table),circularities);
  6368. if (nullpSv(print_circle)) {
  6369. /* *PRINT-READABLY* enforces *PRINT-CIRCLE* = T */
  6370. dynamic_bind(S(print_circle),T);
  6371. pr_enter_1(stream_,obj,pr_xxx);
  6372. dynamic_unbind(S(print_circle));
  6373. } else {
  6374. pr_enter_1(stream_,obj,pr_xxx);
  6375. }
  6376. dynamic_unbind(S(print_circle_table));
  6377. }
  6378. } else {
  6379. pr_enter_1(stream_,obj,pr_xxx);
  6380. }
  6381. }
  6382. /* The same routine with treatment of *PRINT-CIRCLE*, *PRINT-PRETTY*
  6383. and SYS::*PRIN-STREAM* : */
  6384. local void pr_enter (const gcv_object_t* stream_, object obj,
  6385. pr_routine_t* pr_xxx) {
  6386. /* value of SYS::*PRIN-STREAM* = this stream ? */
  6387. if (eq(Symbol_value(S(prin_stream)),*stream_)) { /* yes -> recursive call */
  6388. /* if SYS::*PRINT-CIRCLE-TABLE* = #<UNBOUND> (which means, that
  6389. *PRINT-CIRCLE* was NIL beforehand) and now *PRINT-CIRCLE* /= NIL,
  6390. object obj must be scanned for circularities. */
  6391. if (!boundp(Symbol_value(S(print_circle_table)))) {
  6392. pr_enter_2(stream_,obj,pr_xxx);
  6393. } else {
  6394. pr_enter_1(stream_,obj,pr_xxx);
  6395. }
  6396. } else { /* no -> non-recursive call */
  6397. #if STACKCHECKP
  6398. var gcv_object_t* STACKbefore = STACK; /* save STACK for later */
  6399. #endif
  6400. dynamic_bind(S(prin_level),Fixnum_0); /* bind SYS::*PRIN-LEVEL* to 0 */
  6401. dynamic_bind(S(prin_lines),Fixnum_0); /* bind SYS::*PRIN-LINES* to 0 */
  6402. dynamic_bind(S(prin_bqlevel),Fixnum_0); /* bind SYS::*PRIN-BQLEVEL* to 0 */
  6403. dynamic_bind(S(prin_l1),Fixnum_0); /* bind SYS::*PRIN-L1* to 0 (for Pretty-Print) */
  6404. dynamic_bind(S(prin_lm),Fixnum_0); /* bind SYS::*PRIN-LM* to 0 (for Pretty-Print) */
  6405. dynamic_bind(S(prin_traillength),Fixnum_0); /* bind SYS::*PRIN-TRAILLENGTH* */
  6406. pr_enter_2(stream_,obj,pr_xxx);
  6407. dynamic_unbind(S(prin_traillength)); /* SYS::*PRIN-TRAILLENGTH* */
  6408. dynamic_unbind(S(prin_lm)); /* SYS::*PRIN-LM* */
  6409. dynamic_unbind(S(prin_l1)); /* SYS::*PRIN-L1* */
  6410. dynamic_unbind(S(prin_bqlevel)); /* SYS::*PRIN-BQLEVEL* */
  6411. dynamic_unbind(S(prin_lines)); /* SYS::*PRIN-LINES* */
  6412. dynamic_unbind(S(prin_level)); /* SYS::*PRIN-LEVEL* */
  6413. #if STACKCHECKP
  6414. /* check, if Stack is cleaned: */
  6415. if (!(STACK == STACKbefore))
  6416. abort(); /* if not, go to Debugger */
  6417. #endif
  6418. }
  6419. }
  6420. /* --------------- Leaving the printer through an external call ------------
  6421. preparation of the call of an external print-function
  6422. pr_external_1(stream)
  6423. > stream: stream
  6424. < result: number of dynamic bindings, that have to be unbound. */
  6425. local uintC pr_external_1 (object stream) {
  6426. var uintC count = 1;
  6427. /* bind SYM to VAL unless already bound to it */
  6428. #define BIND_UNLESS(sym,val) \
  6429. if (!eq(Symbol_value(S(sym)),val)) { dynamic_bind(S(sym),val); count++; }
  6430. /* obey *PRINT-CIRCLE*: */
  6431. if (nullpSv(print_circle)) { /* *PRINT-CIRCLE* = NIL -> */
  6432. /* in case, that *PRINT-CIRCLE* will be bound to T,
  6433. SYS::*PRINT-CIRCLE-TABLE* must be bound to #<UNBOUND>
  6434. (unless, it is already = #<UNBOUND>). */
  6435. BIND_UNLESS(print_circle_table,unbound);
  6436. }
  6437. /* obey *PRINT-READABLY*: */
  6438. if (!nullpSv(print_readably)) {
  6439. /* for the user-defined print-functions, which do not yet know
  6440. of *PRINT-READABLY*, to behave accordingly,
  6441. we bind the other printer-variables appropriately:
  6442. *PRINT-READABLY* enforces *PRINT-ESCAPE* = T : */
  6443. BIND_UNLESS(print_escape,T);
  6444. /* *PRINT-READABLY* enforces *PRINT-BASE* = 10 : */
  6445. BIND_UNLESS(print_base,fixnum(10));
  6446. /* *PRINT-READABLY* enforces *PRINT-RADIX* = T : */
  6447. BIND_UNLESS(print_radix,T);
  6448. /* *PRINT-READABLY* enforces *PRINT-CIRCLE* = T : */
  6449. BIND_UNLESS(print_circle,T);
  6450. /* *PRINT-READABLY* enforces *PRINT-LEVEL* = NIL : */
  6451. BIND_UNLESS(print_level,NIL);
  6452. /* *PRINT-READABLY* enforces *PRINT-LENGTH* = NIL : */
  6453. BIND_UNLESS(print_length,NIL);
  6454. /* *PRINT-READABLY* enforces *PRINT-LINES* = NIL : */
  6455. BIND_UNLESS(print_lines,NIL);
  6456. /* *PRINT-READABLY* enforces *PRINT-MISER-WIDTH* = NIL : */
  6457. BIND_UNLESS(print_miser_width,NIL);
  6458. /* *PRINT-READABLY* enforces *PRINT-PPRINT-DISPATCH* = NIL : */
  6459. BIND_UNLESS(print_pprint_dispatch,NIL);
  6460. /* *PRINT-READABLY* enforces *PRINT-GENSYM* = T : */
  6461. BIND_UNLESS(print_gensym,T);
  6462. /* *PRINT-READABLY* enforces *PRINT-ARRAY* = T : */
  6463. BIND_UNLESS(print_array,T);
  6464. /* *PRINT-READABLY* enforces *PRINT-CLOSURE* = T : */
  6465. BIND_UNLESS(print_closure,T);
  6466. }
  6467. #undef BIND_UNLESS
  6468. /* SYS::*PRIN-STREAM* an stream binden: */
  6469. dynamic_bind(S(prin_stream),stream);
  6470. return count;
  6471. }
  6472. /* postprocessing after the call of an external print-function
  6473. pr_external_2(count);
  6474. > count: number of dynamic bindungs, that have to be unbound. */
  6475. #define pr_external_2(countvar) \
  6476. dotimespC(countvar,countvar, { dynamic_unbind_g(); } );
  6477. /* ------------------------ Main-PRINT-routine --------------------------- */
  6478. /* here are the particular pr_xxx-routines: */
  6479. local pr_routine_t prin_object;
  6480. local pr_routine_t prin_object_dispatch;
  6481. local pr_routine_t pr_symbol;
  6482. local void pr_symbol_part (const gcv_object_t* stream_, object string,
  6483. bool case_sensitive, bool case_inverted);
  6484. local pr_routine_t pr_like_symbol;
  6485. local pr_routine_t pr_character;
  6486. local pr_routine_t pr_string;
  6487. local pr_routine_t pr_list;
  6488. local pr_routine_t pr_cons;
  6489. local pr_routine_t pr_list_quote;
  6490. local pr_routine_t pr_list_function;
  6491. local pr_routine_t pr_list_backquote;
  6492. local pr_routine_t pr_list_splice;
  6493. local pr_routine_t pr_list_nsplice;
  6494. local pr_routine_t pr_list_unquote;
  6495. local pr_routine_t pr_real_number;
  6496. local pr_routine_t pr_number;
  6497. local pr_routine_t pr_array_nil;
  6498. local pr_routine_t pr_bvector;
  6499. local pr_routine_t pr_vector;
  6500. local pr_routine_t pr_nilvector;
  6501. local pr_routine_t pr_array;
  6502. local pr_routine_t pr_instance;
  6503. local pr_routine_t pr_structure;
  6504. local pr_routine_t pr_machine;
  6505. local pr_routine_t pr_system;
  6506. local pr_routine_t pr_readlabel;
  6507. local pr_routine_t pr_framepointer;
  6508. local pr_routine_t pr_orecord;
  6509. local pr_routine_t pr_subr;
  6510. local pr_routine_t pr_fsubr;
  6511. local pr_routine_t pr_closure;
  6512. local pr_routine_t pr_cclosure;
  6513. local pr_routine_t pr_cclosure_lang;
  6514. local pr_routine_t pr_cclosure_codevector;
  6515. local pr_routine_t pr_stream;
  6516. /* UP: prints object to Stream.
  6517. prin_object_ki(&stream,obj,pr_routine);
  6518. > obj: object
  6519. > stream: stream
  6520. > pr_routine: printer
  6521. < stream: stream
  6522. can trigger GC */
  6523. local maygc void prin_object_ki (const gcv_object_t* stream_, object obj,
  6524. pr_routine_t *printer) {
  6525. restart_it:
  6526. interruptp({ /* test for keyboard-interrupt: */
  6527. pushSTACK(obj); /* save obj in the STACK; the stream is safe */
  6528. pushSTACK(S(print)); tast_break(); /* PRINT call break-loop */
  6529. obj = popSTACK(); /* move obj back */
  6530. goto restart_it;
  6531. });
  6532. check_SP(); check_STACK(); /* test for stack overflow */
  6533. pr_circle(stream_,obj,printer); /* handle circularity */
  6534. }
  6535. local maygc void prin_object (const gcv_object_t* stream_, object obj)
  6536. { prin_object_ki(stream_,obj,&prin_object_dispatch); }
  6537. local void prin_object_dispatch_low (const gcv_object_t* stream_, object obj) {
  6538. /* branch according to type-info: */
  6539. #ifdef TYPECODES
  6540. switch (typecode(obj)) {
  6541. case_machine: /* machine pointer */
  6542. pr_machine(stream_,obj); break;
  6543. case_string: /* String */
  6544. pr_string(stream_,obj); break;
  6545. case_bvector: /* Bit-Vector */
  6546. pr_bvector(stream_,obj); break;
  6547. case_b2vector:
  6548. case_b4vector:
  6549. case_b8vector:
  6550. case_b16vector:
  6551. case_b32vector:
  6552. case_vector: /* (vector t) */
  6553. pr_vector(stream_,obj); break;
  6554. case_mdarray: /* generic array */
  6555. pr_array(stream_,obj); break;
  6556. case_closure: /* Closure */
  6557. pr_closure(stream_,obj); break;
  6558. case_instance: /* CLOS-instance */
  6559. pr_instance(stream_,obj); break;
  6560. #ifdef case_structure
  6561. case_structure: /* Structure */
  6562. pr_structure(stream_,obj); break;
  6563. #endif
  6564. #ifdef case_stream
  6565. case_stream: /* Stream */
  6566. pr_stream(stream_,obj); break;
  6567. #endif
  6568. case_orecord: /* OtherRecord */
  6569. case_lrecord: /* LongRecord */
  6570. pr_orecord(stream_,obj); break;
  6571. case_char: /* Character */
  6572. pr_character(stream_,obj); break;
  6573. case_subr: /* SUBR */
  6574. pr_subr(stream_,obj); break;
  6575. case_system: /* Frame-Pointer, Small-Read-Label, System */
  6576. if (as_oint(obj) & wbit(0 + oint_addr_shift)) {
  6577. if (as_oint(obj) & wbit(oint_data_len-1 + oint_addr_shift)) {
  6578. /* System-Pointer */
  6579. pr_system(stream_,obj);
  6580. } else {
  6581. /* Small-Read-Label */
  6582. pr_readlabel(stream_,obj);
  6583. }
  6584. } else { /* Frame-Pointer */
  6585. pr_framepointer(stream_,obj);
  6586. }
  6587. break;
  6588. case_number: /* Number */
  6589. pr_number(stream_,obj); break;
  6590. case_symbol: /* Symbol */
  6591. pr_symbol(stream_,obj); break;
  6592. case_cons: /* Cons */
  6593. pr_cons(stream_,obj); break;
  6594. default: NOTREACHED;
  6595. }
  6596. #else
  6597. if (orecordp(obj))
  6598. pr_orecord(stream_,obj);
  6599. else if (consp(obj))
  6600. pr_cons(stream_,obj);
  6601. else if (immediate_number_p(obj))
  6602. pr_number(stream_,obj);
  6603. else if (charp(obj))
  6604. pr_character(stream_,obj);
  6605. else if (immsubrp(obj))
  6606. pr_subr(stream_,obj);
  6607. else if (machinep(obj))
  6608. pr_machine(stream_,obj);
  6609. else if (small_read_label_p(obj))
  6610. pr_readlabel(stream_,obj);
  6611. else if (systemp(obj))
  6612. pr_system(stream_,obj);
  6613. else
  6614. NOTREACHED;
  6615. #endif
  6616. }
  6617. /* call the appropriate function */
  6618. local void prin_object_dispatch_pretty (const gcv_object_t* stream_, object obj)
  6619. { var object ppp_disp = Symbol_value(S(print_pprint_dispatch));
  6620. /* check whether ppp_disp is a valid non-empty Dispatch Table */
  6621. if (mconsp(ppp_disp) && eq(Car(ppp_disp),S(print_pprint_dispatch))
  6622. && !nullp(Cdr(ppp_disp))) {
  6623. /* Call (PPRINT-DISPATCH obj): */
  6624. pushSTACK(obj); /* save */
  6625. pushSTACK(obj); funcall(S(pprint_dispatch),1);
  6626. obj = popSTACK(); /* restore */
  6627. if (!nullp(value2)) {
  6628. pushSTACK(*stream_); pushSTACK(obj); funcall(value1,2);
  6629. return;
  6630. }
  6631. }
  6632. prin_object_dispatch_low(stream_,obj); /* default printing */
  6633. }
  6634. local void maygc prin_object_dispatch (const gcv_object_t* stream_, object obj)
  6635. { if (!nullpSv(print_pretty))
  6636. prin_object_dispatch_pretty(stream_,obj);
  6637. else prin_object_dispatch_low(stream_,obj);
  6638. }
  6639. /* ------------- PRINT-Routines for various data-types -------------------- */
  6640. /* -------- Symbols -------- */
  6641. /* UP: print a symbol into a stream
  6642. pr_symbol(&stream,sym);
  6643. > sym: symbol
  6644. > stream: stream
  6645. < stream: stream
  6646. can trigger GC */
  6647. local maygc void pr_symbol (const gcv_object_t* stream_, object sym) {
  6648. /* query *PRINT-ESCAPE*: */
  6649. if (!nullpSv(print_escape) || !nullpSv(print_readably)) {
  6650. /* with escape-characters and maybe package-name: */
  6651. var bool case_sensitive = false;
  6652. var bool case_inverted = false;
  6653. pushSTACK(sym); /* save symbol */
  6654. if (keywordp(sym)) { /* Keyword ? */
  6655. write_ascii_char(stream_,':');
  6656. } else {
  6657. var object curr_pack = get_current_package();
  6658. sym = STACK_0; /* restore */
  6659. var object home = Symbol_package(sym); /* home-package of the symbol */
  6660. if (nullp(home)) { /* print uninterned symbol */
  6661. /* query *PRINT-GENSYM*: */
  6662. if (!nullpSv(print_gensym) || !nullpSv(print_readably)) {
  6663. /* use syntax #:name */
  6664. write_ascii_char(stream_,'#');
  6665. write_ascii_char(stream_,':');
  6666. } /* else print without prefix */
  6667. } else {
  6668. if (accessiblep(sym,curr_pack)
  6669. /* When *PRINT-READABLY*, print PACK::SYMBOL even when the symbol is
  6670. accessible. This is to satisfy the contract of *PRINT-READABLY*,
  6671. but is also useful when writing .fas files. */
  6672. && nullpSv(print_readably)) {
  6673. /* if symbol is accessible and not shadowed,
  6674. print no package-name and no package-markers. */
  6675. case_sensitive = pack_casesensitivep(curr_pack);
  6676. case_inverted = pack_caseinvertedp(curr_pack);
  6677. } else {
  6678. { /* print symbol with package-name and 1 or 2 package-markers */
  6679. pushSTACK(home); /* save home-package */
  6680. pr_symbol_part(stream_, /* print package-name */
  6681. ((nullpSv(print_symbol_package_prefix_shortest)
  6682. || !nullpSv(print_readably))
  6683. ? ThePackage(home)->pack_name
  6684. : ThePackage(home)->pack_shortest_name),
  6685. false,false);
  6686. home = popSTACK(); /* move home-package back */
  6687. case_sensitive = pack_casesensitivep(home);
  6688. case_inverted = pack_caseinvertedp(home);
  6689. if (!externalp(STACK_0,home)
  6690. /* When *PRINT-READABLY*, print PACK::SYMBOL even when the
  6691. symbol is external. It may not be external when the
  6692. output is read later. */
  6693. || !nullpSv(print_readably))
  6694. write_ascii_char(stream_,':'); /* yes -> 2 package-markers */
  6695. }
  6696. write_ascii_char(stream_,':');
  6697. }
  6698. }
  6699. }
  6700. sym = popSTACK(); /* move sym back */
  6701. pr_symbol_part(stream_,Symbol_name(sym),case_sensitive,case_inverted); /* print symbol-name */
  6702. } else {
  6703. /* Print symbol without escape-characters:
  6704. print only the symbol-name under control of *PRINT-CASE* */
  6705. write_sstring_case(stream_,Symbol_name(sym));
  6706. }
  6707. }
  6708. /* print #\Newline/#\Return as \n/\r
  6709. > stream: stream
  6710. > c: character
  6711. > pending_newline: is a newline pending due to previous \n/\r?
  6712. < pending_newline: is a newline now pending?
  6713. < return: are we done with this character?
  6714. can trigger GC */
  6715. local inline maygc bool pr_fasl_special (const gcv_object_t* stream_, chart c,
  6716. bool *pending_newline) {
  6717. if (chareq(c,ascii(0x0A))) {
  6718. write_ascii_char(stream_,'\\');
  6719. write_ascii_char(stream_,'n');
  6720. *pending_newline = true;
  6721. return true;
  6722. }
  6723. if (chareq(c,ascii(0x0D))) {
  6724. write_ascii_char(stream_,'\\');
  6725. write_ascii_char(stream_,'r');
  6726. *pending_newline = true;
  6727. return true;
  6728. }
  6729. if (*pending_newline) {
  6730. write_ascii_char(stream_,NL);
  6731. *pending_newline = false;
  6732. }
  6733. return false;
  6734. }
  6735. /* UP: prints part of a symbol (package-name or symbol-name) with Escape-Character
  6736. pr_symbol_part(&stream,string,case_sensitive,case_inverted);
  6737. > string: Simple-String
  6738. > stream: stream
  6739. > case_sensitive: Flag, if re-reading would be case-sensitive
  6740. > case_inverted: Flag, whether to implicitly case-invert the string
  6741. < stream: stream
  6742. can trigger GC */
  6743. local maygc void pr_symbol_part (const gcv_object_t* stream_, object string,
  6744. bool case_sensitive, bool case_inverted) {
  6745. /* find out, if the name can be printed without |...| surrounding it:
  6746. This can be done if it:
  6747. 1. is not empty and
  6748. 2. *PRINT-READABLY* is NIL and
  6749. 3. starts with a character with syntax-code Constituent and
  6750. 4. consists only of characters with syntax-code Constituent or
  6751. Nonterminating Macro and
  6752. 5. if it contains no lower-/upper-case letters
  6753. (depending on readtable_case) and no colons and
  6754. 6. if it does not have Potential-Number Syntax (with *PRINT-BASE* as base).*/
  6755. pushSTACK(string);
  6756. var bool fasl_stream = stream_get_fasl(*stream_);
  6757. string = popSTACK();
  6758. sstring_un_realloc(string);
  6759. var uintL len = Sstring_length(string); /* length */
  6760. /* check condition 1: */
  6761. if (len==0)
  6762. goto surround; /* length=0 -> must use |...| */
  6763. /* check condition 2: */
  6764. if (!nullpSv(print_readably) || fasl_stream)
  6765. /* *PRINT-READABLY* is true -> must use |...| because when read back in, the
  6766. (READTABLE-CASE *READTABLE*) could be :PRESERVE or :INVERT, and we don't
  6767. know in advance. (Actually, the |...| are only necessary if the symbol
  6768. part contains lower- or upper-case letters. But since most nonempty
  6769. symbol parts do, it's not worth testing.) */
  6770. goto surround;
  6771. /* check conditions 3-5: */
  6772. { /* need the attribute-code-table and the current syntaxcode-table: */
  6773. var object syntax_table; /* syntaxcode-table, with char_code_limit elements */
  6774. var uintW rtcase; /* readtable-case */
  6775. {
  6776. var object readtable;
  6777. get_readtable(readtable = ); /* current Readtable */
  6778. syntax_table = TheReadtable(readtable)->readtable_syntax_table;
  6779. rtcase = RTCase(readtable);
  6780. }
  6781. /* traverse string: */
  6782. SstringDispatch(string,X, {
  6783. var const cintX* charptr = &((SstringX)TheVarobject(string))->data[0];
  6784. var uintL count = len;
  6785. var chart c = as_chart(*charptr++); /* first Character */
  6786. /* its syntaxcode shall be Constituent: */
  6787. if (!(syntax_table_get(syntax_table,c) == syntax_constituent))
  6788. goto surround; /* no -> must use |...| */
  6789. while (1) {
  6790. if (attribute_of(c) == a_pack_m) /* Attributcode Package-Marker ? */
  6791. goto surround; /* yes -> must use |...| */
  6792. if (!case_sensitive)
  6793. switch (rtcase) {
  6794. case case_upcase:
  6795. if (!chareq(c,up_case(c))) /* c was lower-case? */
  6796. goto surround; /* yes -> must use |...| */
  6797. break;
  6798. case case_downcase:
  6799. if (!chareq(c,down_case(c))) /* c was upper-case? */
  6800. goto surround; /* yes -> must use |...| */
  6801. break;
  6802. case case_preserve:
  6803. break;
  6804. case case_invert:
  6805. break;
  6806. default: NOTREACHED;
  6807. }
  6808. count--; if (count == 0) break; /* string finished -> end of loop */
  6809. c = as_chart(*charptr++); /* the next character */
  6810. switch (syntax_table_get(syntax_table,c)) { /* its Syntaxcode */
  6811. case syntax_constituent:
  6812. case syntax_nt_macro:
  6813. break;
  6814. default: /* Syntaxcode /= Constituent, Nonterminating Macro */
  6815. goto surround; /* -> must use |...| */
  6816. }
  6817. }
  6818. });
  6819. }
  6820. { /* check condition 6: */
  6821. pushSTACK(string); /* save string */
  6822. get_buffers(); /* allocate two buffers, in the STACK */
  6823. /* and fill: */
  6824. SstringDispatch(STACK_2,X, {
  6825. var uintL index = 0;
  6826. for (; index < len; index++) {
  6827. var chart c = as_chart(((SstringX)TheVarobject(STACK_2))->data[index]); /* the next character */
  6828. ssstring_push_extend(STACK_1,c); /* into the character-buffer */
  6829. ssbvector_push_extend(STACK_0,attribute_of(c)); /* und into the Attributcode-Buffer */
  6830. }
  6831. });
  6832. O(token_buff_2) = popSTACK(); /* Attributcode-Buffer */
  6833. O(token_buff_1) = popSTACK(); /* Character-Buffer */
  6834. string = popSTACK(); /* move string back */
  6835. if (test_dots()) /* only dots -> must use |...| */
  6836. goto surround;
  6837. { /* Potential-Number-Syntax? */
  6838. var uintWL base = get_print_base(); /* value of *PRINT-BASE* */
  6839. var token_info_t info;
  6840. if (test_potential_number_syntax(&base,&info))
  6841. goto surround; /* yes -> must use |...| */
  6842. }
  6843. }
  6844. /* Name can be printed without Escape-Characters.
  6845. But obey *PRINT-CASE* along the way: */
  6846. write_sstring_case_ext(stream_,string,case_sensitive,case_inverted);
  6847. return;
  6848. surround: /* print Names utilizing the Escape-Characters |...|: */
  6849. { /* fetch syntax code table: */
  6850. var object readtable;
  6851. get_readtable(readtable = ); /* current Readtable */
  6852. pushSTACK(TheReadtable(readtable)->readtable_syntax_table);
  6853. }
  6854. pushSTACK(string);
  6855. var bool pending_newline = false;
  6856. /* stack layout: syntax_table, string. */
  6857. write_ascii_char(stream_,'|');
  6858. if (len > 0) {
  6859. SstringDispatch(STACK_0,X, {
  6860. var uintL index = 0;
  6861. do {
  6862. var chart c = as_chart(((SstringX)TheVarobject(STACK_0))->data[index]); /* the next character */
  6863. if (!fasl_stream || !pr_fasl_special(stream_,c,&pending_newline)) {
  6864. if (case_inverted)
  6865. c = invert_case(c);
  6866. switch (syntax_table_get(STACK_1,c)) { /* its Syntaxcode */
  6867. case syntax_single_esc:
  6868. case syntax_multi_esc: /* The Escape-Character c is prepended by '\': */
  6869. { write_ascii_char(stream_,'\\'); }
  6870. default: ;
  6871. }
  6872. write_code_char(stream_,c); /* print Character */
  6873. }
  6874. index++;
  6875. } while (index < len);
  6876. });
  6877. }
  6878. write_ascii_char(stream_,'|');
  6879. skipSTACK(2);
  6880. }
  6881. /* UP: prints Simple-String like a part of a Symbol.
  6882. pr_like_symbol(&stream,string);
  6883. > string: simple-string
  6884. > stream: stream
  6885. < stream: stream
  6886. can trigger GC */
  6887. local maygc void pr_like_symbol (const gcv_object_t* stream_, object string) {
  6888. /* query *PRINT-ESCAPE*: */
  6889. if (!nullpSv(print_escape) || !nullpSv(print_readably)) {
  6890. /* print with escape-characters */
  6891. pushSTACK(string); /* save */
  6892. var object pack = get_current_package();
  6893. pr_symbol_part(stream_,popSTACK()/*string*/,
  6894. pack_casesensitivep(pack),pack_caseinvertedp(pack));
  6895. } else
  6896. /* print without escape-characters */
  6897. write_sstring_case(stream_,string);
  6898. }
  6899. /* -------- Characters --------
  6900. UP: prints character to stream.
  6901. pr_character(&stream,ch);
  6902. > ch: character
  6903. > stream: stream
  6904. < stream: stream
  6905. can trigger GC */
  6906. local maygc void pr_character (const gcv_object_t* stream_, object ch) {
  6907. /* query *PRINT-ESCAPE*: */
  6908. if (!nullpSv(print_escape) || !nullpSv(print_readably)) {
  6909. /* print character with escape-character.
  6910. Syntax: #\char
  6911. respectively #\charname */
  6912. write_ascii_char(stream_,'#');
  6913. write_ascii_char(stream_,'\\');
  6914. var chart code = char_code(ch); /* code */
  6915. /* The printing of #\Space depends on CUSTOM:*PRINT-SPACE-CHAR-ANSI*. The
  6916. default is to print it in the traditional way "#\Space" because "#\ "
  6917. may 1. confuse users, 2. cause problems with editors which automatically
  6918. remove whitespace from the end of lines. */
  6919. if (as_cint(code) >= (nullpSv(print_space_char_ansi) ? 0x21 : 0x20)
  6920. && as_cint(code) < 0x7F) {
  6921. /* graphic standard character -> don't even lookup the name */
  6922. write_code_char(stream_,code);
  6923. } else {
  6924. var object charname = char_name(code); /* name of the characters */
  6925. if (nullp(charname)) /* no name available */
  6926. write_code_char(stream_,code);
  6927. else /* print name (Simple-String) */
  6928. write_sstring_case(stream_,charname);
  6929. }
  6930. } else /* print character without escape-zeichen */
  6931. write_char(stream_,ch); /* print ch itself */
  6932. }
  6933. /* -------- Strings --------
  6934. UP: prints part of a simple-string to stream.
  6935. pr_sstring_ab(&stream,string,start,len);
  6936. > string: not-reallocated simple-string or (only if len==0) NIL
  6937. > start: startindex
  6938. > len: number of characters to be printed
  6939. > stream: stream
  6940. < stream: stream
  6941. can trigger GC */
  6942. local maygc void pr_sstring_ab (const gcv_object_t* stream_, object string,
  6943. uintL start, uintL len) {
  6944. /* query *PRINT-ESCAPE* & *PRINT-READABLY*: */
  6945. if (!nullpSv(print_escape) || !nullpSv(print_readably)) {
  6946. /* with escape-character: */
  6947. var uintL index = start;
  6948. pushSTACK(string); /* save simple-string */
  6949. if (stream_get_fasl(*stream_)) {
  6950. /* With the normal string syntax, CR characters can not be faithfully
  6951. printed and read back in: CR and CR/LF are converted to LF on input.
  6952. But LF characters can: they are converted to either CR or LF or CR/LF
  6953. on output, depending on the stream's line terminator, which are all
  6954. read back as LF.
  6955. FASL ==> Transform LF to \n, CR to \r, and add
  6956. newlines at these occasions, so that the line length stays small. */
  6957. write_ascii_char(stream_,'"'); /* prepend a quotation mark */
  6958. var bool pending_newline = false;
  6959. string = STACK_0;
  6960. #if 0
  6961. SstringDispatch(string,X, {
  6962. dotimespL(len,len, {
  6963. var chart c = as_chart(((SstringX)TheVarobject(STACK_0))->data[index]); /* next character */
  6964. /* if c = #\Linefeed or c = #\Return escape it: */
  6965. if (!pr_fasl_special(stream_,c,&pending_newline)) {
  6966. /* if c = #\" or c = #\\ first print a '\': */
  6967. if (chareq(c,ascii('"')) || chareq(c,ascii('\\')))
  6968. write_ascii_char(stream_,'\\');
  6969. write_code_char(stream_,c);
  6970. }
  6971. index++;
  6972. });
  6973. });
  6974. #else /* the same stuff, a little optimized */
  6975. SstringDispatch(string,X, {
  6976. var uintL index0 = index;
  6977. while (1) { /* search the next #\Linefeed or #\Return or #\" or #\\ : */
  6978. string = STACK_0;
  6979. while (len > 0) {
  6980. var chart c = as_chart(((SstringX)TheVarobject(string))->data[index]);
  6981. if (chareq(c,ascii(0x0A)) || chareq(c,ascii(0x0D))
  6982. || chareq(c,ascii('"')) || chareq(c,ascii('\\')))
  6983. break;
  6984. index++; len--;
  6985. }
  6986. if (!(index==index0)) {
  6987. if (pending_newline) {
  6988. write_ascii_char(stream_,NL);
  6989. pending_newline = false;
  6990. }
  6991. write_sstring_ab(stream_,STACK_0,index0,index-index0);
  6992. }
  6993. if (len==0)
  6994. break;
  6995. var chart c = as_chart(((SstringX)TheVarobject(STACK_0))->data[index]);
  6996. if (pr_fasl_special(stream_,c,&pending_newline)) {
  6997. index++; len--; index0 = index;
  6998. } else {
  6999. write_ascii_char(stream_,'\\');
  7000. index0 = index; index++; len--;
  7001. }
  7002. }
  7003. });
  7004. #endif
  7005. } else {
  7006. write_ascii_char(stream_,'"'); /* prepend a quotation mark */
  7007. string = STACK_0;
  7008. if (len > 0) {
  7009. #if 0
  7010. SstringDispatch(string,X, {
  7011. dotimespL(len,len, {
  7012. var chart c = as_chart(((SstringX)TheVarobject(STACK_0))->data[index]); /* next character */
  7013. /* if c = #\" or c = #\\ first print a '\': */
  7014. if (chareq(c,ascii('"')) || chareq(c,ascii('\\')))
  7015. write_ascii_char(stream_,'\\');
  7016. write_code_char(stream_,c);
  7017. index++;
  7018. });
  7019. });
  7020. #else /* the same stuff, a little optimized */
  7021. SstringDispatch(string,X, {
  7022. var uintL index0 = index;
  7023. while (1) { /* search the next #\" or #\\ : */
  7024. string = STACK_0;
  7025. while (len > 0) {
  7026. var chart c = as_chart(((SstringX)TheVarobject(string))->data[index]);
  7027. if (chareq(c,ascii('"')) || chareq(c,ascii('\\')))
  7028. break;
  7029. index++; len--;
  7030. }
  7031. if (!(index==index0))
  7032. write_sstring_ab(stream_,string,index0,index-index0);
  7033. if (len==0)
  7034. break;
  7035. write_ascii_char(stream_,'\\');
  7036. index0 = index; index++; len--;
  7037. }
  7038. });
  7039. #endif
  7040. }
  7041. }
  7042. write_ascii_char(stream_,'"'); /* append a quotation mark */
  7043. skipSTACK(1);
  7044. } else /* without escape-character: only write_sstring_ab */
  7045. write_sstring_ab(stream_,string,start,len);
  7046. }
  7047. /* UP: prints string to stream.
  7048. pr_string(&stream,string);
  7049. > string: string
  7050. > stream: stream
  7051. < stream: stream
  7052. can trigger GC */
  7053. local maygc void pr_string (const gcv_object_t* stream_, object string) {
  7054. var uintL len = vector_length(string); /* length */
  7055. var uintL offset = 0; /* Offset of string in the data-vector */
  7056. var object sstring = array_displace_check(string,len,&offset); /* data-vector */
  7057. if (!simple_nilarray_p(sstring) || (len==0 && nullpSv(print_readably)))
  7058. pr_sstring_ab(stream_,sstring,offset,len);
  7059. else /* nilvector */
  7060. pr_nilvector(stream_,string);
  7061. }
  7062. /* -------- Conses, Lists --------
  7063. UP: determines, if a Cons is to be printed in a special manner
  7064. special_list_p(obj,dotted_p)
  7065. > obj: object, a Cons
  7066. > dotted_p: flag, indicating whether the output will be dotted
  7067. if this function returns non-NULL
  7068. < result: address of the corresponding pr_list_xxx-routine, if yes,
  7069. NULL, if no. */
  7070. local pr_routine_t* special_list_p (object obj, bool dotted_p) {
  7071. /* special lists are those of the form
  7072. (QUOTE a), (FUNCTION a), (SYS::BACKQUOTE a [b]) and
  7073. (SYS::SPLICE a), (SYS::NSPLICE a), (SYS::UNQUOTE a)
  7074. if SYS::*PRIN-BQLEVEL* > 0 */
  7075. var object head = Car(obj);
  7076. var pr_routine_t* pr_xxx;
  7077. if (!dotted_p && eq(head,S(quote))) { /* QUOTE */
  7078. pr_xxx = &pr_list_quote; goto test2;
  7079. } else if (!dotted_p && eq(head,S(function))) { /* FUNCTION */
  7080. pr_xxx = &pr_list_function; goto test2;
  7081. } else if (eq(head,S(backquote))) { /* SYS::BACKQUOTE */
  7082. pr_xxx = &pr_list_backquote;
  7083. /* test, if obj is a list of length 2 or 3. */
  7084. obj = Cdr(obj); /* the CDR */
  7085. if (consp(obj) && /* must be a Cons, */
  7086. (obj = Cdr(obj), /* the CDDR must be */
  7087. (atomp(obj) ? nullp(obj) : nullp(Cdr(obj))))) /* NIL or a 1-elt list */
  7088. return pr_xxx;
  7089. else
  7090. return (pr_routine_t*)NULL;
  7091. } else if (eq(head,S(splice))) { /* SYS::SPLICE */
  7092. pr_xxx = &pr_list_splice; goto test2bq;
  7093. } else if (eq(head,S(nsplice))) { /* SYS::NSPLICE */
  7094. pr_xxx = &pr_list_nsplice; goto test2bq;
  7095. } else if (eq(head,S(unquote))) { /* SYS::UNQUOTE */
  7096. pr_xxx = &pr_list_unquote; goto test2bq;
  7097. } else
  7098. return (pr_routine_t*)NULL;
  7099. test2bq: {
  7100. /* test, if SYS::*PRIN-BQLEVEL* > 0 and if obj is a list of length 2. */
  7101. var object bqlevel = Symbol_value(S(prin_bqlevel));
  7102. if (!(posfixnump(bqlevel) && !eq(bqlevel,Fixnum_0)))
  7103. return (pr_routine_t*)NULL;
  7104. }
  7105. test2: /* test, if obj is a list of length 2. */
  7106. if (mconsp(Cdr(obj)) && nullp(Cdr(Cdr(obj))))
  7107. return pr_xxx;
  7108. else
  7109. return (pr_routine_t*)NULL;
  7110. }
  7111. /* UP: returns the value of the fixnum *PRINT-INDENT-LISTS*.
  7112. get_indent_lists()
  7113. < result: value of a fixnum > 0 */
  7114. local uintV get_indent_lists (void) {
  7115. var object obj = Symbol_value(S(print_indent_lists));
  7116. if (posfixnump(obj)) {
  7117. var uintV indent = posfixnum_to_V(obj);
  7118. if (indent > 0)
  7119. return indent;
  7120. }
  7121. /* default value is 1. */
  7122. return 1;
  7123. }
  7124. /* UP: prints list to stream, NIL as ().
  7125. pr_list(&stream,list);
  7126. > list: list
  7127. > stream: stream
  7128. < stream: stream
  7129. can trigger GC */
  7130. local maygc void pr_list (const gcv_object_t* stream_, object list) {
  7131. if (nullp(list)) { /* print NIL as (): */
  7132. write_ascii_char(stream_,'('); write_ascii_char(stream_,')');
  7133. } else /* a Cons */
  7134. pr_cons(stream_,list);
  7135. }
  7136. /* UP: print a Cons to a stream.
  7137. pr_cons(&stream,list);
  7138. > list: cons
  7139. > stream: stream
  7140. < stream: stream
  7141. can trigger GC */
  7142. local maygc void pr_cons (const gcv_object_t* stream_, object list) {
  7143. { /* treat special case: */
  7144. var pr_routine_t* special = special_list_p(list,false);
  7145. if (!(special == (pr_routine_t*)NULL)) {
  7146. (*special)(stream_,list); /* call special pr_list_xxx-routine */
  7147. return;
  7148. }
  7149. }
  7150. LEVEL_CHECK;
  7151. {
  7152. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH*-limit */
  7153. var uintL length = 0; /* previous length := 0 */
  7154. pushSTACK(list); /* save list */
  7155. var gcv_object_t* list_ = &STACK_0; /* and memorize, where it is */
  7156. PAREN_OPEN; /* '(' */
  7157. INDENT_START(get_indent_lists()); /* indent by 1 character, because of '(' */
  7158. JUSTIFY_START(1);
  7159. /* test for attaining of *PRINT-LENGTH* : */
  7160. CHECK_LENGTH_LIMIT(length_limit==0,goto end_of_list);
  7161. /* test for attaining of *PRINT-LINES* : */
  7162. CHECK_LINES_LIMIT(goto end_of_list);
  7163. while (1) {
  7164. /* print the CAR from here */
  7165. list = *list_; *list_ = Cdr(list); /* shorten list */
  7166. JUSTIFY_LAST(nullp(*list_));
  7167. prin_object(stream_,Car(list)); /* print the CAR */
  7168. length++; /* increment length */
  7169. /* print the remainder of the list from here */
  7170. if (nullp(*list_)) /* remainder of list=NIL -> end_of_list */
  7171. goto end_of_list;
  7172. JUSTIFY_SPACE; /* print one Space */
  7173. if (matomp(*list_)) /* Dotted List ? */
  7174. goto dotted_list;
  7175. /* check for attaining *PRINT-LENGTH* : */
  7176. CHECK_LENGTH_LIMIT(length >= length_limit,goto end_of_list);
  7177. /* check for attaining *PRINT-LINES* : */
  7178. CHECK_LINES_LIMIT(goto end_of_list);
  7179. /* check, if dotted-list-notation is necessary: */
  7180. list = *list_;
  7181. if (circle_p(list,NULL)) /* necessary because of circularity? */
  7182. goto dotted_list;
  7183. if (special_list_p(list,true) != (pr_routine_t*)NULL) /* necessary because of QUOTE or similar stuff? */
  7184. goto dotted_list;
  7185. }
  7186. dotted_list: { /* print list-remainder in dotted-list-notation: */
  7187. JUSTIFY_LAST(false);
  7188. write_ascii_char(stream_,'.');
  7189. JUSTIFY_SPACE;
  7190. JUSTIFY_LAST(true);
  7191. prin_object(stream_,*list_);
  7192. } goto end_of_list;
  7193. end_of_list: /* print list content. */
  7194. JUSTIFY_END_FILL;
  7195. INDENT_END;
  7196. PAREN_CLOSE;
  7197. skipSTACK(1);
  7198. }
  7199. LEVEL_END;
  7200. }
  7201. /* output of ... as ...
  7202. (quote object) 'object
  7203. (function object) #'object
  7204. (backquote original-form [expanded-form]) `original-form
  7205. (splice form) ,@form
  7206. (nsplice form) ,.form
  7207. (unquote form) ,form */
  7208. local maygc void pr_list_quote (const gcv_object_t* stream_, object list) {
  7209. /* list = (QUOTE object) */
  7210. pushSTACK(Car(Cdr(list))); /* save (second list) */
  7211. write_ascii_char(stream_,'\''); /* print "'" */
  7212. list = popSTACK();
  7213. INDENT_START(1); /* indent by 1 character because of "'" */
  7214. prin_object(stream_,list); /* print object */
  7215. INDENT_END;
  7216. }
  7217. local maygc void pr_list_function (const gcv_object_t* stream_, object list) {
  7218. /* list = (FUNCTION object) */
  7219. pushSTACK(Car(Cdr(list))); /* save (second list) */
  7220. write_ascii_char(stream_,'#'); /* print "#" */
  7221. write_ascii_char(stream_,'\''); /* print "'" */
  7222. list = popSTACK();
  7223. INDENT_START(2); /* indent by 2 characters because of "#'" */
  7224. prin_object(stream_,list); /* print object */
  7225. INDENT_END;
  7226. }
  7227. local maygc void pr_list_backquote (const gcv_object_t* stream_, object list) {
  7228. /* list = (BACKQUOTE original-form [expanded-form]) */
  7229. pushSTACK(Car(Cdr(list))); /* save (second list) */
  7230. write_ascii_char(stream_,'`'); /* print '`' */
  7231. list = popSTACK();
  7232. { /* increase SYS::*PRIN-BQLEVEL* by 1: */
  7233. var object bqlevel = Symbol_value(S(prin_bqlevel));
  7234. if (!posfixnump(bqlevel))
  7235. bqlevel = Fixnum_0;
  7236. dynamic_bind(S(prin_bqlevel),fixnum_inc(bqlevel,1));
  7237. }
  7238. INDENT_START(1); /* indent by 1 character because of '`' */
  7239. prin_object(stream_,list); /* print original-form */
  7240. INDENT_END;
  7241. dynamic_unbind(S(prin_bqlevel));
  7242. }
  7243. local maygc void pr_list_bothsplice (const gcv_object_t* stream_,
  7244. object list, object ch) {
  7245. /* list = (SPLICE object), ch = '@' or
  7246. list = (NSPLICE object), ch = '.' */
  7247. pushSTACK(Car(Cdr(list))); /* save (second list) */
  7248. write_ascii_char(stream_,','); /* print comma */
  7249. write_char(stream_,ch); /* print '@' resp. '.' */
  7250. list = popSTACK();
  7251. /* decrease SYS::*PRIN-BQLEVEL* by 1: */
  7252. dynamic_bind(S(prin_bqlevel),fixnum_inc(Symbol_value(S(prin_bqlevel)),-1));
  7253. INDENT_START(2); /* indent by 2 characters because of ",@" resp. ",." */
  7254. prin_object(stream_,list); /* print form */
  7255. INDENT_END;
  7256. dynamic_unbind(S(prin_bqlevel));
  7257. }
  7258. local maygc void pr_list_splice (const gcv_object_t* stream_, object list) {
  7259. /* list = (SPLICE object) */
  7260. pr_list_bothsplice(stream_,list,ascii_char('@'));
  7261. }
  7262. local maygc void pr_list_nsplice (const gcv_object_t* stream_, object list) {
  7263. /* list = (NSPLICE object) */
  7264. pr_list_bothsplice(stream_,list,ascii_char('.'));
  7265. }
  7266. local maygc void pr_list_unquote (const gcv_object_t* stream_, object list) {
  7267. /* list = (UNQUOTE object) */
  7268. pushSTACK(Car(Cdr(list))); /* save (second list) */
  7269. write_ascii_char(stream_,','); /* print ',' */
  7270. list = popSTACK();
  7271. /* decrease SYS::*PRIN-BQLEVEL* by 1: */
  7272. dynamic_bind(S(prin_bqlevel),fixnum_inc(Symbol_value(S(prin_bqlevel)),-1));
  7273. INDENT_START(1); /* indent by 1 character because of ',' */
  7274. prin_object(stream_,list); /* print object */
  7275. INDENT_END;
  7276. dynamic_unbind(S(prin_bqlevel));
  7277. }
  7278. /* UP: Print a pair in cons-like (car . cdr) notation.
  7279. pr_pair(&stream,car,cdr);
  7280. > car: an object
  7281. > cdr: an object
  7282. > stream: stream
  7283. < stream: stream
  7284. can trigger GC */
  7285. local maygc void pr_pair (const gcv_object_t* stream_, object car, object cdr) {
  7286. LEVEL_CHECK;
  7287. {
  7288. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH*-limit */
  7289. pushSTACK(car); pushSTACK(cdr); /* save car and cdr */
  7290. var gcv_object_t* pair_ = &STACK_0; /* and memorize, where they are */
  7291. PAREN_OPEN; /* '(' */
  7292. INDENT_START(get_indent_lists());/* indent by 1 character, because of '(' */
  7293. JUSTIFY_START(1);
  7294. /* test for attaining of *PRINT-LENGTH* : */
  7295. CHECK_LENGTH_LIMIT(length_limit==0,goto end_of_list);
  7296. /* test for attaining of *PRINT-LINES* : */
  7297. CHECK_LINES_LIMIT(goto end_of_list);
  7298. /* print the CAR from here */
  7299. JUSTIFY_LAST(false);
  7300. prin_object(stream_,*(pair_ STACKop 1)); /* print the CAR */
  7301. JUSTIFY_SPACE; /* print one Space */
  7302. JUSTIFY_LAST(false);
  7303. { write_ascii_char(stream_,'.'); }
  7304. JUSTIFY_SPACE;
  7305. JUSTIFY_LAST(true);
  7306. prin_object(stream_,*(pair_ STACKop 0));
  7307. end_of_list:
  7308. JUSTIFY_END_FILL;
  7309. INDENT_END;
  7310. PAREN_CLOSE;
  7311. skipSTACK(2);
  7312. }
  7313. LEVEL_END;
  7314. }
  7315. /* -------- Numbers --------
  7316. UP: prints real number to stream.
  7317. pr_real_number(&stream,number);
  7318. > number: real number
  7319. > stream: stream
  7320. < stream: stream
  7321. can trigger GC */
  7322. local maygc void pr_real_number (const gcv_object_t* stream_, object number) {
  7323. if (R_rationalp(number)) { /* rational number */
  7324. var uintWL base = get_print_base(); /* value of *PRINT-BASE* */
  7325. /* query *PRINT-RADIX*: */
  7326. if (!nullpSv(print_radix) || !nullpSv(print_readably)) {
  7327. /* print Radix-Specifier: */
  7328. pushSTACK(number); /* save number */
  7329. switch (base) {
  7330. case 2: { /* base 2 */
  7331. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'b');
  7332. } break;
  7333. case 8: { /* base 8 */
  7334. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'o');
  7335. } break;
  7336. case 16: { /* base 16 */
  7337. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'x');
  7338. } break;
  7339. case 10: /* base 10 */
  7340. if (RA_integerp(number)) {
  7341. /* mark base 10 for integers by appending a period: */
  7342. skipSTACK(1);
  7343. print_integer(number,base,stream_);
  7344. write_ascii_char(stream_,'.');
  7345. return;
  7346. }
  7347. default: { /* print base in #nR-notation: */
  7348. write_ascii_char(stream_,'#');
  7349. pr_uint(stream_,base);
  7350. write_ascii_char(stream_,'r');
  7351. } break;
  7352. }
  7353. number = popSTACK();
  7354. }
  7355. if (RA_integerp(number)) { /* print integer in base base :-) : */
  7356. print_integer(number,base,stream_);
  7357. } else { /* print ratio in base base: */
  7358. pushSTACK(TheRatio(number)->rt_den); /* save denominator */
  7359. print_integer(TheRatio(number)->rt_num,base,stream_); /* print enumerator */
  7360. write_ascii_char(stream_,'/'); /* fraction bar */
  7361. print_integer(popSTACK(),base,stream_); /* print denominator */
  7362. }
  7363. } else /* float */
  7364. print_float(number,stream_);
  7365. }
  7366. /* UP: prints number to stream.
  7367. pr_number(&stream,number);
  7368. > number: number
  7369. > stream: stream
  7370. < stream: stream
  7371. can trigger GC */
  7372. local maygc void pr_number (const gcv_object_t* stream_, object number) {
  7373. if (N_realp(number)) { /* real number */
  7374. pr_real_number(stream_,number);
  7375. } else { /* complex number */
  7376. pushSTACK(number); /* save number */
  7377. var gcv_object_t* number_ = &STACK_0; /* and memorize, where it is */
  7378. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'C');
  7379. PAREN_OPEN;
  7380. INDENT_START(3); /* indent by 3 characters because of '#C(' */
  7381. JUSTIFY_START(1);
  7382. JUSTIFY_LAST(false);
  7383. pr_real_number(stream_,TheComplex(*number_)->c_real); /* print real part */
  7384. JUSTIFY_SPACE;
  7385. JUSTIFY_LAST(true);
  7386. pr_real_number(stream_,TheComplex(*number_)->c_imag); /* print imaginary part */
  7387. JUSTIFY_END_FILL;
  7388. INDENT_END;
  7389. PAREN_CLOSE;
  7390. skipSTACK(1);
  7391. }
  7392. }
  7393. #define UNREADABLE_START \
  7394. do { \
  7395. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'<'); \
  7396. INDENT_START(2); /* indent by 2 characters because of '#<' */ \
  7397. JUSTIFY_START(1); \
  7398. } while (0)
  7399. #define UNREADABLE_END \
  7400. do { \
  7401. INDENT_END; \
  7402. write_ascii_char(stream_,'>'); \
  7403. } while (0)
  7404. /* UP: prints object #<BLABLA FOO> to stream.
  7405. pr_unreadably(&stream,obj,&string,printer);
  7406. > stream: stream
  7407. > obj: object
  7408. > string: simple-string "BLABLA"
  7409. > printer: function to print the object to the stream
  7410. < stream: stream
  7411. can trigger GC */
  7412. local maygc void pr_record_ab_00 (const gcv_object_t* stream_, object obj);
  7413. local maygc void pr_unreadably (const gcv_object_t* stream_, object obj,
  7414. gcv_object_t *string_, pr_routine_t printer) {
  7415. LEVEL_CHECK;
  7416. pushSTACK(obj); /* save object */
  7417. var gcv_object_t* obj_ = &STACK_0; /* and memorize, where it is */
  7418. UNREADABLE_START;
  7419. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH* */
  7420. JUSTIFY_LAST(length_limit==0);
  7421. write_sstring_case(stream_,*string_); /* print string */
  7422. if (printer != pr_record_ab_00) {
  7423. JUSTIFY_SPACE;
  7424. JUSTIFY_LAST(true);
  7425. }
  7426. printer(stream_,*obj_); /* print obj as an address */
  7427. JUSTIFY_END_FILL;
  7428. UNREADABLE_END;
  7429. skipSTACK(1);
  7430. LEVEL_END;
  7431. }
  7432. /* UP: prints object #<BLABLA (FOO . BAR)> to stream.
  7433. pr_unreadably_2(&stream,obj1,obj2,&string);
  7434. > stream: stream
  7435. > obj1, obj2: objects
  7436. > string: simple-string "BLABLA"
  7437. < stream: stream
  7438. can trigger GC */
  7439. local maygc void pr_unreadably_2 (const gcv_object_t* stream_, object obj1,
  7440. object obj2, gcv_object_t *string_) {
  7441. LEVEL_CHECK;
  7442. pushSTACK(obj1); /* save */
  7443. pushSTACK(obj2); /* save */
  7444. var gcv_object_t* aux_ = &STACK_0; /* and memorize, where they are */
  7445. UNREADABLE_START;
  7446. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH* */
  7447. JUSTIFY_LAST(length_limit==0);
  7448. write_sstring_case(stream_,*string_);
  7449. /* check for attaining of *PRINT-LENGTH*: */
  7450. if (length_limit == 0) goto pr_unreadably_2_end;
  7451. JUSTIFY_SPACE; /* print Space */
  7452. JUSTIFY_LAST(true);
  7453. pr_pair(stream_,*(aux_ STACKop 0),*(aux_ STACKop 1)); /* output (obj1 . obj2) pair */
  7454. pr_unreadably_2_end:
  7455. JUSTIFY_END_FILL;
  7456. UNREADABLE_END;
  7457. skipSTACK(2);
  7458. LEVEL_END;
  7459. }
  7460. /* -------- Arrays when *PRINT-ARRAY*=NIL --------
  7461. UP: prints array in short form to stream.
  7462. pr_array_nil(&stream,obj);
  7463. > obj: array
  7464. > stream: stream
  7465. < stream: stream
  7466. can trigger GC */
  7467. local maygc void pr_array_nil (const gcv_object_t* stream_, object obj) {
  7468. pushSTACK(obj); /* save array */
  7469. var gcv_object_t* obj_ = &STACK_0; /* and memorize, where it is */
  7470. UNREADABLE_START;
  7471. JUSTIFY_LAST(false);
  7472. write_sstring_case(stream_,O(printstring_array)); /* print "ARRAY" */
  7473. JUSTIFY_SPACE; JUSTIFY_LAST(false);
  7474. prin_object_dispatch(stream_,array_element_type(*obj_)); /* print elementtype (symbol or list) */
  7475. JUSTIFY_SPACE; JUSTIFY_LAST(false);
  7476. pr_list(stream_,array_dimensions(*obj_)); /* print dimension-list */
  7477. if (array_has_fill_pointer_p(*obj_)) {
  7478. /* Array with fill-pointer -> also print the fill-pointer: */
  7479. JUSTIFY_SPACE; JUSTIFY_LAST(false);
  7480. write_sstring_case(stream_,O(printstring_fill_pointer)); /* print "FILL-POINTER=" */
  7481. pr_uint(stream_,vector_length(*obj_)); /* print length (=fill-pointer) */
  7482. }
  7483. JUSTIFY_SPACE; JUSTIFY_LAST(true);
  7484. pr_hex6(stream_,*obj_);
  7485. JUSTIFY_END_FILL;
  7486. UNREADABLE_END;
  7487. skipSTACK(1);
  7488. }
  7489. /* -------- Bit-Vectors --------
  7490. UP: prints part of a simple-bit-vector to stream.
  7491. pr_sbvector_ab(&stream,bv,start,len);
  7492. > bv: simple-bit-vector
  7493. > start: startindex
  7494. > len: number of the bits to be printed
  7495. > stream: stream
  7496. < stream: stream
  7497. can trigger GC */
  7498. local maygc void pr_sbvector_ab (const gcv_object_t* stream_, object bv,
  7499. uintL start, uintL len) {
  7500. var uintL index = start;
  7501. pushSTACK(bv); /* save simple-bit-vector */
  7502. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'*');
  7503. dotimesL(len,len, {
  7504. write_char(stream_,
  7505. (sbvector_btst(STACK_0,index) ?
  7506. ascii_char('1') : ascii_char('0')));
  7507. index++;
  7508. });
  7509. skipSTACK(1);
  7510. }
  7511. /* UP: prints bit-vector to stream.
  7512. pr_bvector(&stream,bv);
  7513. > bv: bit-vector
  7514. > stream: stream
  7515. < stream: stream
  7516. can trigger GC */
  7517. local maygc void pr_bvector (const gcv_object_t* stream_, object bv) {
  7518. /* query *PRINT-ARRAY*: */
  7519. if (!nullpSv(print_array) || !nullpSv(print_readably)) {
  7520. /* print bv elementwise: */
  7521. var uintL len = vector_length(bv); /* length */
  7522. var uintL offset = 0; /* offset of bit-vector into the data-vector */
  7523. var object sbv = array_displace_check(bv,len,&offset); /* data-vector */
  7524. pr_sbvector_ab(stream_,sbv,offset,len);
  7525. } else /* *PRINT-ARRAY* = NIL -> print in short form: */
  7526. pr_array_nil(stream_,bv);
  7527. }
  7528. /* -------- Generic Vectors --------
  7529. UP: prints generic vector to stream.
  7530. pr_vector(&stream,v);
  7531. > v: generic vector
  7532. > stream: stream
  7533. < stream: stream
  7534. can trigger GC */
  7535. local maygc void pr_vector (const gcv_object_t* stream_, object v) {
  7536. /* query *PRINT-ARRAY*: */
  7537. if (!nullpSv(print_array) || !nullpSv(print_readably)) {
  7538. /* print v elementwise: */
  7539. LEVEL_CHECK;
  7540. {
  7541. var bool readable = /* Flag, if length and type are also printed */
  7542. (!nullpSv(print_readably) && !general_vector_p(v));
  7543. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH*-limit */
  7544. var uintL length = 0; /* previous length := 0 */
  7545. /* process vector elementwise: */
  7546. var uintL len = vector_length(v); /* vector-length */
  7547. var uintL offset = 0; /* offset of vector into the data-vector */
  7548. pushSTACK(array_displace_check(v,len,&offset)); /* save data-vector */
  7549. var gcv_object_t* sv_ = &STACK_0; /* and memorize, where it is */
  7550. var uintL index = 0 + offset; /* startindex = 0 in the vector */
  7551. if (readable) {
  7552. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'A');
  7553. PAREN_OPEN; /* print '(' */
  7554. INDENT_START(3); /* indent by 3 characters because of '#A(' */
  7555. JUSTIFY_START(1);
  7556. JUSTIFY_LAST(false);
  7557. prin_object_dispatch(stream_,array_element_type(*sv_)); /* print element-type */
  7558. JUSTIFY_SPACE;
  7559. JUSTIFY_LAST(false);
  7560. pushSTACK(fixnum(len));
  7561. pr_list(stream_,listof(1)); /* print list with the length */
  7562. JUSTIFY_SPACE;
  7563. JUSTIFY_LAST(true);
  7564. PAREN_OPEN; /* '(' */
  7565. INDENT_START(1); /* indent by 1 character because of '(' */
  7566. } else {
  7567. write_ascii_char(stream_,'#');
  7568. PAREN_OPEN; /* '(' */
  7569. INDENT_START(2); /* indent by 2 characters because of '#(' */
  7570. }
  7571. JUSTIFY_START(1);
  7572. for (; len > 0; len--) {
  7573. /* print Space (unless in front of first elemnt): */
  7574. if (!(length==0))
  7575. JUSTIFY_SPACE;
  7576. /* check for attaining of *PRINT-LENGTH* : */
  7577. CHECK_LENGTH_LIMIT(length >= length_limit,break);
  7578. /* test for attaining of *PRINT-LINES* : */
  7579. CHECK_LINES_LIMIT(break);
  7580. JUSTIFY_LAST(len==1);
  7581. /* print vector-element: */
  7582. prin_object(stream_,storagevector_aref(*sv_,index));
  7583. length++; /* increment length */
  7584. index++; /* then go to vector-element */
  7585. }
  7586. JUSTIFY_END_FILL;
  7587. INDENT_END;
  7588. PAREN_CLOSE;
  7589. if (readable) {
  7590. JUSTIFY_END_FILL;
  7591. INDENT_END;
  7592. PAREN_CLOSE;
  7593. }
  7594. skipSTACK(1);
  7595. }
  7596. LEVEL_END;
  7597. } else /* *PRINT-ARRAY* = NIL -> print in short form: */
  7598. pr_array_nil(stream_,v);
  7599. }
  7600. /* print a key-value table (for a hash table) kvt (on the stack)
  7601. the table is printed as an alist: a sequence of (key . value)
  7602. can trigger GC */
  7603. local maygc void pr_kvtable (const gcv_object_t* stream_, gcv_object_t* kvt_,
  7604. uintL index, uintL count) {
  7605. var uintL length = 0;
  7606. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH*-limit */
  7607. while (1) {
  7608. length++; /* increase previous length */
  7609. /* search for next to be printed Key-Value-Pair: */
  7610. var object kvt = *kvt_;
  7611. while (1) {
  7612. if (index==0) /* finished kvtable? */
  7613. goto kvt_finish;
  7614. index -= 3; /* decrease index */
  7615. if (boundp(TheHashedAlist(kvt)->hal_data[index+0])) /* Key /= "empty" ? */
  7616. break;
  7617. }
  7618. JUSTIFY_SPACE; /* print Space */
  7619. /* check for attaining of *PRINT-LENGTH* : */
  7620. CHECK_LENGTH_LIMIT(length >= length_limit,break);
  7621. /* test for attaining of *PRINT-LINES* : */
  7622. CHECK_LINES_LIMIT(break);
  7623. count--;
  7624. JUSTIFY_LAST(count==0);
  7625. /* Print fake cons (Key . Value): */
  7626. var gcv_object_t* ptr = &TheHashedAlist(*kvt_)->hal_data[index];
  7627. pr_pair(stream_,ptr[0],ptr[1]);
  7628. }
  7629. kvt_finish: ;
  7630. }
  7631. /* -------- Nil-Vectors --------
  7632. UP: prints a vector of element type NIL to stream.
  7633. pr_nilvector(&stream,v);
  7634. > v: vector of element type NIL
  7635. > stream: stream
  7636. < stream: stream
  7637. can trigger GC */
  7638. local maygc void pr_nilvector (const gcv_object_t* stream_, object v) {
  7639. var uintL len = vector_length(v); /* vector-length */
  7640. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'A');
  7641. PAREN_OPEN; /* print '(' */
  7642. INDENT_START(3); /* indent by 3 characters because of '#A(' */
  7643. JUSTIFY_START(1);
  7644. JUSTIFY_LAST(false);
  7645. prin_object_dispatch(stream_,NIL); /* print element-type */
  7646. JUSTIFY_SPACE;
  7647. JUSTIFY_LAST(true);
  7648. pushSTACK(fixnum(len));
  7649. pr_list(stream_,listof(1)); /* print list with the length */
  7650. JUSTIFY_END_FILL;
  7651. INDENT_END;
  7652. PAREN_CLOSE;
  7653. }
  7654. /* -------- Multi-Dimensional Arrays --------
  7655. (defun %print-array (array stream)
  7656. (let ((rank (array-rank array))
  7657. (dims (array-dimensions array))
  7658. (eltype (array-element-type array)))
  7659. (write-char #\#stream)
  7660. (if (zerop (array-total-size array))
  7661. ; rereadable Output of empty multi-dimensional Arrays
  7662. (progn
  7663. (write-char #\A stream)
  7664. (prin1 dims stream))
  7665. (progn
  7666. (let ((*print-base* 10.)) (prin1 rank stream))
  7667. (write-char #\A stream)
  7668. (if (and (plusp rank)
  7669. (or (eq eltype 'bit) (eq eltype 'character))
  7670. (or (null *print-length*) (>= *print-length* (array-dimension array (1- rank)))))
  7671. ; shorter Output of multidimensional Bit- and Character-Arrays
  7672. (let* ((lastdim (array-dimension array (1- rank)))
  7673. (offset 0)
  7674. (sub-array (make-array 0 :element-type eltype :adjustable t)))
  7675. (labels ((help (dimsr)
  7676. (if (null dimsr)
  7677. (progn
  7678. (prin1
  7679. (adjust-array sub-array lastdim :displaced-to array
  7680. :displaced-index-offset offset)
  7681. stream)
  7682. (setq offset (+ offset lastdim)))
  7683. (let ((dimsrr (rest dimsr)))
  7684. (write-char #\( stream)
  7685. (dotimes (i (first dimsr))
  7686. (unless (zerop i) (write-char #\space stream))
  7687. (help dimsrr))
  7688. (write-char #\) stream)))))
  7689. (help (nbutlast dims))))
  7690. ; normal Output of multidimensional Arrays
  7691. (let ((indices (make-list rank))) ; List of rank Indices
  7692. (labels ((help (dimsr indicesr)
  7693. (if (null dimsr)
  7694. (prin1 (apply #'aref array indices) stream)
  7695. (let ((dimsrr (rest dimsr)) (indicesrr (rest indicesr)))
  7696. (write-char #\( stream)
  7697. (dotimes (i (first dimsr))
  7698. (unless (zerop i) (write-char #\space stream))
  7699. (rplaca indicesr i)
  7700. (help dimsrr indicesrr))
  7701. (write-char #\) stream)))))
  7702. (help dims indices))))))))
  7703. sub-routines for printing of an element resp. a sub-array:
  7704. pr_array_elt_xxx(&stream,obj,&info);
  7705. > obj: data-vector
  7706. > info.index: index of the first to be printed element
  7707. > info.count: number of the elements to be printed
  7708. > stream: stream
  7709. < stream: stream
  7710. < info.index: increased by info.count
  7711. can trigger GC */
  7712. typedef struct {
  7713. uintL index;
  7714. uintL count;
  7715. } pr_array_info_t;
  7716. typedef maygc void pr_array_elt_routine_t (const gcv_object_t* stream_,
  7717. object obj, pr_array_info_t* info);
  7718. /* subroutine for printing an element:
  7719. info.count = 1 for this routine. */
  7720. local pr_array_elt_routine_t pr_array_elt_simple;
  7721. /* Two SRs for printing a sub-array: */
  7722. local pr_array_elt_routine_t pr_array_elt_bvector; /* sub-array is bit-vector */
  7723. local pr_array_elt_routine_t pr_array_elt_string; /* sub-array is string */
  7724. local maygc void pr_array_elt_simple (const gcv_object_t* stream_, object obj,
  7725. pr_array_info_t* info)
  7726. { /* simple-vector */
  7727. /* fetch element of generic type and print: */
  7728. prin_object(stream_,storagevector_aref(obj,info->index));
  7729. info->index++;
  7730. }
  7731. local maygc void pr_array_elt_bvector (const gcv_object_t* stream_, object obj,
  7732. pr_array_info_t* info)
  7733. { /* simple-bit-vector */
  7734. /* print sub-bit-vector: */
  7735. pr_sbvector_ab(stream_,obj,info->index,info->count);
  7736. info->index += info->count;
  7737. }
  7738. local maygc void pr_array_elt_string (const gcv_object_t* stream_, object obj,
  7739. pr_array_info_t* info)
  7740. { /* simple-string */
  7741. /* print sub-string: */
  7742. pr_sstring_ab(stream_,obj,info->index,info->count);
  7743. info->index += info->count;
  7744. }
  7745. /* UP: prints part of an array.
  7746. pr_array_recursion(locals,depth,rdepth);
  7747. > depth: recursion-depth relative to the elements/sub-arrays
  7748. > rdepth: recursion-depth relative to the elements, i.e. rank of this part
  7749. > locals: Variables:
  7750. *(locals->stream_) : stream
  7751. *(locals->obj_) : data-vector
  7752. locals->dims_sizes: address of the table of dimensions of the array
  7753. and its sub-products
  7754. *(locals->pr_one_elt): function for printing an element/sub-arrays
  7755. locals->info: parameter for this function
  7756. locals->info.index: start-index in datenvector
  7757. locals->length_limit: length-limit
  7758. < locals->info.index: end-index in the data-vector
  7759. can trigger GC */
  7760. typedef struct {
  7761. const gcv_object_t* stream_;
  7762. const gcv_object_t* obj_;
  7763. const array_dim_size_t* dims_sizes;
  7764. pr_array_elt_routine_t* pr_one_elt;
  7765. pr_array_info_t info;
  7766. uintL length_limit;
  7767. } pr_array_locals_t;
  7768. local maygc void pr_array_recursion (pr_array_locals_t* locals, uintL depth,
  7769. uintL rdepth) {
  7770. check_SP(); check_STACK();
  7771. if (depth==0) { /* recursion-depth 0 -> start(base) of recursion */
  7772. (*(locals->pr_one_elt)) /* call function pr_one_elt, with */
  7773. (locals->stream_, /* address of stream, */
  7774. *(locals->obj_), /* data-vector obj, */
  7775. &(locals->info) /* infopointer */
  7776. ); /* as arguments */
  7777. /* This function increases locals->info.index itself. */
  7778. } else {
  7779. depth--; /* decrease recursion-depth (still >=0) */
  7780. rdepth--; /* decrease recursion-depth (still >= depth) */
  7781. var const gcv_object_t* stream_ = locals->stream_;
  7782. var uintL length = 0; /* previous length := 0 */
  7783. var uintL endindex = locals->info.index /* start-index in data vector */
  7784. + locals->dims_sizes[depth].dimprod /* + dimension product */
  7785. ; /* delivers the end-index of this sub-array */
  7786. var uintL count = locals->dims_sizes[depth].dim;
  7787. PAREN_OPEN; /* print '(' */
  7788. INDENT_START(1); /* indent by 1 character, because of '(' */
  7789. JUSTIFY_START(1);
  7790. /* loop over dimension (r-depth): print a sub-array at a time */
  7791. for (; count > 0; count--) {
  7792. /* print Space(except before the first sub-array): */
  7793. if (!(length==0))
  7794. JUSTIFY_SPACE;
  7795. /* check for attaining of *PRINT-LENGTH* : */
  7796. CHECK_LENGTH_LIMIT(length >= locals->length_limit,break);
  7797. /* test for attaining of *PRINT-LINES* : */
  7798. CHECK_LINES_LIMIT(break);
  7799. JUSTIFY_LAST(count==1);
  7800. /* print sub-array:
  7801. (recursively, with decreased depth, and locals->info.index
  7802. is passed from one call to the next call
  7803. without requiring further action) */
  7804. if (depth > 0) {
  7805. if (!level_check(locals->stream_)) {
  7806. pr_array_recursion(locals,depth,rdepth);
  7807. level_end(locals->stream_);
  7808. }
  7809. } else {
  7810. pr_array_recursion(locals,depth,rdepth);
  7811. }
  7812. length++; /* increment length :-) */
  7813. /* locals->info.index is already incremented */
  7814. }
  7815. /* Attempt to put a 1-dimensional group of objects into as few lines as
  7816. possible, but don't do so for >=2-dimensional groups of objects. */
  7817. if (rdepth==0) {
  7818. JUSTIFY_END_FILL;
  7819. } else {
  7820. JUSTIFY_END_LINEAR;
  7821. }
  7822. INDENT_END;
  7823. PAREN_CLOSE; /* print ')' */
  7824. locals->info.index = endindex; /* reached end-index */
  7825. }
  7826. }
  7827. /* UP: prints multi-dimensional array to stream.
  7828. pr_array(&stream,obj);
  7829. > obj: multi-dimensional array
  7830. > stream: stream
  7831. < stream: stream
  7832. can trigger GC */
  7833. local maygc void pr_array (const gcv_object_t* stream_, object obj) {
  7834. /* query *PRINT-ARRAY* : */
  7835. if (!nullpSv(print_array) || !nullpSv(print_readably)) {
  7836. /* print obj elementwise: */
  7837. LEVEL_CHECK;
  7838. { /* determine rank and fetch dimensions and sub-product: */
  7839. var uintL r = (uintL)Iarray_rank(obj); /* rank */
  7840. var DYNAMIC_ARRAY(dims_sizes,array_dim_size_t,r); /* dynamically allocated array */
  7841. iarray_dims_sizes(obj,dims_sizes); /* fill */
  7842. var uintL depth = r; /* depth of recursion */
  7843. var pr_array_locals_t locals; /* local variables */
  7844. var bool readable = true; /* Flag, if dimensions and type are also printed */
  7845. locals.stream_ = stream_;
  7846. locals.dims_sizes = dims_sizes;
  7847. locals.length_limit = get_print_length(); /* length limit */
  7848. { /* decision over routine to be used: */
  7849. var uintB atype = Iarray_flags(obj) & arrayflags_atype_mask;
  7850. if ((r>0) && (locals.length_limit >= dims_sizes[0].dim)) {
  7851. switch (atype) {
  7852. case Atype_Bit: /* print whole bitvectors instead of single bits */
  7853. locals.pr_one_elt = &pr_array_elt_bvector;
  7854. goto not_single;
  7855. case Atype_Char: /* print whole Strings instead of single Characters */
  7856. locals.pr_one_elt = &pr_array_elt_string;
  7857. not_single:
  7858. /* don't print single elements, but one-dimensional sub-arrays. */
  7859. depth--; /* therefore depth := r-1 */
  7860. locals.info.count = dims_sizes[0].dim; /* Dim_r as "Elementary length" */
  7861. locals.dims_sizes++; /* consider only Dim_1, ..., Dim_(r-1) */
  7862. readable = false; /* automatically rereadable */
  7863. goto routine_ok;
  7864. default: ;
  7865. }
  7866. }
  7867. locals.info.count = 1; /* 1 as "Elementary length" */
  7868. switch (atype) {
  7869. case Atype_NIL: locals.pr_one_elt = NULL; break;
  7870. case Atype_T: readable = false; /* automatically rereadable */
  7871. /*FALLTHROUGH*/
  7872. default: locals.pr_one_elt = &pr_array_elt_simple;
  7873. }
  7874. routine_ok:
  7875. locals.info.index = 0; /* start-index is 0 */
  7876. }
  7877. if (nullpSv(print_readably))
  7878. readable = false; /* does not need to be rereadable */
  7879. pushSTACK(obj); /* save array */
  7880. var gcv_object_t* obj_ = &STACK_0; /* and memorize, where it is */
  7881. /* fetch data-vector: */
  7882. var uintL size = TheIarray(obj)->totalsize;
  7883. if ((size==0 && (!nullpSv(print_readably) || nullpSv(print_empty_arrays_ansi)))
  7884. || locals.pr_one_elt==NULL)
  7885. readable = true; /* or else you would not even know the dimensions */
  7886. obj = iarray_displace_check(obj,size,&locals.info.index); /* data-vector */
  7887. /* locals.info.index = Offset from array to the data-vector */
  7888. pushSTACK(obj); locals.obj_ = &STACK_0; /* store obj in Stack */
  7889. /* now go ahead. */
  7890. if (readable) {
  7891. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'A');
  7892. PAREN_OPEN; /* print '(' */
  7893. INDENT_START(3); /* indent by 3 characters, because of '#A(' */
  7894. JUSTIFY_START(1);
  7895. JUSTIFY_LAST(false);
  7896. prin_object_dispatch(stream_, locals.pr_one_elt==NULL ? NIL : array_element_type(*locals.obj_)); /* print element-type (Symbol or List) */
  7897. JUSTIFY_SPACE; JUSTIFY_LAST(false);
  7898. pr_list(stream_,array_dimensions(*obj_)); /* print dimension-list */
  7899. if (locals.pr_one_elt) { /* not (ARRAY NIL) */
  7900. JUSTIFY_SPACE; JUSTIFY_LAST(true);
  7901. pr_array_recursion(&locals,depth,r); /* print array-elements */
  7902. }
  7903. JUSTIFY_END_FILL;
  7904. INDENT_END;
  7905. PAREN_CLOSE; /* print ')' */
  7906. } else {
  7907. /* first, print prefix #nA : */
  7908. INDENTPREP_START;
  7909. write_ascii_char(stream_,'#');
  7910. pr_uint(stream_,r); /* print rank decimally */
  7911. write_ascii_char(stream_,'A');
  7912. {
  7913. var uintV indent = INDENTPREP_END;
  7914. /* then print the array-elements: */
  7915. INDENT_START(indent);
  7916. }
  7917. pr_array_recursion(&locals,depth,r);
  7918. INDENT_END;
  7919. }
  7920. skipSTACK(2);
  7921. FREE_DYNAMIC_ARRAY(dims_sizes);
  7922. }
  7923. LEVEL_END;
  7924. } else /* *PRINT-ARRAY* = NIL -> print in short form: */
  7925. pr_array_nil(stream_,obj);
  7926. }
  7927. /* -------- CLOS-instances -------- */
  7928. local maygc void pr_sharp_dot (const gcv_object_t* stream_,object obj) {
  7929. pushSTACK(obj); /* save form */
  7930. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'.');
  7931. obj = popSTACK(); /* recall form */
  7932. INDENT_START(2); /* indent by 2 characters, because of '#.' */
  7933. prin_object(stream_,obj); /* print form */
  7934. INDENT_END;
  7935. }
  7936. /* UP: prints CLOS-instance to stream.
  7937. pr_instance(&stream,obj);
  7938. > obj: CLOS-Instance
  7939. > stream: stream
  7940. < stream: stream
  7941. can trigger GC */
  7942. local maygc void pr_instance (const gcv_object_t* stream_, object obj) {
  7943. pushSTACK(obj); /* save obj */
  7944. if (stream_get_fasl(*stream_) && !nullpSv(print_readably)
  7945. && !nullpSv(load_forms)) { /* compiling - use MAKE-LOAD-FORM */
  7946. pushSTACK(STACK_0/*obj*/); funcall(S(make_init_form),1);
  7947. obj = popSTACK(); /* recall obj */
  7948. if (!nullp(value1)) {
  7949. pr_sharp_dot(stream_,value1);
  7950. return;
  7951. }
  7952. } else obj = popSTACK();
  7953. LEVEL_CHECK;
  7954. /* execute (CLOS:PRINT-OBJECT obj stream) : */
  7955. var uintC count = pr_external_1(*stream_); /* instantiate bindings */
  7956. pushSTACK(obj); pushSTACK(*stream_); funcall(S(print_object),2);
  7957. pr_external_2(count); /* dissolve bindings */
  7958. LEVEL_END;
  7959. }
  7960. /* -------- Structures --------
  7961. (defun %print-structure (structure stream)
  7962. (let ((name (type-of structure)))
  7963. (let ((fun (get name 'STRUCTURE-PRINT)))
  7964. (if fun
  7965. (funcall fun structure stream *PRIN-LEVEL*)
  7966. (print-object structure stream)))))
  7967. (defmethod print-object ((structure structure-object) stream)
  7968. (print-structure structure stream))
  7969. (defun print-structure (structure stream)
  7970. (let ((class (get name 'CLOS::CLOSCLASS)))
  7971. (if class
  7972. (let ((readable (clos::class-kconstructor class)))
  7973. (write-string (if readable "#S(" "#<") stream)
  7974. (prin1 name stream)
  7975. (dolist (slot (clos:class-slots class))
  7976. (write-char #\space stream)
  7977. (prin1 (intern (symbol-name (clos:slot-definition-name slot)) *KEYWORD-PACKAGE*) stream)
  7978. (write-char #\space stream)
  7979. (prin1 (%structure-ref name structure (slot:slot-definition-location slot)) stream))
  7980. (write-string (if readable ")" ">") stream))
  7981. (progn
  7982. (write-string "#<" stream)
  7983. (prin1 name stream)
  7984. (do ((l (%record-length structure))
  7985. (i 1 (1+ i)))
  7986. ((>= i l))
  7987. (write-char #\space stream)
  7988. (prin1 (%structure-ref name structure i) stream))
  7989. (write-string ">" stream)))))
  7990. UP: call of a (external) print-function for structures
  7991. pr_structure_external(&stream,structure,function);
  7992. > stream: stream
  7993. > structure: structure
  7994. > function: print-function for structures of this type
  7995. can trigger GC */
  7996. local maygc void pr_structure_external (const gcv_object_t* stream_,
  7997. object structure, object function) {
  7998. LEVEL_CHECK;
  7999. var object stream = *stream_;
  8000. var uintC count = pr_external_1(stream); /* create bindings */
  8001. /* (funcall fun Structure Stream SYS::*PRIN-LEVEL*) : */
  8002. pushSTACK(structure); /* Structure = 1st argument */
  8003. pushSTACK(stream); /* Stream = 2nd argument */
  8004. pushSTACK(Symbol_value(S(prin_level))); /* SYS::*PRIN-LEVEL* = 3rd Argument */
  8005. funcall(function,3);
  8006. pr_external_2(count); /* dissolve bindings */
  8007. LEVEL_END;
  8008. }
  8009. /* UP: prints structure to stream.
  8010. pr_structure(&stream,structure);
  8011. > structure: structure
  8012. > stream: stream
  8013. < stream: stream :-) (great documentation, right? )
  8014. can trigger GC */
  8015. local maygc void pr_structure (const gcv_object_t* stream_, object structure) {
  8016. /* determine type of the structure (ref. TYPE-OF): */
  8017. var object name = Car(TheStructure(structure)->structure_types);
  8018. /* name = (car '(name_1 ... name_i-1 name_i)) = name_1.
  8019. execute (GET name 'SYS::STRUCTURE-PRINT) : */
  8020. var object fun = get(name,S(structure_print));
  8021. if (boundp(fun)) { /* call given print-function: */
  8022. pr_structure_external(stream_,structure,fun);
  8023. } else { /* no given print-function found. */
  8024. /* call CLOS:PRINT-OBJECT: */
  8025. pr_instance(stream_,structure);
  8026. }
  8027. }
  8028. /* UP: print structure to stream.
  8029. pr_structure_default(&stream,structure);
  8030. > structure: structure
  8031. > stream: stream
  8032. < stream: stream
  8033. can trigger GC */
  8034. local maygc void pr_structure_default (const gcv_object_t* stream_,
  8035. object structure) {
  8036. var object name = Car(TheStructure(structure)->structure_types);
  8037. /* name = (car '(name_1 ... name_i-1 name_i)) = name_1. */
  8038. pushSTACK(structure);
  8039. pushSTACK(name);
  8040. var gcv_object_t* structure_ = &STACK_1;
  8041. /* it is *(structure_ STACKop 0) = structure
  8042. and *(structure_ STACKop -1) = name .
  8043. execute (GET name 'CLOS::CLOSCLASS) : */
  8044. var object clas = get(name,S(closclass));
  8045. if (boundp(clas)) { /* print structure with slot-name: */
  8046. pushSTACK(clas);
  8047. /* stack layout: structure, name, clas.
  8048. clas must be an instance of <structure-class> ! */
  8049. if_defined_class_p(clas, ; , goto bad_clas; );
  8050. if (srecord_length(TheClass(clas)) <= built_in_class_length) goto bad_clas;
  8051. if (matomp(TheClass(clas)->current_version)) {
  8052. bad_clas:
  8053. pushSTACK(S(print));
  8054. error(error_condition,GETTEXT("~S: bad class"));
  8055. }
  8056. var object constructor = /* (clos::class-kconstructor class) */
  8057. (&TheClass(clas)->current_version)[1];
  8058. var bool readable = /* true if (clos::class-kconstructor class) /= NIL */
  8059. !nullp(constructor);
  8060. if (readable) { /* print structure re-readably: */
  8061. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'S');
  8062. PAREN_OPEN;
  8063. INDENT_START(3); /* indent by 3 characters, because of '#S(' */
  8064. JUSTIFY_START(1);
  8065. } else { /* print structure non-rereadably: */
  8066. CHECK_PRINT_READABLY(*structure_);
  8067. UNREADABLE_START;
  8068. }
  8069. pushSTACK(TheClass(*(structure_ STACKop -2))->slots);
  8070. JUSTIFY_LAST(matomp(STACK_0));
  8071. prin_object(stream_,*(structure_ STACKop -1)); /* print name */
  8072. { /* loop through slot-list STACK_0 = (clos:class-slots clas) : */
  8073. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH*-limit */
  8074. var uintL length = 0; /* previous length := 0 */
  8075. while (mconsp(STACK_0)) {
  8076. var object slot = STACK_0;
  8077. STACK_0 = Cdr(slot); /* shorten list */
  8078. slot = Car(slot); /* a single slot */
  8079. if (!(instancep(slot) && Srecord_length(slot) >= 8))
  8080. goto bad_clas; /* should be a <structure-effective-slot-definition> */
  8081. pushSTACK(slot); /* save slot */
  8082. JUSTIFY_SPACE; /* print Space */
  8083. /* check for attaining of *PRINT-LENGTH* : */
  8084. CHECK_LENGTH_LIMIT(length >= length_limit,
  8085. skipSTACK(1); /* forget slot */
  8086. break);
  8087. /* test for attaining of *PRINT-LINES* : */
  8088. CHECK_LINES_LIMIT(skipSTACK(1);break);
  8089. JUSTIFY_LAST(matomp(STACK_1));
  8090. var gcv_object_t* slot_ = &STACK_0; /* there is the slot */
  8091. JUSTIFY_START(0);
  8092. JUSTIFY_LAST(false);
  8093. write_ascii_char(stream_,':'); /* keyword-mark */
  8094. { /* Print (symbol-name (clos:slot-definition-name slot)): */
  8095. var object obj = TheSlotDefinition(*slot_)->slotdef_name;
  8096. if (!symbolp(obj)) goto bad_clas;
  8097. pr_like_symbol(stream_,Symbol_name(obj)); /* print symbolname of component */
  8098. }
  8099. JUSTIFY_SPACE;
  8100. JUSTIFY_LAST(true);
  8101. /* (SYS::%%STRUCTURE-REF name Structure (slot-definition-location slot)): */
  8102. pushSTACK(*(structure_ STACKop -1)); /* name as 1st Argument */
  8103. pushSTACK(*(structure_ STACKop 0)); /* Structure as 2nd Argument */
  8104. pushSTACK(TheSlotDefinition(*slot_)->slotdef_location); /* (slot-definition-location slot) as 3. Argument */
  8105. funcall(L(pstructure_ref),3);
  8106. prin_object(stream_,value1); /* print component */
  8107. JUSTIFY_END_FILL;
  8108. skipSTACK(1); /* forget slot */
  8109. }
  8110. }
  8111. skipSTACK(1);
  8112. JUSTIFY_END_FILL;
  8113. if (readable) { /* completion of fall differentiation from above */
  8114. INDENT_END;
  8115. PAREN_CLOSE;
  8116. } else {
  8117. UNREADABLE_END;
  8118. }
  8119. skipSTACK(3);
  8120. } else { /* print structure elementwise, without component-name. */
  8121. CHECK_PRINT_READABLY(*structure_);
  8122. UNREADABLE_START;
  8123. var uintC len = Structure_length(*structure_); /* Length of Structure (>=1) */
  8124. JUSTIFY_LAST(len==1);
  8125. prin_object(stream_,*(structure_ STACKop -1)); /* print name */
  8126. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH*-limit */
  8127. var uintL length = 0; /* Index = previous length := 0 */
  8128. for (len = len-1; len > 0; len--) {
  8129. JUSTIFY_SPACE; /* print Space */
  8130. /* check for attaining of *PRINT-LENGTH* : */
  8131. CHECK_LENGTH_LIMIT(length >= length_limit,break);
  8132. /* test for attaining of *PRINT-LINES* : */
  8133. CHECK_LINES_LIMIT(break);
  8134. JUSTIFY_LAST(len==1);
  8135. length++; /* increase index */
  8136. /* print component: */
  8137. prin_object(stream_,TheStructure(*structure_)->recdata[length]);
  8138. }
  8139. JUSTIFY_END_FILL;
  8140. INDENT_END;
  8141. write_ascii_char(stream_,'>');
  8142. skipSTACK(2);
  8143. }
  8144. }
  8145. /* This is the default-function, which is called by CLOS:PRINT-OBJECT: */
  8146. LISPFUNN(print_structure,2) {
  8147. /* stack layout: structure, stream. */
  8148. STACK_1 = check_structure(STACK_1);
  8149. STACK_0 = check_stream(STACK_0);
  8150. pr_enter(&STACK_0,STACK_1,&pr_structure_default);
  8151. skipSTACK(2);
  8152. VALUES1(NIL);
  8153. }
  8154. /* -------- machine pointer --------
  8155. UP: prints machine-pointer to stream.
  8156. pr_machine(&stream,obj);
  8157. > obj: machine-pointer
  8158. > stream: stream
  8159. < stream: stream
  8160. can trigger GC */
  8161. local maygc void pr_machine (const gcv_object_t* stream_, object obj) {
  8162. /* #<ADDRESS #x...> */
  8163. CHECK_PRINT_READABLY(obj);
  8164. pr_unreadably(stream_,obj,&O(printstring_address),pr_hex6);
  8165. }
  8166. /* -------- Frame-Pointer, Small-Read-Label, System --------
  8167. UP: prints systempointer to stream.
  8168. pr_system(&stream,obj);
  8169. > obj: systempointer
  8170. > stream: stream
  8171. < stream: stream
  8172. can trigger GC */
  8173. local maygc void pr_system (const gcv_object_t* stream_, object obj) {
  8174. if (nullpSv(print_readably)) {
  8175. if (!boundp(obj))
  8176. write_sstring_case(stream_,O(printstring_unbound));
  8177. else if (eq(obj,specdecl)) /* #<SPECIAL REFERENCE> */
  8178. write_sstring_case(stream_,O(printstring_special_reference));
  8179. else if (eq(obj,disabled)) /* #<DISABLED POINTER> */
  8180. write_sstring_case(stream_,O(printstring_disabled_pointer));
  8181. else if (eq(obj,dot_value)) /* #<DOT> */
  8182. write_sstring_case(stream_,O(printstring_dot));
  8183. else if (eq(obj,eof_value)) /* #<END OF FILE> */
  8184. write_sstring_case(stream_,O(printstring_eof));
  8185. else /* #<SYSTEM-POINTER #x...> */
  8186. pr_unreadably(stream_,obj,&O(printstring_system),pr_hex6);
  8187. } else {
  8188. if (!boundp(obj))
  8189. write_sstring_case(stream_,O(printstring_unbound_readably));
  8190. else
  8191. error_print_readably(obj);
  8192. }
  8193. }
  8194. /* UP: prints read-label to stream.
  8195. pr_readlabel(&stream,obj);
  8196. > obj: Read-Label
  8197. > stream: Stream
  8198. < stream: Stream
  8199. can trigger GC */
  8200. local maygc void pr_readlabel (const gcv_object_t* stream_, object obj) {
  8201. CHECK_PRINT_READABLY(obj);
  8202. /* #<READ-LABEL ...> */
  8203. UNREADABLE_START;
  8204. JUSTIFY_LAST(false);
  8205. write_sstring_case(stream_,O(printstring_read_label)); /* "READ-LABEL" */
  8206. JUSTIFY_SPACE;
  8207. JUSTIFY_LAST(true);
  8208. var object n = (orecordp(obj) /* BigReadLabel or Small-Read-Label? */
  8209. ? (object)TheBigReadLabel(obj)->brl_value
  8210. : small_read_label_value(obj));
  8211. print_integer(n,10,stream_); /* print n in decimal */
  8212. JUSTIFY_END_FILL;
  8213. UNREADABLE_END;
  8214. }
  8215. /* UP: prints framepointer to stream.
  8216. pr_framepointer(&stream,obj);
  8217. > obj: Frame-Pointer
  8218. > stream: Stream
  8219. < stream: Stream
  8220. can trigger GC */
  8221. local maygc void pr_framepointer_1 (const gcv_object_t* stream_, object obj)
  8222. { pr_uint(stream_,STACK_item_count(uTheFramepointer(obj),
  8223. (gcv_object_t*)STACK_start)); }
  8224. local maygc void pr_framepointer (const gcv_object_t* stream_, object obj) {
  8225. CHECK_PRINT_READABLY(obj);
  8226. /* #<FRAME-POINTER N> */
  8227. pr_unreadably(stream_,obj,&O(printstring_frame_pointer),pr_framepointer_1);
  8228. }
  8229. /* -------- Records --------
  8230. UP: prints the remainder of a Record. Only within a JUSTIFY-block!
  8231. The output normally starts with a JUSTIFY_SPACE.
  8232. pr_record_ab(&stream,&obj,start,now);
  8233. > obj: record
  8234. > start: startindex
  8235. > now: number of already printed items (for *PRINT-LENGTH*)
  8236. > stream: stream
  8237. < stream: stream
  8238. can trigger GC */
  8239. local maygc void pr_record_ab (const gcv_object_t* stream_,
  8240. const gcv_object_t* obj_,
  8241. uintL index, uintL length) {
  8242. var uintL len = Record_length(*obj_); /* length of record */
  8243. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH*-limit */
  8244. while (index < len) { /* index >= Recordlength -> finished */
  8245. JUSTIFY_SPACE; /* print Space */
  8246. /* check for attaining of *PRINT-LENGTH* : */
  8247. CHECK_LENGTH_LIMIT(length >= length_limit,break);
  8248. /* test for attaining of *PRINT-LINES* : */
  8249. CHECK_LINES_LIMIT(break);
  8250. JUSTIFY_LAST(index+1 >= len);
  8251. /* print component: */
  8252. prin_object(stream_,TheRecord(*obj_)->recdata[index]);
  8253. length++; /* increase previous length */
  8254. index++; /* next component */
  8255. }
  8256. }
  8257. /* a pr_routine_t version of pr_record_ab
  8258. pr_record_ab_00(&stream,obj)
  8259. > stream - output stream
  8260. > obj =record
  8261. < stream - same stream
  8262. can trigger GC */
  8263. local maygc void pr_record_ab_00 (const gcv_object_t* stream_, object obj) {
  8264. pushSTACK(obj);
  8265. pr_record_ab(stream_,&STACK_0,0,0);
  8266. skipSTACK(1);
  8267. }
  8268. /* UP: prints a list as the rest of a record.
  8269. Only within a JUSTIFY-blocks!
  8270. The output starts normally with a JUSTIFY_SPACE.
  8271. pr_record_rest(&stream,obj,now);
  8272. > obj: list
  8273. > now: number of already printed items (for *PRINT-LENGTH*)
  8274. > stream: stream
  8275. < stream: stream
  8276. can trigger GC */
  8277. local maygc void pr_record_rest (const gcv_object_t* stream_, object obj,
  8278. uintL length) {
  8279. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH*-limit */
  8280. pushSTACK(obj);
  8281. while (mconsp(STACK_0)) {
  8282. JUSTIFY_SPACE; /* print Space */
  8283. /* check for attaining of *PRINT-LENGTH* : */
  8284. CHECK_LENGTH_LIMIT(length >= length_limit,break);
  8285. /* test for attaining of *PRINT-LINES* : */
  8286. CHECK_LINES_LIMIT(break);
  8287. {
  8288. var object list = STACK_0;
  8289. STACK_0 = Cdr(list); /* shorten list */
  8290. JUSTIFY_LAST(matomp(STACK_0));
  8291. prin_object(stream_,Car(list)); /* print element of list */
  8292. }
  8293. length++; /* increment length */
  8294. }
  8295. skipSTACK(1);
  8296. }
  8297. /* UP: print an OtherRecord with slotname to stream.
  8298. pr_record_descr(&stream,obj,name,readable,slotlist);
  8299. > obj: OtherRecord
  8300. > name: structure-name
  8301. > readable: Flag, if to print re-readably
  8302. > slotlist: list ((slotname . accessor) ...)
  8303. > stream: stream
  8304. < stream: stream
  8305. can trigger GC */
  8306. local maygc void pr_record_descr (const gcv_object_t* stream_, object obj,
  8307. object name, bool readable, object slotlist) {
  8308. LEVEL_CHECK;
  8309. {
  8310. pushSTACK(obj);
  8311. pushSTACK(name);
  8312. pushSTACK(slotlist);
  8313. /* stack layout: obj, name, slotlist. */
  8314. var gcv_object_t* obj_ = &STACK_2;
  8315. /* Es ist *(obj_ STACKop 0) = obj
  8316. und *(obj_ STACKop -1) = name
  8317. und *(obj_ STACKop -2) = slotlist . */
  8318. if (readable) { /* print obj re-readably: */
  8319. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'S');
  8320. PAREN_OPEN;
  8321. INDENT_START(3); /* indent by 3 characters, because of '#S(' */
  8322. JUSTIFY_START(1);
  8323. } else { /* print obj non-re-readably: */
  8324. CHECK_PRINT_READABLY(STACK_2);
  8325. UNREADABLE_START;
  8326. }
  8327. pushSTACK(*(obj_ STACKop -2));
  8328. JUSTIFY_LAST(matomp(STACK_0));
  8329. prin_object(stream_,*(obj_ STACKop -1)); /* print name */
  8330. { /* loop over slot-list STACK_0 : */
  8331. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH*-limit */
  8332. var uintL length = 0; /* previous length := 0 */
  8333. while (mconsp(STACK_0)) {
  8334. {
  8335. var object slotlistr = STACK_0;
  8336. STACK_0 = Cdr(slotlistr); /* shorten list */
  8337. pushSTACK(Car(slotlistr)); /* a single slot */
  8338. }
  8339. JUSTIFY_SPACE; /* print Space */
  8340. /* check attaining of *PRINT-LENGTH* : */
  8341. CHECK_LENGTH_LIMIT(length >= length_limit,
  8342. skipSTACK(1); /* forget slot */
  8343. break);
  8344. /* test for attaining of *PRINT-LINES* : */
  8345. CHECK_LINES_LIMIT(skipSTACK(1);break);
  8346. JUSTIFY_LAST(matomp(STACK_1));
  8347. var gcv_object_t* slot_ = &STACK_0; /* there's the slot */
  8348. JUSTIFY_START(0);
  8349. JUSTIFY_LAST(false);
  8350. write_ascii_char(stream_,':'); /* Keyword-mark */
  8351. /* (first slot) should be a symbol */
  8352. pr_like_symbol(stream_,Symbol_name(Car(*slot_))); /* print symbolnames of the component */
  8353. JUSTIFY_SPACE;
  8354. JUSTIFY_LAST(true);
  8355. pushSTACK(*(obj_ STACKop 0)); /* obj as argument */
  8356. funcall(Cdr(*slot_),1); /* call accessor */
  8357. prin_object(stream_,value1); /* print component */
  8358. JUSTIFY_END_FILL;
  8359. skipSTACK(1); /* forget slot */
  8360. }
  8361. }
  8362. skipSTACK(1);
  8363. JUSTIFY_END_FILL;
  8364. if (readable) { /* completion of fall differentiation from above */
  8365. INDENT_END;
  8366. PAREN_CLOSE;
  8367. } else {
  8368. UNREADABLE_END;
  8369. }
  8370. skipSTACK(3);
  8371. }
  8372. LEVEL_END;
  8373. }
  8374. /* UP: prints an OtherRecord to stream.
  8375. pr_orecord(&stream,obj);
  8376. > obj: OtherRecord
  8377. > stream: stream
  8378. < stream: stream
  8379. can trigger GC */
  8380. local maygc void pr_orecord (const gcv_object_t* stream_, object obj) {
  8381. switch (Record_type(obj)) {
  8382. #ifndef TYPECODES
  8383. case Rectype_string: case Rectype_reallocstring:
  8384. case Rectype_S8string: case Rectype_Imm_S8string:
  8385. case Rectype_S16string: case Rectype_Imm_S16string:
  8386. case Rectype_S32string: case Rectype_Imm_S32string: /* String */
  8387. pr_string(stream_,obj); break;
  8388. case Rectype_bvector: case Rectype_Sbvector: /* bit-vector */
  8389. pr_bvector(stream_,obj); break;
  8390. case Rectype_b2vector: case Rectype_Sb2vector: /* 2bit-vector */
  8391. case Rectype_b4vector: case Rectype_Sb4vector: /* 4bit-vector */
  8392. case Rectype_b8vector: case Rectype_Sb8vector: /* 8bit-vector */
  8393. case Rectype_b16vector: case Rectype_Sb16vector: /* 16bit-vector */
  8394. case Rectype_b32vector: case Rectype_Sb32vector: /* 32bit-vector */
  8395. case Rectype_vector: case Rectype_Svector: /* (vector t) */
  8396. pr_vector(stream_,obj); break;
  8397. case Rectype_mdarray: /* generic Array */
  8398. pr_array(stream_,obj); break;
  8399. case Rectype_Closure: /* Closure */
  8400. pr_closure(stream_,obj); break;
  8401. case Rectype_Instance: /* CLOS-Instance */
  8402. pr_instance(stream_,obj); break;
  8403. case Rectype_Complex: case Rectype_Ratio:
  8404. case Rectype_Dfloat: case Rectype_Ffloat: case Rectype_Lfloat:
  8405. case Rectype_Bignum: /* number */
  8406. pr_number(stream_,obj); break;
  8407. case Rectype_Symbol: /* Symbol */
  8408. pr_symbol(stream_,obj); break;
  8409. #endif
  8410. case Rectype_Hashtable:
  8411. /* depending on *PRINT-ARRAY* :
  8412. #<HASH-TABLE #x...> or
  8413. #S(HASH-TABLE :TEST test [:WEAK ...] [:WARN-IF-NEEDS-REHASH-AFTER-GC T]
  8414. (Key_1 . Value_1) ... (Key_n . Value_n)) */
  8415. LEVEL_CHECK;
  8416. {
  8417. var bool detailed_contents = (!nullpSv(print_array) || !nullpSv(print_readably));
  8418. var bool readable = (detailed_contents && !ht_weak_p(obj));
  8419. pushSTACK(obj); /* save Hash-Table */
  8420. var gcv_object_t* obj_ = &STACK_0; /* and memorize, where it is */
  8421. if (readable) {
  8422. /* #S(HASH-TABLE ...) */
  8423. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'S');
  8424. PAREN_OPEN;
  8425. INDENT_START(3); /* indent by 3 characters, because of '#S(' */
  8426. JUSTIFY_START(1);
  8427. } else {
  8428. /* #<HASH-TABLE ...> */
  8429. CHECK_PRINT_READABLY(obj);
  8430. UNREADABLE_START;
  8431. }
  8432. JUSTIFY_LAST(false);
  8433. prin_object(stream_,S(hash_table)); /* print symbol HASH-TABLE */
  8434. obj = *obj_;
  8435. var bool show_test = true;
  8436. var bool show_weak = ht_weak_p(obj);
  8437. var bool show_warn = ((record_flags(TheHashtable(obj)) & htflags_warn_gc_rehash_B) != 0);
  8438. var bool show_contents = (!detailed_contents || !eq(TheHashedAlist(TheHashtable(obj)->ht_kvtable)->hal_count,Fixnum_0));
  8439. if (show_test) {
  8440. JUSTIFY_SPACE; JUSTIFY_LAST(!(show_weak||show_warn||show_contents));
  8441. {
  8442. JUSTIFY_START(0); JUSTIFY_LAST(false);
  8443. prin_object(stream_,S(Ktest)); /* print :TEST */
  8444. JUSTIFY_SPACE; JUSTIFY_LAST(true);
  8445. prin_object(stream_,hash_table_test(*obj_));
  8446. JUSTIFY_END_FILL;
  8447. }
  8448. }
  8449. if (show_weak) {
  8450. JUSTIFY_SPACE; JUSTIFY_LAST(!(show_warn||show_contents));
  8451. {
  8452. JUSTIFY_START(0); JUSTIFY_LAST(false);
  8453. prin_object(stream_,S(Kweak)); /* print :WEAK */
  8454. JUSTIFY_SPACE; JUSTIFY_LAST(true);
  8455. prin_object(stream_,hash_table_weak_type(*obj_)); /*:KEY/:VALUE/:KEY-AND-VALUE/:KEY-OR-VALUE*/
  8456. JUSTIFY_END_FILL;
  8457. }
  8458. }
  8459. if (show_warn) {
  8460. JUSTIFY_SPACE; JUSTIFY_LAST(!show_contents);
  8461. {
  8462. JUSTIFY_START(0); JUSTIFY_LAST(false);
  8463. prin_object(stream_,S(Kwarn_if_needs_rehash_after_gc)); /* print :WARN-IF-NEEDS-REHASH-AFTER-GC */
  8464. JUSTIFY_SPACE; JUSTIFY_LAST(true);
  8465. prin_object(stream_,T); /* print T */
  8466. JUSTIFY_END_FILL;
  8467. }
  8468. }
  8469. obj = *obj_;
  8470. if (show_contents) {
  8471. if (detailed_contents) {
  8472. var uintL index = /* move Index into the Key-Value-Vector */
  8473. 3*posfixnum_to_V(TheHashtable(obj)->ht_maxcount);
  8474. pushSTACK(TheHashtable(obj)->ht_kvtable); /* Key-Value-Vector */
  8475. var uintL count = posfixnum_to_V(TheHashedAlist(STACK_0)->hal_count);
  8476. pr_kvtable(stream_,&STACK_0,index,count);
  8477. skipSTACK(1);
  8478. } else {
  8479. JUSTIFY_SPACE; JUSTIFY_LAST(false);
  8480. {
  8481. JUSTIFY_START(0); JUSTIFY_LAST(false);
  8482. prin_object(stream_,S(Kcount)); /* print :COUNT */
  8483. JUSTIFY_SPACE; JUSTIFY_LAST(true);
  8484. prin_object(stream_,TheHashedAlist(TheHashtable(*obj_)->ht_kvtable)->hal_count); /* print hash-table-count */
  8485. JUSTIFY_END_FILL;
  8486. }
  8487. JUSTIFY_SPACE; JUSTIFY_LAST(true);
  8488. pr_hex6(stream_,*obj_);
  8489. }
  8490. }
  8491. JUSTIFY_END_FILL;
  8492. if (readable) {
  8493. INDENT_END;
  8494. PAREN_CLOSE;
  8495. } else {
  8496. UNREADABLE_END;
  8497. }
  8498. skipSTACK(1);
  8499. }
  8500. LEVEL_END;
  8501. break;
  8502. case Rectype_Package: {
  8503. /* depending on *PRINT-READABLY*:
  8504. #<PACKAGE name> or #.(SYSTEM::%FIND-PACKAGE "name") */
  8505. pushSTACK(obj); /* save package */
  8506. var gcv_object_t* obj_ = &STACK_0; /* and memorize, where it is */
  8507. if (nullpSv(print_readably)) {
  8508. UNREADABLE_START;
  8509. JUSTIFY_LAST(false);
  8510. if (pack_deletedp(*obj_))
  8511. write_sstring_case(stream_,O(printstring_deleted)); /* "DELETED " */
  8512. write_sstring_case(stream_,O(printstring_package)); /* "PACKAGE" */
  8513. JUSTIFY_SPACE;
  8514. JUSTIFY_LAST(true);
  8515. pr_like_symbol(stream_,ThePackage(*obj_)->pack_name); /* print Name */
  8516. JUSTIFY_END_FILL;
  8517. UNREADABLE_END;
  8518. } else {
  8519. if (nullpSv(read_eval) && !stream_get_fasl(*stream_))
  8520. error_print_readably(*obj_);
  8521. if (pack_deletedp(*obj_))
  8522. error_print_readably(*obj_);
  8523. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'.');
  8524. PAREN_OPEN; /* '(' */
  8525. INDENT_START(3); /* indent by 3 characters, because of '#.(' */
  8526. JUSTIFY_START(1);
  8527. JUSTIFY_LAST(false);
  8528. pr_symbol(stream_,S(pfind_package)); /* SYSTEM::%FIND-PACKAGE */
  8529. JUSTIFY_SPACE;
  8530. JUSTIFY_LAST(true);
  8531. pr_string(stream_,ThePackage(*obj_)->pack_name); /* print Name */
  8532. JUSTIFY_END_FILL;
  8533. INDENT_END;
  8534. PAREN_CLOSE;
  8535. }
  8536. skipSTACK(1);
  8537. } break;
  8538. case Rectype_Readtable: /* #<READTABLE #x...> */
  8539. CHECK_PRINT_READABLY(obj);
  8540. pr_unreadably(stream_,obj,&O(printstring_readtable),pr_hex6);
  8541. break;
  8542. case Rectype_Pathname: {
  8543. #ifdef IO_DEBUG
  8544. pr_record_descr(stream_,obj,S(pathname),true,O(pathname_slotlist));
  8545. #else
  8546. pushSTACK(obj); /* pathname */
  8547. /* call (NAMESTRING pathname) */
  8548. pushSTACK(obj); funcall(L(namestring),1); obj = value1;
  8549. ASSERT(stringp(obj));
  8550. pushSTACK(obj); /* string */
  8551. if (nullpSv(print_readably)) { /* not readably */
  8552. if (!nullpSv(print_escape)) { /* print "#P" */
  8553. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'P');
  8554. }
  8555. pr_string(stream_,STACK_0); /* print the string */
  8556. } else if (stream_get_fasl(*stream_)) { /* readably & compiling */
  8557. pr_record_descr(stream_,STACK_1,S(pathname),true,O(pathname_slotlist));
  8558. } else if (nullpSv(print_pathnames_ansi)) { /* readably, not ANSI */
  8559. var gcv_object_t* obj_ = &STACK_0;
  8560. JUSTIFY_START(0);
  8561. JUSTIFY_LAST(false);
  8562. JUSTIFY_START(0);
  8563. JUSTIFY_LAST(false);
  8564. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'-');
  8565. write_sstring(stream_,O(lisp_implementation_type_string));
  8566. JUSTIFY_SPACE;
  8567. JUSTIFY_LAST(true);
  8568. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'P');
  8569. pr_string(stream_,*obj_);
  8570. JUSTIFY_END_FILL;
  8571. JUSTIFY_SPACE;
  8572. JUSTIFY_LAST(true);
  8573. JUSTIFY_START(0);
  8574. JUSTIFY_LAST(false);
  8575. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'+');
  8576. write_sstring(stream_,O(lisp_implementation_type_string));
  8577. JUSTIFY_SPACE;
  8578. JUSTIFY_LAST(true);
  8579. pr_record_descr(stream_,*(obj_ STACKop 1),S(pathname),true,
  8580. O(pathname_slotlist));
  8581. JUSTIFY_END_FILL; JUSTIFY_END_FILL;
  8582. } else { /* readably ANSI */
  8583. if (!namestring_correctly_parseable_p(&STACK_1))
  8584. error_print_readably(STACK_1);
  8585. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'P');
  8586. pr_string(stream_,STACK_0); /* #P"string" */
  8587. }
  8588. skipSTACK(2);
  8589. #endif
  8590. } break;
  8591. #ifdef LOGICAL_PATHNAMES
  8592. case Rectype_Logpathname:
  8593. if (!nullpSv(print_readably) || nullpSv(parse_namestring_ansi)) {
  8594. /* when printing readably or when "host:path" is not logical
  8595. #S(LOGICAL-PATHNAME :HOST host :DIRECTORY directory :NAME name
  8596. :TYPE type :VERSION version) */
  8597. pr_record_descr(stream_,obj,S(logical_pathname),
  8598. true,O(pathname_slotlist));
  8599. } else { /* #P"namestring" or just namestring */
  8600. pushSTACK(obj); funcall(L(namestring),1); obj = value1; /* string */
  8601. if (!nullpSv(print_escape)) { /* #P */
  8602. pushSTACK(obj);
  8603. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'P');
  8604. obj = popSTACK();
  8605. }
  8606. pr_string(stream_,obj);
  8607. }
  8608. break;
  8609. #endif
  8610. case Rectype_Random_State: /* #S(RANDOM-STATE seed) */
  8611. LEVEL_CHECK;
  8612. {
  8613. pushSTACK(obj); /* save Random-State */
  8614. var gcv_object_t* obj_ = &STACK_0; /* and memorize, where it is */
  8615. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'S');
  8616. PAREN_OPEN;
  8617. INDENT_START(3); /* indent by 3 characters, because of '#S(' */
  8618. JUSTIFY_START(1);
  8619. JUSTIFY_LAST(false);
  8620. prin_object(stream_,S(random_state)); /* print Symbol RANDOM-STATE */
  8621. pr_record_ab(stream_,obj_,0,0); /* print component */
  8622. JUSTIFY_END_FILL;
  8623. INDENT_END;
  8624. PAREN_CLOSE;
  8625. skipSTACK(1);
  8626. }
  8627. LEVEL_END;
  8628. break;
  8629. #ifndef case_structure
  8630. case Rectype_Structure: /* Structure */
  8631. pr_structure(stream_,obj); break;
  8632. #endif
  8633. #ifndef case_stream
  8634. case Rectype_Stream: /* Stream */
  8635. pr_stream(stream_,obj); break;
  8636. #endif
  8637. case Rectype_Byte: {
  8638. #if 0
  8639. /* #<BYTE size position> */
  8640. CHECK_PRINT_READABLY(obj);
  8641. pr_unreadably(stream_,obj,&O(printstring_byte),pr_record_ab_00);
  8642. #else
  8643. /* #S(BYTE :SIZE size :POSITION position) */
  8644. pr_record_descr(stream_,obj,S(byte),true,O(byte_slotlist));
  8645. #endif
  8646. } break;
  8647. #ifdef LINUX_NOEXEC_HEAPCODES
  8648. case Rectype_Subr: /* Subr */
  8649. pr_subr(stream_,obj);
  8650. break;
  8651. #endif
  8652. case Rectype_Fsubr: /* Fsubr */
  8653. pr_fsubr(stream_,obj);
  8654. break;
  8655. case Rectype_Loadtimeeval: /* #.form */
  8656. if (!nullpSv(print_readably))
  8657. if (nullpSv(read_eval)) {
  8658. pushSTACK(obj);
  8659. var bool allowed = stream_get_fasl(*stream_);
  8660. obj = popSTACK();
  8661. if (!allowed)
  8662. error_print_readably(obj);
  8663. }
  8664. pr_sharp_dot(stream_,TheLoadtimeeval(obj)->loadtimeeval_form);
  8665. break;
  8666. case Rectype_Symbolmacro: /* #<SYMBOL-MACRO expansion> */
  8667. CHECK_PRINT_READABLY(obj);
  8668. pr_unreadably(stream_,obj,&O(printstring_symbolmacro),pr_record_ab_00);
  8669. break;
  8670. case Rectype_GlobalSymbolmacro: /* #<GLOBAL SYMBOL-MACRO expansion> */
  8671. CHECK_PRINT_READABLY(obj);
  8672. pr_unreadably(stream_,TheSymbolmacro(TheGlobalSymbolmacro(obj)->globalsymbolmacro_definition)->symbolmacro_expansion,
  8673. &O(printstring_globalsymbolmacro),prin_object);
  8674. break;
  8675. case Rectype_Macro: /* #<MACRO expansion lambda-list> */
  8676. CHECK_PRINT_READABLY(obj);
  8677. pr_unreadably(stream_,obj,&O(printstring_macro),pr_record_ab_00);
  8678. break;
  8679. case Rectype_FunctionMacro: /* #<FUNCTION-MACRO expansion> */
  8680. CHECK_PRINT_READABLY(obj);
  8681. pr_unreadably(stream_,obj,&O(printstring_functionmacro),pr_record_ab_00);
  8682. break;
  8683. case Rectype_BigReadLabel: /* #<READ-LABEL n> */
  8684. pr_readlabel(stream_,obj);
  8685. break;
  8686. case Rectype_Encoding: /* #<ENCODING [charset] line-terminator> */
  8687. CHECK_PRINT_READABLY(obj);
  8688. LEVEL_CHECK;
  8689. {
  8690. pushSTACK(obj); /* save Encoding */
  8691. var gcv_object_t* obj_ = &STACK_0; /* and memorize, where it is */
  8692. UNREADABLE_START;
  8693. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH* */
  8694. #ifdef UNICODE
  8695. JUSTIFY_LAST(length_limit==0);
  8696. #else
  8697. JUSTIFY_LAST(true);
  8698. #endif
  8699. write_sstring_case(stream_,O(printstring_encoding)); /* "ENCODING" */
  8700. {
  8701. var uintL length = 0; /* previous length := 0 */
  8702. #ifdef UNICODE
  8703. /* check for attaining of *PRINT-LENGTH* : */
  8704. if (length >= length_limit) goto encoding_end;
  8705. JUSTIFY_SPACE; /* print Space */
  8706. JUSTIFY_LAST(length+1 >= length_limit);
  8707. /* print Charset: */
  8708. prin_object(stream_,TheEncoding(*obj_)->enc_charset);
  8709. length++; /* increase previous length */
  8710. #endif
  8711. /* check for attaining of *PRINT-LENGTH* : */
  8712. if (length >= length_limit) goto encoding_end;
  8713. JUSTIFY_SPACE; /* print Space */
  8714. JUSTIFY_LAST(true);
  8715. /* print Line-Terminator: */
  8716. prin_object(stream_,TheEncoding(*obj_)->enc_eol);
  8717. length++; /* increase previous length */
  8718. }
  8719. encoding_end:
  8720. JUSTIFY_END_FILL;
  8721. UNREADABLE_END;
  8722. skipSTACK(1);
  8723. }
  8724. LEVEL_END;
  8725. break;
  8726. #ifdef FOREIGN
  8727. case Rectype_Fpointer: /* #<FOREIGN-POINTER address> */
  8728. CHECK_PRINT_READABLY(obj);
  8729. LEVEL_CHECK;
  8730. {
  8731. var bool validp = fp_validp(TheFpointer(obj));
  8732. var uintP val = (uintP)(TheFpointer(obj)->fp_pointer); /* fetch value */
  8733. UNREADABLE_START;
  8734. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH* */
  8735. JUSTIFY_LAST(length_limit==0);
  8736. if (!validp)
  8737. write_sstring_case(stream_,O(printstring_invalid)); /* "INVALID " */
  8738. write_sstring_case(stream_,O(printstring_fpointer)); /* FOREIGN-POINTER */
  8739. {
  8740. var uintL length = 0; /* previous length := 0 */
  8741. /* check for attaining of *PRINT-LENGTH* : */
  8742. if (length >= length_limit) goto fpointer_end;
  8743. JUSTIFY_SPACE; /* print Space */
  8744. JUSTIFY_LAST(true);
  8745. /* print Address: */
  8746. pr_hex8(stream_,val);
  8747. length++; /* increase previous length */
  8748. }
  8749. fpointer_end:
  8750. JUSTIFY_END_FILL;
  8751. UNREADABLE_END;
  8752. }
  8753. LEVEL_END;
  8754. break;
  8755. #endif
  8756. #ifdef DYNAMIC_FFI
  8757. case Rectype_Faddress: /* #<FOREIGN-ADDRESS #x...> */
  8758. CHECK_PRINT_READABLY(obj);
  8759. LEVEL_CHECK;
  8760. {
  8761. pushSTACK(obj); /* save */
  8762. var gcv_object_t* obj_ = &STACK_0; /* and memorize, where it is */
  8763. UNREADABLE_START;
  8764. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH* */
  8765. JUSTIFY_LAST(length_limit==0);
  8766. if (!fp_validp(TheFpointer(TheFaddress(*obj_)->fa_base)))
  8767. write_sstring_case(stream_,O(printstring_invalid)); /* "INVALID " */
  8768. write_sstring_case(stream_,O(printstring_faddress)); /* FOREIGN-ADDRESS */
  8769. {
  8770. var uintL length = 0; /* previous length := 0 */
  8771. /* check for attaining of *PRINT-LENGTH* : */
  8772. if (length >= length_limit) goto faddress_end;
  8773. JUSTIFY_SPACE; /* print Space */
  8774. JUSTIFY_LAST(true);
  8775. /* print Address: */
  8776. pr_hex8(stream_,(uintP)Faddress_value(*obj_));
  8777. length++; /* increase previous length */
  8778. }
  8779. faddress_end:
  8780. JUSTIFY_END_FILL;
  8781. UNREADABLE_END;
  8782. skipSTACK(1);
  8783. }
  8784. LEVEL_END;
  8785. break;
  8786. case Rectype_Fvariable: /* #<FOREIGN-VARIABLE name #x...> */
  8787. CHECK_PRINT_READABLY(obj);
  8788. LEVEL_CHECK;
  8789. {
  8790. pushSTACK(obj); /* save */
  8791. var gcv_object_t* obj_ = &STACK_0; /* and memorize, where it is */
  8792. UNREADABLE_START;
  8793. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH* */
  8794. JUSTIFY_LAST(length_limit==0);
  8795. if (!fp_validp(TheFpointer(TheFaddress(TheFvariable(*obj_)->fv_address)->fa_base)))
  8796. write_sstring_case(stream_,O(printstring_invalid)); /* "INVALID " */
  8797. write_sstring_case(stream_,O(printstring_fvariable)); /* FOREIGN-VARIABLE */
  8798. {
  8799. var uintL length = 0; /* previous length := 0 */
  8800. /* check for attaining of *PRINT-LENGTH* : */
  8801. if (length >= length_limit) goto fvariable_end;
  8802. JUSTIFY_SPACE; /* print Space */
  8803. /* print Name: */
  8804. if (!nullp(TheFvariable(*obj_)->fv_name)) {
  8805. JUSTIFY_LAST(length+1 >= length_limit);
  8806. prin_object(stream_,TheFvariable(*obj_)->fv_name);
  8807. if (!nullp(TheFfunction(*obj_)->ff_version)) {
  8808. write_ascii_char(stream_,'@');
  8809. prin_object(stream_,TheFfunction(*obj_)->ff_version);
  8810. }
  8811. length++; /* increase previous length */
  8812. if (length >= length_limit) goto fvariable_end;
  8813. JUSTIFY_SPACE; /* print Space */
  8814. }
  8815. JUSTIFY_LAST(true);
  8816. /* print Address: */
  8817. var object faddress = TheFvariable(*obj_)->fv_address;
  8818. pr_hex8(stream_,(uintP)Faddress_value(faddress));
  8819. length++; /* increase previous length */
  8820. }
  8821. fvariable_end:
  8822. JUSTIFY_END_FILL;
  8823. UNREADABLE_END;
  8824. skipSTACK(1);
  8825. }
  8826. LEVEL_END;
  8827. break;
  8828. case Rectype_Ffunction: /* #<FOREIGN-FUNCTION name #x...> */
  8829. CHECK_PRINT_READABLY(obj);
  8830. LEVEL_CHECK;
  8831. {
  8832. pushSTACK(obj); /* save */
  8833. var gcv_object_t* obj_ = &STACK_0; /* and memorize, where it is */
  8834. UNREADABLE_START;
  8835. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH* */
  8836. JUSTIFY_LAST(length_limit==0);
  8837. if (!fp_validp(TheFpointer(TheFaddress(TheFfunction(*obj_)->ff_address)->fa_base)))
  8838. write_sstring_case(stream_,O(printstring_invalid)); /* "INVALID " */
  8839. write_sstring_case(stream_,O(printstring_ffunction)); /* FOREIGN-FUNCTION */
  8840. {
  8841. var uintL length = 0; /* previous length := 0 */
  8842. /* check for attaining of *PRINT-LENGTH*: */
  8843. if (length >= length_limit) goto ffunction_end;
  8844. JUSTIFY_SPACE; /* print Space */
  8845. /* print Name: */
  8846. if (!nullp(TheFfunction(*obj_)->ff_name)) {
  8847. JUSTIFY_LAST(length+1 >= length_limit);
  8848. prin_object(stream_,TheFfunction(*obj_)->ff_name);
  8849. if (!nullp(TheFfunction(*obj_)->ff_version)) {
  8850. write_ascii_char(stream_,'@');
  8851. prin_object(stream_,TheFfunction(*obj_)->ff_version);
  8852. }
  8853. length++; /* increase previous length */
  8854. if (length >= length_limit) goto ffunction_end;
  8855. JUSTIFY_SPACE; /* print Space */
  8856. }
  8857. JUSTIFY_LAST(true);
  8858. /* print Address: */
  8859. var object faddress = TheFfunction(*obj_)->ff_address;
  8860. pr_hex8(stream_,(uintP)Faddress_value(faddress));
  8861. length++; /* increase previous length */
  8862. }
  8863. ffunction_end:
  8864. JUSTIFY_END_FILL;
  8865. UNREADABLE_END;
  8866. skipSTACK(1);
  8867. }
  8868. LEVEL_END;
  8869. break;
  8870. #endif
  8871. case Rectype_Weakpointer: /* #<WEAK-POINTER value> or #<BROKEN WEAK-POINTER> */
  8872. CHECK_PRINT_READABLY(obj);
  8873. if (!weakpointer_broken_p(obj))
  8874. pr_unreadably(stream_,TheWeakpointer(obj)->wp_value,
  8875. &O(printstring_weakpointer),prin_object);
  8876. else
  8877. write_sstring_case(stream_,O(printstring_broken_weakpointer));
  8878. break;
  8879. case Rectype_MutableWeakList: /* #<WEAK-LIST (element1 ...)> */
  8880. CHECK_PRINT_READABLY(obj);
  8881. LEVEL_CHECK;
  8882. {
  8883. pushSTACK(TheMutableWeakList(obj)->mwl_list); /* save list */
  8884. var gcv_object_t* wl_ = &STACK_0; /* and memorize, where it is */
  8885. var uintL wl_length = Lrecord_length(*wl_)-2;
  8886. UNREADABLE_START;
  8887. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH* */
  8888. JUSTIFY_LAST(length_limit==0);
  8889. write_sstring_case(stream_,O(printstring_weak_list)); /* "WEAK-LIST" */
  8890. {
  8891. /* check for attaining of *PRINT-LENGTH*: */
  8892. if (0 >= length_limit) goto weak_list_end;
  8893. JUSTIFY_SPACE; /* print Space */
  8894. JUSTIFY_LAST(true);
  8895. /* Now the list (element1 ...): */
  8896. LEVEL_CHECK;
  8897. var uintL length = 0; /* previous length := 0 */
  8898. PAREN_OPEN; /* '(' */
  8899. INDENT_START(get_indent_lists()); /* indent by 1 character, because of '(' */
  8900. JUSTIFY_START(1);
  8901. /* test for attaining of *PRINT-LENGTH* : */
  8902. CHECK_LENGTH_LIMIT(length_limit==0,goto weak_list_end);
  8903. /* test for attaining of *PRINT-LINES* : */
  8904. CHECK_LINES_LIMIT(goto weak_list_end);
  8905. var uintL i1;
  8906. for (i1 = 0; i1 < wl_length; i1++)
  8907. if (!eq(TheWeakList(*wl_)->wl_elements[i1],unbound))
  8908. break;
  8909. if (i1 < wl_length) {
  8910. pushSTACK(TheWeakList(*wl_)->wl_elements[i1]);
  8911. while (1) {
  8912. var uintL i2;
  8913. for (i2 = i1+1; i2 < wl_length; i2++)
  8914. if (!eq(TheWeakList(*wl_)->wl_elements[i2],unbound))
  8915. break;
  8916. JUSTIFY_LAST(i2 == wl_length);
  8917. var object element = STACK_0; /* = TheWeakList(*wl_)->wl_elements[i1] */
  8918. if (i2 < wl_length)
  8919. STACK_0 = TheWeakList(*wl_)->wl_elements[i2];
  8920. prin_object(stream_,element);
  8921. length++; /* increment length */
  8922. if (i2 == wl_length)
  8923. break;
  8924. JUSTIFY_SPACE; /* print one Space */
  8925. /* check for attaining *PRINT-LENGTH* : */
  8926. CHECK_LENGTH_LIMIT(length >= length_limit,break);
  8927. /* check for attaining *PRINT-LINES* : */
  8928. CHECK_LINES_LIMIT(break);
  8929. i1 = i2;
  8930. }
  8931. skipSTACK(1);
  8932. }
  8933. JUSTIFY_END_FILL;
  8934. INDENT_END;
  8935. PAREN_CLOSE;
  8936. LEVEL_END;
  8937. }
  8938. weak_list_end:
  8939. JUSTIFY_END_FILL;
  8940. UNREADABLE_END;
  8941. skipSTACK(1);
  8942. }
  8943. LEVEL_END;
  8944. break;
  8945. case Rectype_MutableWeakAlist: /* #<WEAK-ALIST (pair1 ...)> */
  8946. CHECK_PRINT_READABLY(obj);
  8947. LEVEL_CHECK;
  8948. {
  8949. pushSTACK(TheMutableWeakAlist(obj)->mwal_list); /* save list */
  8950. var gcv_object_t* wal_ = &STACK_0; /* and memorize, where it is */
  8951. var uintL wal_length = (Lrecord_length(*wal_)-2)/2;
  8952. UNREADABLE_START;
  8953. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH* */
  8954. JUSTIFY_LAST(length_limit==0);
  8955. write_sstring_case(stream_,O(printstring_weak_alist)); /* "WEAK-ALIST" */
  8956. {
  8957. /* check for attaining of *PRINT-LENGTH*: */
  8958. if (0 >= length_limit) goto weak_alist_end;
  8959. JUSTIFY_SPACE; /* print Space */
  8960. JUSTIFY_LAST(true);
  8961. /* Now the list (pair1 ...): */
  8962. LEVEL_CHECK;
  8963. var uintL length = 0; /* previous length := 0 */
  8964. PAREN_OPEN; /* '(' */
  8965. INDENT_START(get_indent_lists()); /* indent by 1 character, because of '(' */
  8966. JUSTIFY_START(1);
  8967. /* test for attaining of *PRINT-LENGTH* : */
  8968. CHECK_LENGTH_LIMIT(length_limit==0,goto weak_alist_end);
  8969. /* test for attaining of *PRINT-LINES* : */
  8970. CHECK_LINES_LIMIT(goto weak_alist_end);
  8971. var uintL i1;
  8972. for (i1 = 0; i1 < wal_length; i1++)
  8973. if (!eq(TheWeakAlist(*wal_)->wal_data[2*i1+0],unbound))
  8974. break;
  8975. if (i1 < wal_length) {
  8976. pushSTACK(TheWeakAlist(*wal_)->wal_data[2*i1+0]);
  8977. pushSTACK(TheWeakAlist(*wal_)->wal_data[2*i1+1]);
  8978. while (1) {
  8979. var uintL i2;
  8980. for (i2 = i1+1; i2 < wal_length; i2++)
  8981. if (!eq(TheWeakAlist(*wal_)->wal_data[2*i2+0],unbound))
  8982. break;
  8983. JUSTIFY_LAST(i2 == wal_length);
  8984. var object key = STACK_1; /* = TheWeakAlist(*wal_)->wal_data[2*i1+0] */
  8985. var object value = STACK_0; /* = TheWeakAlist(*wal_)->wal_data[2*i1+1] */
  8986. if (i2 < wal_length) {
  8987. STACK_1 = TheWeakAlist(*wal_)->wal_data[2*i2+0];
  8988. STACK_0 = TheWeakAlist(*wal_)->wal_data[2*i2+1];
  8989. }
  8990. pr_pair(stream_,key,value);
  8991. length++; /* increment length */
  8992. if (i2 == wal_length)
  8993. break;
  8994. JUSTIFY_SPACE; /* print one Space */
  8995. /* check for attaining *PRINT-LENGTH* : */
  8996. CHECK_LENGTH_LIMIT(length >= length_limit,break);
  8997. /* check for attaining *PRINT-LINES* : */
  8998. CHECK_LINES_LIMIT(break);
  8999. i1 = i2;
  9000. }
  9001. skipSTACK(2);
  9002. }
  9003. JUSTIFY_END_FILL;
  9004. INDENT_END;
  9005. PAREN_CLOSE;
  9006. LEVEL_END;
  9007. }
  9008. weak_alist_end:
  9009. JUSTIFY_END_FILL;
  9010. UNREADABLE_END;
  9011. skipSTACK(1);
  9012. }
  9013. LEVEL_END;
  9014. break;
  9015. case Rectype_Weakmapping: /* #<WEAK-MAPPING (key . value)> or #<BROKEN WEAK-MAPPING> */
  9016. CHECK_PRINT_READABLY(obj);
  9017. if (!eq(TheWeakmapping(obj)->wm_value,unbound))
  9018. pr_unreadably_2(stream_,TheWeakmapping(obj)->wm_value,
  9019. TheWeakmapping(obj)->wm_key,
  9020. &O(printstring_weakmapping));
  9021. else
  9022. write_sstring_case(stream_,O(printstring_broken_weakmapping));
  9023. break;
  9024. case Rectype_Finalizer: /* #<FINALIZER> */
  9025. CHECK_PRINT_READABLY(obj);
  9026. write_sstring_case(stream_,O(printstring_finalizer));
  9027. break;
  9028. #ifdef SOCKET_STREAMS
  9029. case Rectype_Socket_Server: /* #<SOCKET-SERVER host:port> */
  9030. CHECK_PRINT_READABLY(obj);
  9031. LEVEL_CHECK;
  9032. {
  9033. pushSTACK(obj); /* save */
  9034. var gcv_object_t* obj_ = &STACK_0; /* and memorize, where it is */
  9035. UNREADABLE_START;
  9036. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH* */
  9037. JUSTIFY_LAST(length_limit==0);
  9038. /* if closed, print "CLOSED " : */
  9039. if (nullp(TheSocketServer(*obj_)->socket_handle))
  9040. write_sstring_case(stream_,O(printstring_closed));
  9041. write_sstring_case(stream_,O(printstring_socket_server)); /* SOCKET-SERVER */
  9042. {
  9043. var uintL length = 0; /* previous length := 0 */
  9044. /* check for attaining of *PRINT-LENGTH*: */
  9045. if (length >= length_limit) goto socket_server_end;
  9046. JUSTIFY_SPACE; /* print Space */
  9047. JUSTIFY_LAST(true);
  9048. /* output host */
  9049. write_string(stream_,TheSocketServer(*obj_)->host);
  9050. write_ascii_char(stream_,':'); /* print Port: */
  9051. pr_number(stream_,TheSocketServer(*obj_)->port);
  9052. length++; /* increase previous length */
  9053. }
  9054. socket_server_end:
  9055. JUSTIFY_END_FILL;
  9056. UNREADABLE_END;
  9057. skipSTACK(1);
  9058. }
  9059. LEVEL_END;
  9060. break;
  9061. #endif
  9062. #ifdef YET_ANOTHER_RECORD
  9063. case Rectype_Yetanother: /* #<YET-ANOTHER address> */
  9064. CHECK_PRINT_READABLY(obj);
  9065. LEVEL_CHECK;
  9066. {
  9067. pushSTACK(obj); /* save Yetanother */
  9068. var gcv_object_t* obj_ = &STACK_0; /* and memorize, where it is */
  9069. UNREADABLE_START;
  9070. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH* */
  9071. JUSTIFY_LAST(length_limit==0);
  9072. write_sstring_case(stream_,O(printstring_yetanother)); /* YET-ANOTHER */
  9073. {
  9074. var uintL length = 0; /* previous length := 0 */
  9075. /* check for attaining of *PRINT-LENGTH*: */
  9076. if (length >= length_limit) goto yetanother_end;
  9077. JUSTIFY_SPACE; /* print Space */
  9078. JUSTIFY_LAST(true);
  9079. /* print x: */
  9080. pr_hex6(stream_,TheYetanother(*obj_)->yetanother_x);
  9081. length++; /* increase previous length */
  9082. }
  9083. yetanother_end:
  9084. JUSTIFY_END_FILL;
  9085. UNREADABLE_END;
  9086. skipSTACK(1);
  9087. }
  9088. LEVEL_END;
  9089. break;
  9090. #endif
  9091. case Rectype_WeakList: /* #<INTERNAL-WEAK-LIST> */
  9092. CHECK_PRINT_READABLY(obj);
  9093. write_sstring_case(stream_,O(printstring_internal_weak_list));
  9094. break;
  9095. case Rectype_WeakAnd: /* #<WEAK-AND-RELATION keys-list> or #<BROKEN WEAK-AND-RELATION> */
  9096. CHECK_PRINT_READABLY(obj);
  9097. if (!eq(TheWeakAnd(obj)->war_keys_list,unbound))
  9098. pr_unreadably(stream_,TheWeakAnd(obj)->war_keys_list,
  9099. &O(printstring_weak_and_relation),prin_object);
  9100. else
  9101. write_sstring_case(stream_,O(printstring_broken_weak_and_relation));
  9102. break;
  9103. case Rectype_WeakOr: /* #<WEAK-OR-RELATION keys-list> or #<BROKEN WEAK-OR-RELATION> */
  9104. CHECK_PRINT_READABLY(obj);
  9105. if (!eq(TheWeakOr(obj)->wor_keys_list,unbound))
  9106. pr_unreadably(stream_,TheWeakOr(obj)->wor_keys_list,
  9107. &O(printstring_weak_or_relation),prin_object);
  9108. else
  9109. write_sstring_case(stream_,O(printstring_broken_weak_or_relation));
  9110. break;
  9111. case Rectype_WeakAndMapping: /* #<WEAK-AND-MAPPING (keys-list . value)> or #<BROKEN WEAK-AND-MAPPING> */
  9112. CHECK_PRINT_READABLY(obj);
  9113. if (!eq(TheWeakAndMapping(obj)->wam_keys_list,unbound))
  9114. pr_unreadably_2(stream_,TheWeakAndMapping(obj)->wam_value,
  9115. TheWeakAndMapping(obj)->wam_keys_list,
  9116. &O(printstring_weak_and_mapping));
  9117. else
  9118. write_sstring_case(stream_,O(printstring_broken_weak_and_mapping));
  9119. break;
  9120. case Rectype_WeakOrMapping: /* #<WEAK-OR-MAPPING (keys-list . value)> or #<BROKEN WEAK-OR-MAPPING> */
  9121. CHECK_PRINT_READABLY(obj);
  9122. if (!eq(TheWeakOrMapping(obj)->wom_keys_list,unbound))
  9123. pr_unreadably_2(stream_,TheWeakOrMapping(obj)->wom_value,
  9124. TheWeakOrMapping(obj)->wom_keys_list,
  9125. &O(printstring_weak_or_mapping));
  9126. else
  9127. write_sstring_case(stream_,O(printstring_broken_weak_or_mapping));
  9128. break;
  9129. case Rectype_WeakAlist_Key:
  9130. case Rectype_WeakAlist_Value:
  9131. case Rectype_WeakAlist_Either:
  9132. case Rectype_WeakAlist_Both: /* #<INTERNAL-WEAK-ALIST> */
  9133. CHECK_PRINT_READABLY(obj);
  9134. write_sstring_case(stream_,O(printstring_internal_weak_alist));
  9135. break;
  9136. case Rectype_WeakHashedAlist_Key:
  9137. case Rectype_WeakHashedAlist_Value:
  9138. case Rectype_WeakHashedAlist_Either:
  9139. case Rectype_WeakHashedAlist_Both: /* #<INTERNAL-WEAK-HASHED-ALIST> */
  9140. CHECK_PRINT_READABLY(obj);
  9141. write_sstring_case(stream_,O(printstring_internal_weak_hashed_alist));
  9142. break;
  9143. #ifdef MULTITHREAD
  9144. case Rectype_Thread:
  9145. CHECK_PRINT_READABLY(obj);
  9146. pr_unreadably(stream_,TheThread(obj)->xth_name,
  9147. &O(printstring_thread),prin_object);
  9148. break;
  9149. case Rectype_Mutex:
  9150. CHECK_PRINT_READABLY(obj);
  9151. pr_unreadably(stream_,TheMutex(obj)->xmu_name,
  9152. &O(printstring_mutex),prin_object);
  9153. break;
  9154. case Rectype_Exemption:
  9155. CHECK_PRINT_READABLY(obj);
  9156. pr_unreadably(stream_,TheExemption(obj)->xco_name,
  9157. &O(printstring_exemption),prin_object);
  9158. break;
  9159. #endif
  9160. default:
  9161. pushSTACK(S(print));
  9162. error(serious_condition,
  9163. GETTEXT("~S: an unknown record type has been generated!"));
  9164. }
  9165. }
  9166. /* -------- SUBRs, FSUBRs --------
  9167. UP: prints SUBR to Stream.
  9168. pr_subr(&stream,obj);
  9169. > obj: SUBR
  9170. > stream: Stream
  9171. < stream: Stream
  9172. can trigger GC */
  9173. local maygc void pr_subr (const gcv_object_t* stream_, object obj) {
  9174. /* #<SYSTEM-FUNCTION name> bzw. #<ADD-ON-SYSTEM-FUNCTION name>
  9175. bzw. #.(SYSTEM::%FIND-SUBR 'name) */
  9176. if (!nullpSv(print_readably)) {
  9177. if (nullpSv(read_eval)) {
  9178. pushSTACK(obj);
  9179. var bool allowed = stream_get_fasl(*stream_);
  9180. obj = popSTACK();
  9181. if (!allowed)
  9182. error_print_readably(obj);
  9183. }
  9184. pushSTACK(obj); /* save obj */
  9185. var gcv_object_t* obj_ = &STACK_0; /* and memorize, where it is */
  9186. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'.');
  9187. PAREN_OPEN; /* '(' */
  9188. INDENT_START(3); /* indent by 3 characters, because of '#.(' */
  9189. JUSTIFY_START(1);
  9190. JUSTIFY_LAST(false);
  9191. pr_symbol(stream_,S(find_subr)); /* SYSTEM::%FIND-SUBR */
  9192. JUSTIFY_SPACE;
  9193. JUSTIFY_LAST(true);
  9194. write_ascii_char(stream_,'\'');
  9195. pr_symbol(stream_,TheSubr(*obj_)->name); /* print Name */
  9196. JUSTIFY_END_FILL;
  9197. INDENT_END;
  9198. PAREN_CLOSE;
  9199. skipSTACK(1);
  9200. } else
  9201. pr_unreadably(stream_,TheSubr(obj)->name,
  9202. ((as_oint(subr_tab_ptr_as_object(&subr_tab)) <=
  9203. as_oint(obj))
  9204. && (as_oint(obj) <
  9205. as_oint(subr_tab_ptr_as_object(&subr_tab+1))))
  9206. ? &O(printstring_subr) : &O(printstring_addon_subr),
  9207. prin_object);
  9208. }
  9209. /* UP: prints FSUBR to Stream.
  9210. pr_fsubr(&stream,obj);
  9211. > obj: FSUBR
  9212. > stream: Stream
  9213. < stream: Stream
  9214. can trigger GC */
  9215. local maygc void pr_fsubr (const gcv_object_t* stream_, object obj) {
  9216. /* #<SPECIAL-OPERATOR name> */
  9217. CHECK_PRINT_READABLY(obj);
  9218. pr_unreadably(stream_,TheFsubr(obj)->name,&O(printstring_fsubr),prin_object);
  9219. }
  9220. /* -------- Closures --------
  9221. UP: prints Closure to Stream.
  9222. pr_closure(&stream,obj);
  9223. > obj: Closure
  9224. > stream: Stream
  9225. < stream: Stream
  9226. can trigger GC */
  9227. local maygc void pr_closure (const gcv_object_t* stream_, object obj) {
  9228. if (Closure_instancep(obj)) {
  9229. /* funcallable instance */
  9230. pr_instance(stream_,obj);
  9231. } else if (simple_bit_vector_p(Atype_8Bit,TheClosure(obj)->clos_codevec)) {
  9232. /* compiled Closure */
  9233. pr_cclosure(stream_,obj);
  9234. } else {
  9235. /* print interpreted Closure: #<FUNCTION ...>
  9236. if *PRINT-CLOSURE* /= NIL, print everything, else print Name and
  9237. (if still existing) Lambdalist and forms: */
  9238. CHECK_PRINT_READABLY(obj);
  9239. LEVEL_CHECK;
  9240. {
  9241. pushSTACK(obj); /* save Closure */
  9242. var gcv_object_t* obj_ = &STACK_0; /* and memorize, where it is */
  9243. UNREADABLE_START;
  9244. JUSTIFY_LAST(false);
  9245. write_sstring_case(stream_,O(printstring_closure));
  9246. if (!nullpSv(print_closure)) { /* query *PRINT-CLOSURE* */
  9247. /* *PRINT-CLOSURE* /= NIL -> print #<FUNCTION komponente1 ...> : */
  9248. pr_record_ab(stream_,obj_,0,0); /* print the remaining components */
  9249. } else {
  9250. /* *PRINT-CLOSURE* = NIL -> print #<FUNCTION name . form> : */
  9251. JUSTIFY_SPACE;
  9252. prin_object(stream_,TheIclosure(*obj_)->clos_name); /* print Name */
  9253. /* print form-list elementwise: */
  9254. pr_record_rest(stream_,TheIclosure(*obj_)->clos_form,1);
  9255. }
  9256. JUSTIFY_END_FILL;
  9257. UNREADABLE_END;
  9258. skipSTACK(1);
  9259. }
  9260. LEVEL_END;
  9261. }
  9262. }
  9263. /* UP: prints compiled Closure to Stream.
  9264. pr_cclosure(&stream,obj);
  9265. > obj: compiled Closure
  9266. > stream: Stream
  9267. < stream: Stream
  9268. can trigger GC */
  9269. local maygc void pr_cclosure (const gcv_object_t* stream_, object obj) {
  9270. /* query *PRINT-CLOSURE* : */
  9271. if (!nullpSv(print_closure) || !nullpSv(print_readably))
  9272. /* *PRINT-CLOSURE /= NIL -> print in re-readable form #Y(...) */
  9273. pr_cclosure_lang(stream_,obj);
  9274. else
  9275. /* *PRINT-CLOSURE* = NIL -> only print #<COMPILED-FUNCTION name> : */
  9276. pr_unreadably(stream_,Closure_name(obj),&O(printstring_compiled_closure),
  9277. prin_object);
  9278. }
  9279. /* print compiled Closure in rereadable Form:
  9280. (defun %print-cclosure (closure)
  9281. (princ "#Y(")
  9282. (prin1 (closure-name closure))
  9283. (princ " #")
  9284. (let ((L (closure-codevec closure)))
  9285. (let ((*print-base* 10.)) (prin1 (length L)))
  9286. (princ "Y(")
  9287. (let ((*print-base* 16.))
  9288. (do ((i 0 (1- i))
  9289. (x L (cdr x)))
  9290. ((endp x))
  9291. (when (zerop i) (terpri) (setq i 25))
  9292. (princ " ")
  9293. (prin1 (car x))))
  9294. (princ ")"))
  9295. (terpri)
  9296. (dolist (x (closure-consts closure))
  9297. (princ " ")
  9298. (prin1 x))
  9299. (princ ")") )
  9300. UP: prints compiled Closure in re-readable form
  9301. to stream.
  9302. pr_cclosure_lang(&stream,obj);
  9303. > obj: compiled Closure
  9304. > stream: Stream
  9305. < stream: Stream
  9306. can trigger GC */
  9307. local maygc void pr_cclosure_lang (const gcv_object_t* stream_, object obj) {
  9308. LEVEL_CHECK;
  9309. {
  9310. pushSTACK(obj); /* save Closure */
  9311. var gcv_object_t* obj_ = &STACK_0; /* and memorize, where it is */
  9312. write_ascii_char(stream_,'#'); write_ascii_char(stream_,'Y');
  9313. PAREN_OPEN;
  9314. INDENT_START(3); /* indent by 3 characters, because of '#Y(' */
  9315. JUSTIFY_START(1);
  9316. JUSTIFY_LAST(false);
  9317. prin_object(stream_,Closure_name(*obj_)); /* print Name */
  9318. JUSTIFY_SPACE;
  9319. /* print Codevector bytewise, treat possible circularity: */
  9320. var object codevec = TheCclosure(*obj_)->clos_codevec;
  9321. var uintB ccv_flags = TheCodevec(codevec)->ccv_flags;
  9322. pr_circle(stream_,codevec,&pr_cclosure_codevector);
  9323. JUSTIFY_SPACE;
  9324. PAREN_OPEN; /* ( */
  9325. INDENT_START(get_indent_lists()); /* ==> indent by 1 character */
  9326. JUSTIFY_START(1);
  9327. /* ignore *PRINT-LENGTH* & *PRINT-LINES* because of *PRINT-READABLE* */
  9328. var uintL last = Cclosure_last_const(*obj_);
  9329. var uintL pos = 0;
  9330. var bool lambda_list_p = ccv_flags_lambda_list_p(ccv_flags);
  9331. var bool documentation_p = ccv_flags_documentation_p(ccv_flags);
  9332. var bool jitc_p = ccv_flags_jitc_p(ccv_flags);
  9333. var uintL end = last - lambda_list_p - documentation_p - jitc_p;
  9334. if (end != (uintL)-1)
  9335. for (; true; pos++) {
  9336. prin_object(stream_,TheCclosure(*obj_)->clos_consts[pos]);
  9337. JUSTIFY_LAST(pos==end);
  9338. if (pos==end) break;
  9339. JUSTIFY_SPACE; /* print one Space */
  9340. }
  9341. JUSTIFY_END_FILL;
  9342. INDENT_END;
  9343. PAREN_CLOSE;
  9344. JUSTIFY_SPACE;
  9345. prin_object(stream_,seclass_object((seclass_t)Cclosure_seclass(*obj_)));
  9346. if (lambda_list_p) { /* lambda-list is a list */
  9347. JUSTIFY_SPACE;
  9348. pr_list(stream_,TheCclosure(*obj_)->clos_consts[++end]);
  9349. if (documentation_p) { /* documentation is a string or NIL */
  9350. JUSTIFY_SPACE;
  9351. prin_object(stream_,TheCclosure(*obj_)->clos_consts[++end]);
  9352. if (jitc_p) { /* jitc_p: 0 or 1 */
  9353. JUSTIFY_SPACE;
  9354. write_ascii_char(stream_,'1');
  9355. }
  9356. }
  9357. }
  9358. JUSTIFY_END_FILL;
  9359. INDENT_END;
  9360. PAREN_CLOSE;
  9361. skipSTACK(1);
  9362. }
  9363. LEVEL_END;
  9364. }
  9365. /* UP: prints Closure-Codevector in #nY(...)-notation
  9366. to Stream.
  9367. pr_cclosure_codevector(&stream,codevec);
  9368. > codevec: a Simple-Bit-Vector
  9369. > stream: Stream
  9370. < stream: Stream
  9371. can trigger GC */
  9372. local maygc void pr_cclosure_codevector (const gcv_object_t* stream_, object codevec) {
  9373. LEVEL_CHECK;
  9374. {
  9375. pushSTACK(codevec); /* save Codevector */
  9376. var gcv_object_t* codevec_ = &STACK_0; /* and memorize, where it is */
  9377. var uintL len = Sbvector_length(codevec); /* length in Bytes */
  9378. #if BIG_ENDIAN_P
  9379. var uintL header_end_index =
  9380. (TheSbvector(codevec)->data[CCV_FLAGS] & bit(7) ?
  9381. CCV_START_KEY : CCV_START_NONKEY);
  9382. #endif
  9383. /* print prefix: */
  9384. INDENTPREP_START;
  9385. write_ascii_char(stream_,'#');
  9386. pr_uint(stream_,len); /* print length decimally */
  9387. write_ascii_char(stream_,'Y');
  9388. {
  9389. var uintV indent = INDENTPREP_END;
  9390. /* print main part: */
  9391. INDENT_START(indent); /* indent */
  9392. }
  9393. PAREN_OPEN;
  9394. INDENT_START(1); /* indent by 1 character, because of '(' */
  9395. JUSTIFY_START(1);
  9396. {
  9397. var uintL length_limit = get_print_length(); /* *PRINT-LENGTH*-limit */
  9398. var uintL length = 0; /* Index = previous length := 0 */
  9399. for ( ; len > 0; len--) {
  9400. /* print Space (except before the first element): */
  9401. if (!(length==0))
  9402. JUSTIFY_SPACE;
  9403. /* check for attaining of *PRINT-LENGTH*: */
  9404. CHECK_LENGTH_LIMIT(length >= length_limit,break);
  9405. /* test for attaining of *PRINT-LINES* : */
  9406. CHECK_LINES_LIMIT(break);
  9407. JUSTIFY_LAST(len==1 || length+1 >= length_limit);
  9408. codevec = *codevec_;
  9409. var uintL index = length;
  9410. #if BIG_ENDIAN_P
  9411. /* calculate Byte-Index, converting Big-Endian -> Little-Endian : */
  9412. if (index < header_end_index) {
  9413. switch (index) {
  9414. case CCV_SPDEPTH_1: case CCV_SPDEPTH_1+1:
  9415. case CCV_SPDEPTH_JMPBUFSIZE: case CCV_SPDEPTH_JMPBUFSIZE+1:
  9416. case CCV_NUMREQ: case CCV_NUMREQ+1:
  9417. case CCV_NUMOPT: case CCV_NUMOPT+1:
  9418. case CCV_NUMKEY: case CCV_NUMKEY+1:
  9419. case CCV_KEYCONSTS: case CCV_KEYCONSTS+1:
  9420. index = index^1;
  9421. break;
  9422. default:
  9423. break;
  9424. }
  9425. }
  9426. #endif
  9427. /* print Byte: */
  9428. pr_hex2(stream_,TheSbvector(codevec)->data[index]);
  9429. length++; /* increase index */
  9430. }
  9431. }
  9432. JUSTIFY_END_FILL;
  9433. INDENT_END;
  9434. PAREN_CLOSE;
  9435. INDENT_END;
  9436. skipSTACK(1);
  9437. }
  9438. LEVEL_END;
  9439. }
  9440. /* -------- Streams --------
  9441. UP: prints stream to stream.
  9442. pr_stream(&stream,obj);
  9443. > obj: Stream to be printed
  9444. > stream: Stream
  9445. < stream: Stream
  9446. can trigger GC */
  9447. local maygc void pr_stream (const gcv_object_t* stream_, object obj) {
  9448. CHECK_PRINT_READABLY(obj);
  9449. pushSTACK(obj); /* save Stream */
  9450. var gcv_object_t* obj_ = &STACK_0; /* and memorize, where it is */
  9451. UNREADABLE_START;
  9452. JUSTIFY_LAST(false);
  9453. /* if Stream is closed, print "CLOSED " : */
  9454. if ((TheStream(*obj_)->strmflags & strmflags_open_B) == 0)
  9455. write_sstring_case(stream_,O(printstring_closed));
  9456. { /* INPUT/OUTPUT/IO */
  9457. var bool input_p = (TheStream(*obj_)->strmflags & strmflags_rd_B) != 0;
  9458. var bool output_p = (TheStream(*obj_)->strmflags & strmflags_wr_B) != 0;
  9459. if (input_p) {
  9460. if (output_p) write_sstring_case(stream_,O(printstring_io));
  9461. else write_sstring_case(stream_,O(printstring_input));
  9462. } else {
  9463. if (output_p) write_sstring_case(stream_,O(printstring_output));
  9464. else write_sstring_case(stream_,O(printstring_invalid));
  9465. }
  9466. }
  9467. /* if a channel or socket stream, print "BUFFERED " or "UNBUFFERED ": */
  9468. var uintL type = TheStream(*obj_)->strmtype;
  9469. switch (type) {
  9470. case strmtype_file:
  9471. #ifdef PIPES
  9472. case strmtype_pipe_in:
  9473. case strmtype_pipe_out:
  9474. #endif
  9475. #ifdef X11SOCKETS
  9476. case strmtype_x11socket:
  9477. #endif
  9478. #ifdef SOCKET_STREAMS
  9479. case strmtype_socket:
  9480. case strmtype_twoway_socket:
  9481. #endif
  9482. write_sstring_case(stream_,
  9483. (&O(printstring_buffered_00))[stream_isbuffered(*obj_)]);
  9484. break;
  9485. default:
  9486. break;
  9487. }
  9488. { /* print Streamtype: */
  9489. var const gcv_object_t* stringtable = &O(printstring_strmtype_synonym);
  9490. write_sstring_case(stream_,stringtable[type]); /* fetch string from table */
  9491. }
  9492. /* print "-STREAM" : */
  9493. write_sstring_case(stream_,O(printstring_stream));
  9494. /* Stream-specific supplementary information: */
  9495. switch (type) {
  9496. #if 0
  9497. /* this is disabled with "#if 0" because the string may be huge.
  9498. normally one should use :i/:d in debugger, as described in
  9499. http://clisp.cons.org/impnotes/faq.html#faq-bad-error
  9500. and enable this only for build process debugging
  9501. when reploop, inspect, and describe are not yet available */
  9502. case strmtype_str_in: /* STRING-INPUT-STREAM */
  9503. JUSTIFY_SPACE; JUSTIFY_LAST(false);
  9504. prin_object(stream_,TheStream(*obj_)->strm_other[0]); /* string */
  9505. write_ascii_char(stream_,':');
  9506. prin_object(stream_,TheStream(*obj_)->strm_other[1]); /* index */
  9507. JUSTIFY_SPACE; JUSTIFY_LAST(false); prin_object(stream_,S(Kstart));
  9508. JUSTIFY_SPACE; JUSTIFY_LAST(false);
  9509. prin_object(stream_,TheStream(*obj_)->strm_other[2]); /* begindex */
  9510. JUSTIFY_SPACE; JUSTIFY_LAST(false); prin_object(stream_,S(Kend));
  9511. JUSTIFY_SPACE; JUSTIFY_LAST(true);
  9512. prin_object(stream_,TheStream(*obj_)->strm_other[3]); /* endindex */
  9513. break;
  9514. #endif
  9515. case strmtype_synonym: /* Synonym-Stream */
  9516. JUSTIFY_SPACE;
  9517. JUSTIFY_LAST(true);
  9518. prin_object(stream_,TheStream(*obj_)->strm_synonym_symbol); /* Symbol */
  9519. break;
  9520. case strmtype_broad: /* Broadcast-Stream */
  9521. pr_record_rest(stream_,TheStream(*obj_)->strm_broad_list,0); /* Streams */
  9522. break;
  9523. case strmtype_twoway: /* two-way stream */
  9524. case strmtype_echo: /* echo stream */
  9525. pushSTACK(TheStream(*obj_)->strm_twoway_input);
  9526. pushSTACK(TheStream(*obj_)->strm_twoway_output);
  9527. pr_record_rest(stream_,listof(2),0);
  9528. break;
  9529. case strmtype_concat: /* Concatenated-Stream */
  9530. pr_record_rest(stream_,TheStream(*obj_)->strm_concat_list,0); /* Streams */
  9531. break;
  9532. case strmtype_buff_in: /* Buffered-Input-Stream */
  9533. JUSTIFY_SPACE;
  9534. JUSTIFY_LAST(true);
  9535. prin_object(stream_,TheStream(*obj_)->strm_buff_in_fun); /* Function */
  9536. break;
  9537. case strmtype_buff_out: /* Buffered-Output-Stream */
  9538. JUSTIFY_SPACE;
  9539. JUSTIFY_LAST(true);
  9540. prin_object(stream_,TheStream(*obj_)->strm_buff_out_fun); /* Function */
  9541. break;
  9542. #ifdef GENERIC_STREAMS
  9543. case strmtype_generic: /* Generic Streams */
  9544. JUSTIFY_SPACE;
  9545. JUSTIFY_LAST(true);
  9546. prin_object(stream_,TheStream(*obj_)->strm_controller_object); /* Controller */
  9547. break;
  9548. #endif
  9549. case strmtype_file: { /* File-Stream */
  9550. var bool fname_p = !nullp(TheStream(*obj_)->strm_file_name);
  9551. var bool lineno_p =
  9552. (eq(TheStream(*obj_)->strm_eltype,S(character))
  9553. && ((TheStream(*obj_)->strmflags & strmflags_rd_B) != 0));
  9554. JUSTIFY_SPACE;
  9555. JUSTIFY_LAST(!fname_p && !lineno_p);
  9556. prin_object(stream_,TheStream(*obj_)->strm_eltype); /* Stream-Element-Type */
  9557. if (fname_p) {
  9558. JUSTIFY_SPACE;
  9559. JUSTIFY_LAST(!lineno_p);
  9560. prin_object(stream_,TheStream(*obj_)->strm_file_name); /* Filename */
  9561. }
  9562. if (lineno_p) {
  9563. JUSTIFY_SPACE;
  9564. JUSTIFY_LAST(true);
  9565. /* print line-number, in which stream currently is: */
  9566. write_ascii_char(stream_,'@');
  9567. pr_number(stream_,stream_line_number(*obj_));
  9568. }
  9569. } break;
  9570. #ifdef PIPES
  9571. case strmtype_pipe_in: case strmtype_pipe_out: /* Pipe-In/Out-Stream */
  9572. JUSTIFY_SPACE;
  9573. JUSTIFY_LAST(false);
  9574. prin_object(stream_,TheStream(*obj_)->strm_eltype); /* Stream-Element-Type */
  9575. JUSTIFY_SPACE;
  9576. JUSTIFY_LAST(true);
  9577. pr_uint(stream_,I_to_UL(TheStream(*obj_)->strm_pipe_pid)); /* Process-Id */
  9578. break;
  9579. #endif
  9580. #ifdef X11SOCKETS
  9581. case strmtype_x11socket: /* X11-Socket-Stream */
  9582. JUSTIFY_SPACE;
  9583. JUSTIFY_LAST(true);
  9584. prin_object(stream_,TheStream(*obj_)->strm_x11socket_connect); /* connection destination */
  9585. break;
  9586. #endif
  9587. #ifdef SOCKET_STREAMS
  9588. case strmtype_twoway_socket:
  9589. *obj_ = TheStream(*obj_)->strm_twoway_socket_input;
  9590. /*FALLTHROUGH*/
  9591. case strmtype_socket: { /* Socket-Stream */
  9592. JUSTIFY_SPACE;
  9593. JUSTIFY_LAST(false);
  9594. prin_object(stream_,TheStream(*obj_)->strm_eltype); /* Stream-Element-Type */
  9595. JUSTIFY_SPACE;
  9596. JUSTIFY_LAST(true);
  9597. {
  9598. var object host = TheStream(*obj_)->strm_socket_host;
  9599. if (!nullp(host))
  9600. write_string(stream_,host);
  9601. }
  9602. write_ascii_char(stream_,':');
  9603. pr_number(stream_,TheStream(*obj_)->strm_socket_port);
  9604. } break;
  9605. #endif
  9606. default: /* else no supplementary information */
  9607. break;
  9608. }
  9609. JUSTIFY_END_FILL;
  9610. UNREADABLE_END;
  9611. skipSTACK(1);
  9612. }
  9613. /* ---------------------- Top-Level-Call of the Printers -------------------
  9614. UP: prints object to stream.
  9615. prin1(&stream,obj);
  9616. > obj: object
  9617. > stream: stream
  9618. < stream: stream
  9619. can trigger GC */
  9620. global maygc void prin1 (const gcv_object_t* stream_, object obj) {
  9621. pr_enter(stream_,obj,&prin_object);
  9622. }
  9623. /* UP: print Newline first, then print an object to stream.
  9624. print(&stream,obj);
  9625. > obj: Object
  9626. > stream: Stream
  9627. < stream: Stream
  9628. can trigger GC */
  9629. local maygc void print (const gcv_object_t* stream_, object obj) {
  9630. pushSTACK(obj); /* save Object */
  9631. write_ascii_char(stream_,NL); /* print #\Newline */
  9632. obj = popSTACK();
  9633. prin1(stream_,obj); /* print Object */
  9634. }
  9635. /* ----------------------- Helper-functions of the Printer -----------------
  9636. UP: Check the output-stream argument.
  9637. The value of *STANDARD-OUTPUT* is the default.
  9638. check_ostream(&stream);
  9639. > stream_: output-stream argument
  9640. < stream_: output-stream (a Stream)
  9641. can trigger GC */
  9642. local maygc void check_ostream (gcv_object_t* stream_) {
  9643. var object stream = *stream_; /* output-stream argument */
  9644. if (missingp(stream)) { /* #<UNBOUND> or NIL -> value of *STANDARD-OUTPUT* */
  9645. *stream_ = var_stream(S(standard_output),strmflags_wr_ch_B);
  9646. } else if (eq(stream,T)) { /* T -> value of *TERMINAL-IO* */
  9647. *stream_ = var_stream(S(terminal_io),strmflags_wr_ch_B);
  9648. } else /* should be a stream */
  9649. *stream_ = check_stream(stream);
  9650. }
  9651. LISPFUNN(whitespacep,1) { /* (SYS::WHITESPACEP CHAR) */
  9652. var object ch = popSTACK();
  9653. value1 = NIL;
  9654. if (charp(ch)) {
  9655. var cint ci = as_cint(char_code(ch));
  9656. if (cint_white_p(ci))
  9657. value1 = T;
  9658. }
  9659. mv_count=1;
  9660. }
  9661. /* (SYS::WRITE-SPACES num &optional stream) */
  9662. LISPFUN(write_spaces,seclass_default,1,1,norest,nokey,0,NIL) {
  9663. check_ostream(&STACK_0);
  9664. STACK_1 = check_posfixnum(STACK_1);
  9665. spaces(&STACK_0,STACK_1);
  9666. VALUES1(NIL); skipSTACK(2);
  9667. }
  9668. /* ---------------------- Pretty Printer ----------------------
  9669. (PPRINT-INDENT relative-to n &optional stream) ==> NIL
  9670. relative-to---either :block or :current.
  9671. n ---a real.
  9672. stream ---an output stream designator. The default is standard output. */
  9673. LISPFUN(pprint_indent,seclass_default,2,1,norest,nokey,0,NIL) {
  9674. check_ostream(&STACK_0);
  9675. /* check the indentation increment */
  9676. STACK_1 = check_real(STACK_1);
  9677. var sintV offset = 0;
  9678. {
  9679. var object num = STACK_1;
  9680. if (!integerp(num)) {
  9681. pushSTACK(num); funcall(L(round),1);
  9682. num = value1;
  9683. }
  9684. if (!fixnump(num)) {
  9685. bad_num:
  9686. pushSTACK(STACK_1); /* TYPE-ERROR slot DATUM */
  9687. pushSTACK(S(fixnum)); /* TYPE-ERROR slot EXPECTED-TYPE */
  9688. pushSTACK(STACK_1); pushSTACK(S(pprint_indent));
  9689. error(type_error,GETTEXT("~S: argument ~S is too large"));
  9690. }
  9691. offset = fixnum_to_V(num);
  9692. if ((oint_data_len==intVsize) && (posfixnump(num) ? offset < 0 : offset >= 0))
  9693. goto bad_num;
  9694. }
  9695. /* check the relative-to arg */
  9696. var object indent = Symbol_value(S(prin_indentation));
  9697. var object linepos = get_line_position(STACK_0);
  9698. var uintV linepos_i = (posfixnump(linepos) ? posfixnum_to_V(linepos) : 0);
  9699. if (eq(S(Kblock),STACK_2)) {
  9700. if (posfixnump(indent))
  9701. offset += posfixnum_to_V(indent);
  9702. } else if (eq(S(Kcurrent),STACK_2)) {
  9703. if (linepos_i > 0)
  9704. offset += linepos_i;
  9705. } else { /* invalid value */
  9706. pushSTACK(STACK_2); /* TYPE-ERROR slot DATUM */
  9707. pushSTACK(O(type_pprint_indent)); /* TYPE-ERROR slot EXPECTED-TYPE */
  9708. pushSTACK(S(Kblock)); pushSTACK(S(Kcurrent));
  9709. pushSTACK(STACK_2);
  9710. pushSTACK(S(pprint_indent));
  9711. error(type_error,GETTEXT("~S: argument ~S should be ~S or ~S."));
  9712. }
  9713. if (PPHELP_STREAM_P(STACK_0) && !nullpSv(print_pretty)) {
  9714. /* set indentation */
  9715. if (offset<0) offset = 0;
  9716. #if IO_DEBUG > 1
  9717. printf("pprint-indent: %d --> %d\n",
  9718. !boundp(Symbol_value(S(prin_indentation))) ? -1 :
  9719. posfixnum_to_V(Symbol_value(S(prin_indentation))),offset);
  9720. #endif
  9721. Symbol_value(S(prin_indentation)) = fixnum(offset);
  9722. if (linepos_i < offset)
  9723. spaces(&STACK_0,fixnum(offset-linepos_i));
  9724. }
  9725. VALUES1(NIL); skipSTACK(3);
  9726. }
  9727. typedef enum {
  9728. PPRINT_NEWLINE_LINEAR,
  9729. PPRINT_NEWLINE_FILL,
  9730. PPRINT_NEWLINE_MISER,
  9731. PPRINT_NEWLINE_MANDATORY
  9732. } pprint_newline_t;
  9733. /* (PPRINT-NEWLINE kind &optional stream) ==> NIL
  9734. kind ---one of :linear, :fill, :miser, or :mandatory.
  9735. stream---a stream designator. The default is standard output. */
  9736. LISPFUN(pprint_newline,seclass_default,1,1,norest,nokey,0,NIL) {
  9737. check_ostream(&STACK_0);
  9738. var pprint_newline_t ppn_type = PPRINT_NEWLINE_MANDATORY;
  9739. if (eq(S(Klinear),STACK_1)) ppn_type = PPRINT_NEWLINE_LINEAR;
  9740. else if (eq(S(Kfill),STACK_1)) ppn_type = PPRINT_NEWLINE_FILL;
  9741. else if (eq(S(Kmiser),STACK_1)) ppn_type = PPRINT_NEWLINE_MISER;
  9742. else if (eq(S(Kmandatory),STACK_1)) ppn_type = PPRINT_NEWLINE_MANDATORY;
  9743. else { /* invalid value */
  9744. pushSTACK(STACK_1); /* TYPE-ERROR slot DATUM */
  9745. pushSTACK(O(type_pprint_newline)); /* TYPE-ERROR slot EXPECTED-TYPE */
  9746. pushSTACK(S(Klinear)); pushSTACK(S(Kfill));
  9747. pushSTACK(S(Kmiser)); pushSTACK(S(Kmandatory));
  9748. pushSTACK(STACK_1);
  9749. pushSTACK(S(pprint_newline));
  9750. error(type_error,GETTEXT("~S: argument ~S should be ~S, ~S, ~S or ~S."));
  9751. }
  9752. if (PPHELP_STREAM_P(STACK_0) && !nullpSv(print_pretty))
  9753. switch (ppn_type) {
  9754. case PPRINT_NEWLINE_MISER: {
  9755. if (nullpSv(prin_miserp)) /* miser style */
  9756. break;
  9757. STACK_1 = S(Klinear);
  9758. } /*FALLTHROUGH*/
  9759. case PPRINT_NEWLINE_LINEAR: {
  9760. if (eq(TheStream(STACK_0)->strm_pphelp_modus,mehrzeiler))
  9761. goto mandatory;
  9762. } /*FALLTHROUGH*/
  9763. case PPRINT_NEWLINE_FILL: {
  9764. cons_ssstring(&STACK_0,STACK_1);
  9765. } break;
  9766. case PPRINT_NEWLINE_MANDATORY: mandatory: {
  9767. cons_ssstring(&STACK_0,NIL);
  9768. } break;
  9769. }
  9770. VALUES1(NIL); skipSTACK(2);
  9771. }
  9772. local pr_routine_t pprin_object;
  9773. local pr_routine_t pprin_object_dispatch;
  9774. local void pprin_object (const gcv_object_t* stream_,object obj)
  9775. { prin_object_ki(stream_,obj,&pprin_object_dispatch); }
  9776. /* SYS::*PRIN-PPRINTER* == the lisp function */
  9777. local void pprin_object_dispatch (const gcv_object_t* stream_,object obj) {
  9778. LEVEL_CHECK;
  9779. var uintC count = pr_external_1(*stream_); /* instantiate bindings */
  9780. pushSTACK(*stream_); pushSTACK(obj);
  9781. funcall(Symbol_value(S(prin_pprinter)),2);
  9782. pr_external_2(count); /* dissolve bindings */
  9783. LEVEL_END;
  9784. }
  9785. /* (%PPRINT-LOGICAL-BLOCK function object stream) */
  9786. LISPFUNN(ppprint_logical_block,3) {
  9787. check_ostream(&STACK_0);
  9788. if (listp(STACK_1)) {
  9789. var gcv_object_t* stream_ = &STACK_0;
  9790. var object obj = STACK_1;
  9791. var object func = STACK_2;
  9792. dynamic_bind(S(prin_pprinter),func); /* *PRIN-PPRINTER* */
  9793. pr_enter(stream_,obj,&pprin_object);
  9794. dynamic_unbind(S(prin_pprinter)); /* *PRIN-PPRINTER* */
  9795. } else
  9796. pr_enter(&STACK_0,STACK_1,&prin_object);
  9797. VALUES1(NIL); skipSTACK(3);
  9798. }
  9799. /* (%CIRCLEP object stream)
  9800. return the appropriate read label or NIL
  9801. called from PPRINT-POP */
  9802. LISPFUNN(pcirclep,2) {
  9803. check_ostream(&STACK_0);
  9804. /* var circle_info_t ci; */
  9805. if (!circle_p(STACK_1,NULL) || !PPHELP_STREAM_P(STACK_0)) /* &ci */
  9806. VALUES1(NIL);
  9807. else {
  9808. write_ascii_char(&STACK_0,'.');
  9809. write_ascii_char(&STACK_0,' ');
  9810. prin_object(&STACK_0,STACK_1);
  9811. VALUES1(T); /* make_small_read_label(ci.n); */
  9812. }
  9813. skipSTACK(2);
  9814. }
  9815. /* (format-tabulate stream colon-modifier atsign-modifier
  9816. &optional (colnum 1) (colinc 1))
  9817. see format.lisp */
  9818. LISPFUN(format_tabulate,seclass_default,3,2,norest,nokey,0,NIL) {
  9819. check_ostream(&STACK_4);
  9820. STACK_1 = missingp(STACK_1) ? Fixnum_1 : check_posfixnum(STACK_1);
  9821. STACK_0 = missingp(STACK_0) ? Fixnum_1 : check_posfixnum(STACK_0);
  9822. if (PPHELP_STREAM_P(STACK_0) && !nullpSv(print_pretty)) {
  9823. var object tab_spec = allocate_vector(4);
  9824. PPH_TAB_COLON(tab_spec) = STACK_3;
  9825. PPH_TAB_ATSIG(tab_spec) = STACK_2;
  9826. PPH_TAB_COL_N(tab_spec) = STACK_1;
  9827. PPH_TAB_COL_I(tab_spec) = STACK_0;
  9828. var object list = TheStream(STACK_4)->strm_pphelp_strings;
  9829. pushSTACK(tab_spec);
  9830. if (stringp(Car(list)) && (0==vector_length(Car(list)))) {
  9831. /* last string is empty -- keep it! */
  9832. var object new_cons = allocate_cons();
  9833. Car(new_cons) = popSTACK();
  9834. Cdr(new_cons) = Cdr(TheStream(STACK_0)->strm_pphelp_strings);
  9835. Cdr(TheStream(STACK_0)->strm_pphelp_strings) = new_cons;
  9836. } else {
  9837. pushSTACK(make_ssstring(SEMI_SIMPLE_DEFAULT_SIZE));
  9838. swap(object,STACK_0,STACK_1);
  9839. var object new_cons = listof(2);
  9840. Cdr(Cdr(new_cons)) = TheStream(STACK_0)->strm_pphelp_strings;
  9841. TheStream(STACK_0)->strm_pphelp_strings = new_cons;
  9842. }
  9843. } else {
  9844. var bool bind_margin = false; /* fill-out.lisp:with-stream-s-expression */
  9845. var gcv_object_t *stream_ = &STACK_4;
  9846. var object colp = STACK_3;
  9847. var object atp = STACK_2;
  9848. var object coln = STACK_1;
  9849. var object coli = STACK_0;
  9850. if (!builtin_stream_p(STACK_4)) {
  9851. object f = Symbol_function(S(stream_start_s_expression));
  9852. if (boundp(f)) {
  9853. pushSTACK(STACK_4); funcall(f,1);
  9854. dynamic_bind(S(print_right_margin),value1);
  9855. bind_margin = true;
  9856. }
  9857. }
  9858. spaces(stream_,fixnum(format_tab(*stream_,colp,atp,coln,coli)));
  9859. if (bind_margin) {
  9860. pushSTACK(*stream_); funcall(S(stream_end_s_expression),1);
  9861. dynamic_unbind(S(print_right_margin));
  9862. }
  9863. }
  9864. VALUES1(NIL); skipSTACK(5);
  9865. }
  9866. /* ----------------------- LISP-functions of the Printer -------------------
  9867. Print-Variables (ref. CONSTSYM.D):
  9868. *PRINT-CASE* ----+
  9869. *PRINT-LEVEL* |
  9870. *PRINT-LENGTH* |
  9871. *PRINT-GENSYM* |
  9872. *PRINT-ESCAPE* | order fixed!
  9873. *PRINT-RADIX* | the same order as in CONSTSYM.D
  9874. *PRINT-BASE* | also for the SUBRs WRITE, WRITE-TO-STRING
  9875. *PRINT-ARRAY* |
  9876. *PRINT-CIRCLE* |
  9877. *PRINT-PRETTY* |
  9878. *PRINT-CLOSURE* |
  9879. *PRINT-READABLY* |
  9880. *PRINT-LINES* |
  9881. *PRINT-MISER-WIDTH* |
  9882. *PRINT-PPRINT-DISPATCH* |
  9883. *PRINT-RIGHT-MARGIN* ---+
  9884. first Print-Variable: */
  9885. #define first_print_var S(print_case)
  9886. /* number of Print-Variables: */
  9887. #define print_vars_count 16
  9888. /* UP: for WRITE and WRITE-TO-STRING
  9889. > STACK_(print_vars_count+1): Object
  9890. > STACK_(print_vars_count)..STACK_(1): Arguments to the Print-Variables
  9891. > STACK_0: Stream */
  9892. local void write_up (void) {
  9893. /* Pointer over the Keyword-Arguments */
  9894. var gcv_object_t* argptr = args_end_pointer STACKop (1+print_vars_count+1);
  9895. var object obj = NEXT(argptr); /* first Argument = Object */
  9896. /* bind the specified Variable: */
  9897. var uintC bindcount = 0; /* number of bindings */
  9898. {
  9899. var object sym = first_print_var; /* loops over the Symbols */
  9900. var uintC count;
  9901. dotimesC(count,print_vars_count, {
  9902. var object arg = NEXT(argptr); /* next Keyword-Argument */
  9903. if (boundp(arg)) { /* specified? */
  9904. dynamic_bind(sym,arg); bindcount++; /* yes -> pind Variable to it */
  9905. }
  9906. sym = objectplus(sym,(soint)sizeof(*TheSymbol(sym))<<(oint_addr_shift-addr_shift)); /* next Symbol */
  9907. });
  9908. }
  9909. {
  9910. var gcv_object_t* stream_ = &NEXT(argptr); /* next Argument is the Stream */
  9911. prin1(stream_,obj); /* print Object */
  9912. }
  9913. /* dissolve bindings: */
  9914. dotimesC(bindcount,bindcount, { dynamic_unbind_g(); } );
  9915. }
  9916. /* (WRITE object [:stream] [:escape] [:radix] [:base] [:circle] [:pretty]
  9917. [:level] [:length] [:case] [:gensym] [:array] [:closure]
  9918. [:readably] [:lines] [:miser-width] [:pprint-dispatch]
  9919. [:right-margin]),
  9920. CLTL p. 382 */
  9921. LISPFUN(write,seclass_default,1,0,norest,key,17,
  9922. (kw(case),kw(level),kw(length),kw(gensym),kw(escape),kw(radix),
  9923. kw(base),kw(array),kw(circle),kw(pretty),kw(closure),kw(readably),
  9924. kw(lines),kw(miser_width),kw(pprint_dispatch),
  9925. kw(right_margin),kw(stream))) {
  9926. /* stack layout: object, Print-Variablen-Arguments, Stream-Argument. */
  9927. check_ostream(&STACK_0); /* check Output-Stream */
  9928. write_up(); /* execute WRITE */
  9929. skipSTACK(print_vars_count+1);
  9930. VALUES1(popSTACK()); /* object as value */
  9931. }
  9932. /* (defun prin1 (object &optional stream)
  9933. (test-output-stream stream)
  9934. (let ((*print-escape* t))
  9935. (prin object stream))
  9936. object)
  9937. UP: for PRIN1, PRINT and PRIN1-TO-STRING
  9938. > STACK_1: Object
  9939. > STACK_0: Stream */
  9940. local void prin1_up (void) {
  9941. var object obj = STACK_1;
  9942. var gcv_object_t* stream_ = &STACK_0;
  9943. dynamic_bind(S(print_escape),T); /* bind *PRINT-ESCAPE* to T */
  9944. prin1(stream_,obj); /* print object */
  9945. dynamic_unbind(S(print_escape));
  9946. }
  9947. /* (PRIN1 object [stream]), CLTL p. 383 */
  9948. LISPFUN(prin1,seclass_default,1,1,norest,nokey,0,NIL) {
  9949. check_ostream(&STACK_0); /* check Output-Stream */
  9950. prin1_up(); /* execute PRIN1 */
  9951. skipSTACK(1);
  9952. VALUES1(popSTACK()); /* object as value */
  9953. }
  9954. /* (defun print (object &optional stream)
  9955. (test-output-stream stream)
  9956. (terpri stream)
  9957. (let ((*print-escape* t))
  9958. (prin object stream))
  9959. (write-char #\Space stream)
  9960. object)
  9961. (PRINT object [stream]), CLTL p. 383 */
  9962. LISPFUN(print,seclass_default,1,1,norest,nokey,0,NIL) {
  9963. check_ostream(&STACK_0); /* check Output-Stream */
  9964. terpri(&STACK_0); /* new line */
  9965. prin1_up(); /* execute PRIN1 */
  9966. write_ascii_char(&STACK_0,' '); /* add Space */
  9967. skipSTACK(1);
  9968. VALUES1(popSTACK()); /* object as value */
  9969. }
  9970. /* (defun pprint (object &optional stream)
  9971. (test-output-stream stream)
  9972. (terpri stream)
  9973. (let ((*print-escape* t) (*print-pretty* t))
  9974. (prin object stream))
  9975. (values))
  9976. (PPRINT object [stream]), CLTL p. 383 */
  9977. LISPFUN(pprint,seclass_default,1,1,norest,nokey,0,NIL) {
  9978. check_ostream(&STACK_0); /* check Output-Stream */
  9979. terpri(&STACK_0); /* new line */
  9980. var object obj = STACK_1;
  9981. var gcv_object_t* stream_ = &STACK_0;
  9982. dynamic_bind(S(print_pretty),T); /* bind *PRINT-PRETTY* to T */
  9983. dynamic_bind(S(print_escape),T); /* bind *PRINT-ESCAPE* to T */
  9984. prin1(stream_,obj); /* print object */
  9985. dynamic_unbind(S(print_escape));
  9986. dynamic_unbind(S(print_pretty));
  9987. skipSTACK(2);
  9988. VALUES0; /* no values */
  9989. }
  9990. /* (defun princ (object &optional stream)
  9991. (test-output-stream stream)
  9992. (let ((*print-escape* nil)
  9993. (*print-readably* nil))
  9994. (prin object stream))
  9995. object)
  9996. UP: for PRINC and PRINC-TO-STRING
  9997. > STACK_1: Object
  9998. > STACK_0: Stream */
  9999. local void princ_up (void) {
  10000. var object obj = STACK_1;
  10001. var gcv_object_t* stream_ = &STACK_0;
  10002. dynamic_bind(S(print_escape),NIL); /* bind *PRINT-ESCAPE* to NIL */
  10003. dynamic_bind(S(print_readably),NIL); /* bind *PRINT-READABLY* to NIL */
  10004. prin1(stream_,obj); /* print object */
  10005. dynamic_unbind(S(print_readably));
  10006. dynamic_unbind(S(print_escape));
  10007. }
  10008. /* (PRINC object [stream]), CLTL p. 383 */
  10009. LISPFUN(princ,seclass_default,1,1,norest,nokey,0,NIL) {
  10010. check_ostream(&STACK_0); /* check Output-Stream */
  10011. princ_up(); /* execute PRINC */
  10012. skipSTACK(1);
  10013. VALUES1(popSTACK()); /* object as value */
  10014. }
  10015. /* (defun write-to-string (object &rest args
  10016. &key escape radix base circle pretty level
  10017. length case gensym array closure
  10018. readably lines miser-width
  10019. pprint-dispatch right-margin)
  10020. (with-output-to-string (stream)
  10021. (apply #'write object :stream stream args)))
  10022. (WRITE-TO-STRING object [:escape] [:radix] [:base] [:circle] [:pretty]
  10023. [:level] [:length] [:case] [:gensym] [:array]
  10024. [:closure] [:readably] [:lines] [:miser-width]
  10025. [:pprint-dispatch] [:right-margin]),
  10026. CLTL p. 383 */
  10027. LISPFUN(write_to_string,seclass_default,1,0,norest,key,16,
  10028. (kw(case),kw(level),kw(length),kw(gensym),kw(escape),kw(radix),
  10029. kw(base),kw(array),kw(circle),kw(pretty),kw(closure),kw(readably),
  10030. kw(lines),kw(miser_width),kw(pprint_dispatch),kw(right_margin))) {
  10031. pushSTACK(make_string_output_stream()); /* String-Output-Stream */
  10032. write_up(); /* execute WRITE */
  10033. VALUES1(get_output_stream_string(&STACK_0)); /* Result-String as value */
  10034. skipSTACK(1+print_vars_count+1);
  10035. }
  10036. /* (defun prin1-to-string (object)
  10037. (with-output-to-string (stream) (prin1 object stream)))
  10038. (PRIN1-TO-STRING object), CLTL p. 383 */
  10039. LISPFUNN(prin1_to_string,1) {
  10040. pushSTACK(make_string_output_stream()); /* String-Output-Stream */
  10041. prin1_up(); /* execute PRIN1 */
  10042. VALUES1(get_output_stream_string(&STACK_0)); /* Result-String as value */
  10043. skipSTACK(2);
  10044. }
  10045. /* (defun princ-to-string (object)
  10046. (with-output-to-string (stream) (princ object stream)))
  10047. (PRINC-TO-STRING object), CLTL p. 383 */
  10048. LISPFUNN(princ_to_string,1) {
  10049. pushSTACK(make_string_output_stream()); /* String-Output-Stream */
  10050. princ_up(); /* execute PRINC */
  10051. VALUES1(get_output_stream_string(&STACK_0)); /* Result-String as value */
  10052. skipSTACK(2);
  10053. }
  10054. /* (WRITE-CHAR character [stream]), CLTL p. 384 */
  10055. LISPFUN(write_char,seclass_default,1,1,norest,nokey,0,NIL) {
  10056. check_ostream(&STACK_0); /* check Output-Stream */
  10057. var object ch = check_char(STACK_1); /* character-Argument */
  10058. write_char(&STACK_0,ch);
  10059. VALUES1(ch); /* ch (not jeopardized by GC) as value */
  10060. skipSTACK(2);
  10061. }
  10062. /* UP: for WRITE-STRING and WRITE-LINE:
  10063. checks the Arguments and prints a sub-string to stream.
  10064. > stack layout: String-Argument, Stream-Argument, :START-Argument, :END-Argument.
  10065. < stack layout: Stream, String.
  10066. can trigger GC */
  10067. local maygc void write_string_up (void) {
  10068. check_ostream(&STACK_2); /* check Output-Stream */
  10069. swap(object,STACK_2,STACK_3); /* swap string and stream */
  10070. /* stack layout: stream, string, :START-Argument, :END-Argument.
  10071. check borders: */
  10072. var stringarg arg;
  10073. var object string = test_string_limits_ro(&arg);
  10074. pushSTACK(string);
  10075. /* stack layout: stream, string. */
  10076. write_sstring_ab(&STACK_1,arg.string,arg.offset+arg.index,arg.len);
  10077. }
  10078. /* (WRITE-STRING string [stream] [:start] [:end]), CLTL p. 384 */
  10079. LISPFUN(write_string,seclass_default,1,1,norest,key,2, (kw(start),kw(end)) ) {
  10080. write_string_up(); /* check and print */
  10081. VALUES1(popSTACK()); skipSTACK(1); /* string as value */
  10082. }
  10083. /* (WRITE-LINE string [stream] [:start] [:end]), CLTL p. 384 */
  10084. LISPFUN(write_line,seclass_default,1,1,norest,key,2, (kw(start),kw(end)) ) {
  10085. write_string_up(); /* check and print */
  10086. terpri(&STACK_1); /* new line */
  10087. VALUES1(popSTACK()); skipSTACK(1); /* string as value */
  10088. }
  10089. /* (TERPRI [stream]), CLTL p. 384 */
  10090. LISPFUN(terpri,seclass_default,0,1,norest,nokey,0,NIL) {
  10091. check_ostream(&STACK_0); /* check Output-Stream */
  10092. terpri(&STACK_0); /* new line */
  10093. VALUES1(NIL); skipSTACK(1);
  10094. }
  10095. /* (FRESH-LINE [stream]), CLTL p. 384 */
  10096. LISPFUN(fresh_line,seclass_default,0,1,norest,nokey,0,NIL) {
  10097. check_ostream(&STACK_0); /* check Output-Stream */
  10098. if (fresh_line(&STACK_0)) {
  10099. VALUES1(T);
  10100. } else {
  10101. VALUES1(NIL);
  10102. }
  10103. skipSTACK(1);
  10104. }
  10105. /* (EXT:ELASTIC-NEWLINE [stream]) */
  10106. LISPFUN(elastic_newline,seclass_default,0,1,norest,nokey,0,NIL) {
  10107. check_ostream(&STACK_0); /* check Output-Stream */
  10108. elastic_newline(&STACK_0);
  10109. VALUES1(NIL); skipSTACK(1);
  10110. }
  10111. /* (FINISH-OUTPUT [stream]), CLTL p. 384 */
  10112. LISPFUN(finish_output,seclass_default,0,1,norest,nokey,0,NIL) {
  10113. check_ostream(&STACK_0); /* check Output-Stream */
  10114. finish_output(popSTACK()); /* bring Output to the destination */
  10115. VALUES1(NIL);
  10116. }
  10117. /* (FORCE-OUTPUT [stream]), CLTL p. 384 */
  10118. LISPFUN(force_output,seclass_default,0,1,norest,nokey,0,NIL) {
  10119. check_ostream(&STACK_0); /* check Output-Stream */
  10120. force_output(popSTACK()); /* bring output to destination */
  10121. VALUES1(NIL);
  10122. }
  10123. /* (CLEAR-OUTPUT [stream]), CLTL p. 384 */
  10124. LISPFUN(clear_output,seclass_default,0,1,norest,nokey,0,NIL) {
  10125. check_ostream(&STACK_0); /* check Output-Stream */
  10126. clear_output(popSTACK()); /* delete output */
  10127. VALUES1(NIL);
  10128. }
  10129. /* (SYSTEM::WRITE-UNREADABLE function object stream [:type] [:identity]),
  10130. ref. CLtL2 p. 580 */
  10131. LISPFUN(write_unreadable,seclass_default,3,0,norest,key,2,
  10132. (kw(type),kw(identity)) ) {
  10133. var bool flag_fun = false;
  10134. var bool flag_type = false;
  10135. var bool flag_id = false;
  10136. {
  10137. var object arg = popSTACK(); /* :identity - Argument */
  10138. if (!missingp(arg))
  10139. flag_id = true;
  10140. }
  10141. {
  10142. var object arg = popSTACK(); /* :type - Argument */
  10143. if (!missingp(arg))
  10144. flag_type = true;
  10145. }
  10146. if (!nullp(STACK_2))
  10147. flag_fun = true;
  10148. check_ostream(&STACK_0); /* check Output-Stream */
  10149. CHECK_PRINT_READABLY(STACK_1);
  10150. var gcv_object_t* stream_ = &STACK_0;
  10151. UNREADABLE_START;
  10152. if (flag_type) {
  10153. JUSTIFY_LAST(!flag_fun && !flag_id);
  10154. /* print (TYPE-OF object) : */
  10155. pushSTACK(*(stream_ STACKop 1)); funcall(L(type_of),1);
  10156. prin1(stream_,value1);
  10157. /* If *PRINT-UNREADABLE-ANSI* is true, we follow ANSI-CL and print a space
  10158. in all cases, even when !flag_fun || !flag_id. */
  10159. if (flag_fun || flag_id || !nullpSv(print_unreadable_ansi))
  10160. JUSTIFY_SPACE;
  10161. }
  10162. if (flag_fun) {
  10163. JUSTIFY_LAST(!flag_id);
  10164. funcall(*(stream_ STACKop 2),0); /* (FUNCALL function) */
  10165. }
  10166. if (flag_id) {
  10167. /* If *PRINT-UNREADABLE-ANSI* is true, we follow ANSI-CL and print a space
  10168. in all cases, even when !flag_fun || !flag_type. But when
  10169. !flag_fun && flag_type, the space has already been printed above. */
  10170. if (flag_fun || (!flag_type && !nullpSv(print_unreadable_ansi)))
  10171. JUSTIFY_SPACE;
  10172. JUSTIFY_LAST(true);
  10173. pr_hex6(stream_,*(stream_ STACKop 1));
  10174. }
  10175. JUSTIFY_END_FILL;
  10176. UNREADABLE_END;
  10177. skipSTACK(3);
  10178. VALUES1(NIL);
  10179. }
  10180. /* (SYS::LINE-POSITION [stream]), Auxiliary function for FORMAT ~T,
  10181. returns the position of an (Output-)Stream in the current line, or NIL. */
  10182. LISPFUN(line_position,seclass_default,0,1,norest,nokey,0,NIL) {
  10183. check_ostream(&STACK_0); /* check Output-Stream */
  10184. VALUES1(get_line_position(popSTACK()));
  10185. }