7e00b285f616fdef943caf7805206775b793c64e
[platform/upstream/groff.git] / src / preproc / eqn / other.cpp
1 // -*- C++ -*-
2 /* Copyright (C) 1989-2014  Free Software Foundation, Inc.
3      Written by James Clark (jjc@jclark.com)
4
5 This file is part of groff.
6
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20 #include "eqn.h"
21 #include "pbox.h"
22
23 class accent_box : public pointer_box {
24 private:
25   box *ab;
26 public:
27   accent_box(box *, box *);
28   ~accent_box();
29   int compute_metrics(int);
30   void output();
31   void debug_print();
32   void check_tabs(int);
33 };
34
35 box *make_accent_box(box *p, box *q)
36 {
37   return new accent_box(p, q);
38 }
39
40 accent_box::accent_box(box *pp, box *qq) : pointer_box(pp), ab(qq)
41 {
42 }
43
44 accent_box::~accent_box()
45 {
46   delete ab;
47 }
48
49 #if 0
50 int accent_box::compute_metrics(int style)
51 {
52   int r = p->compute_metrics(style);
53   p->compute_skew();
54   ab->compute_metrics(style);
55   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
56   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
57   printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n",
58          uid, p->uid, x_height);
59   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+\\n["
60          SUP_RAISE_FORMAT "]\n",
61          uid, ab->uid, uid);
62   return r;
63 }
64
65 void accent_box::output()
66 {
67   if (output_format == troff) {
68     printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u+\\n["
69            SKEW_FORMAT "]u'",
70            p->uid, ab->uid, p->uid);
71     printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); 
72     ab->output();
73     printf("\\h'-\\n[" WIDTH_FORMAT "]u'", ab->uid);
74     printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
75     printf("\\h'-(\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u+\\n["
76            SKEW_FORMAT "]u)'",
77            p->uid, ab->uid, p->uid);
78     p->output();
79   }
80   else if (output_format == mathml) {
81     printf("<mover accent='true'>");
82     p->output();
83     ab->output();
84     printf("</mover>")
85   }
86 }
87 #endif
88
89 /* This version copes with the possibility of an accent's being wider
90 than its accentee.  LEFT_WIDTH_FORMAT gives the distance from the
91 left edge of the resulting box to the middle of the accentee's box.*/
92
93 int accent_box::compute_metrics(int style)
94 {
95   int r = p->compute_metrics(style);
96   p->compute_skew();
97   ab->compute_metrics(style);
98   printf(".nr " LEFT_WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2"
99          ">?(\\n[" WIDTH_FORMAT "]/2-\\n[" SKEW_FORMAT "])\n",
100          uid, p->uid, ab->uid, p->uid);
101   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2"
102          ">?(\\n[" WIDTH_FORMAT "]/2+\\n[" SKEW_FORMAT "])"
103          "+\\n[" LEFT_WIDTH_FORMAT "]\n",
104          uid, p->uid, ab->uid, p->uid, uid);
105   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
106   printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n",
107          uid, p->uid, x_height);
108   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+\\n["
109          SUP_RAISE_FORMAT "]\n",
110          uid, ab->uid, uid);
111   if (r)
112     printf(".nr " MARK_REG " +\\n[" LEFT_WIDTH_FORMAT "]"
113            "-(\\n[" WIDTH_FORMAT "]/2)'\n",
114            uid, p->uid);
115   return r;
116 }
117
118 void accent_box::output()
119 {
120   if (output_format == troff) {
121     printf("\\Z" DELIMITER_CHAR);
122     printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u+\\n[" SKEW_FORMAT "]u"
123            "-(\\n[" WIDTH_FORMAT "]u/2u)'",
124            uid, p->uid, ab->uid);
125     printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); 
126     ab->output();
127     printf(DELIMITER_CHAR);
128     printf("\\Z" DELIMITER_CHAR);
129     printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u-(\\n[" WIDTH_FORMAT "]u/2u)'",
130            uid, p->uid);
131     p->output();
132     printf(DELIMITER_CHAR);
133     printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid);
134   }
135   else if (output_format == mathml) {
136     printf("<mover accent='true'>");
137     p->output();
138     ab->output();
139     printf("</mover>");
140   }
141 }
142
143 void accent_box::check_tabs(int level)
144 {
145   ab->check_tabs(level + 1);
146   p->check_tabs(level + 1);
147 }
148
149 void accent_box::debug_print()
150 {
151   fprintf(stderr, "{ ");
152   p->debug_print();
153   fprintf(stderr, " } accent { ");
154   ab->debug_print();
155   fprintf(stderr, " }");
156 }
157
158 class overline_char_box : public simple_box {
159 public:
160   overline_char_box();
161   void output();
162   void debug_print();
163 };
164
165 overline_char_box::overline_char_box()
166 {
167 }
168
169 void overline_char_box::output()
170 {
171   if (output_format == troff) {
172     printf("\\v'-%dM/2u-%dM'", 7*default_rule_thickness, x_height);
173     printf((draw_flag ? "\\D'l%dM 0'" : "\\l'%dM\\&\\(ru'"),
174            accent_width);
175     printf("\\v'%dM/2u+%dM'", 7*default_rule_thickness, x_height);
176   }
177   else if (output_format == mathml)
178     printf("<mo>&macr;</mo>");
179 }
180
181 void overline_char_box::debug_print()
182 {
183   fprintf(stderr, "<overline char>");
184 }
185
186 class overline_box : public pointer_box {
187 public:
188   overline_box(box *);
189   int compute_metrics(int);
190   void output();
191   void debug_print();
192 };
193
194 box *make_overline_box(box *p)
195 {
196   if (p->is_char())
197     return new accent_box(p, new overline_char_box);
198   else
199     return new overline_box(p);
200 }
201
202 overline_box::overline_box(box *pp) : pointer_box(pp)
203 {
204 }
205
206 int overline_box::compute_metrics(int style)
207 {
208   int r = p->compute_metrics(cramped_style(style));
209   // 9
210   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+%dM\n",
211          uid, p->uid, default_rule_thickness*5);
212   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
213   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
214   return r;
215 }
216
217 void overline_box::output()
218 {
219   if (output_format == troff) {
220     // 9
221     printf("\\Z" DELIMITER_CHAR);
222     printf("\\v'-\\n[" HEIGHT_FORMAT "]u-(%dM/2u)'",
223            p->uid, 7*default_rule_thickness);
224     if (draw_flag)
225       printf("\\D'l\\n[" WIDTH_FORMAT "]u 0'", p->uid);
226     else
227       printf("\\l'\\n[" WIDTH_FORMAT "]u\\&\\(ru'", p->uid);
228     printf(DELIMITER_CHAR);
229     p->output();
230   }
231   else if (output_format == mathml) {
232     printf("<mover accent='false'>");
233     p->output();
234     printf("<mo>&macr;</mo></mover>");
235   }
236 }
237
238 void overline_box::debug_print()
239 {
240   fprintf(stderr, "{ ");
241   p->debug_print();
242   fprintf(stderr, " } bar");
243 }
244
245 class uaccent_box : public pointer_box {
246   box *ab;
247 public:
248   uaccent_box(box *, box *);
249   ~uaccent_box();
250   int compute_metrics(int);
251   void output();
252   void compute_subscript_kern();
253   void check_tabs(int);
254   void debug_print();
255 };
256
257 box *make_uaccent_box(box *p, box *q)
258 {
259   return new uaccent_box(p, q);
260 }
261
262 uaccent_box::uaccent_box(box *pp, box *qq)
263 : pointer_box(pp), ab(qq)
264 {
265 }
266
267 uaccent_box::~uaccent_box()
268 {
269   delete ab;
270 }
271
272 int uaccent_box::compute_metrics(int style)
273 {
274   int r = p->compute_metrics(style);
275   ab->compute_metrics(style);
276   printf(".nr " LEFT_WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2"
277          ">?(\\n[" WIDTH_FORMAT "]/2)\n",
278          uid, p->uid, ab->uid);
279   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2"
280          ">?(\\n[" WIDTH_FORMAT "]/2)"
281          "+\\n[" LEFT_WIDTH_FORMAT "]\n",
282          uid, p->uid, ab->uid, uid);
283   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
284   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]"
285          "+\\n[" DEPTH_FORMAT "]\n",
286          uid, p->uid, ab->uid);
287   if (r)
288     printf(".nr " MARK_REG " +\\n[" LEFT_WIDTH_FORMAT "]"
289            "-(\\n[" WIDTH_FORMAT "]/2)'\n",
290            uid, p->uid);
291   return r;
292 }
293
294 void uaccent_box::output()
295 {
296   if (output_format == troff) {
297     printf("\\Z" DELIMITER_CHAR);
298     printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u-(\\n[" WIDTH_FORMAT "]u/2u)'",
299            uid, ab->uid);
300     printf("\\v'\\n[" DEPTH_FORMAT "]u'", p->uid); 
301     ab->output();
302     printf(DELIMITER_CHAR);
303     printf("\\Z" DELIMITER_CHAR);
304     printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u-(\\n[" WIDTH_FORMAT "]u/2u)'",
305            uid, p->uid);
306     p->output();
307     printf(DELIMITER_CHAR);
308     printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid);
309   }
310   else if (output_format == mathml) {
311     printf("<munder accent='true'>");
312     p->output();
313     ab->output();
314     printf("</munder>");
315   }
316 }
317
318 void uaccent_box::check_tabs(int level)
319 {
320   ab->check_tabs(level + 1);
321   p->check_tabs(level + 1);
322 }
323
324 void uaccent_box::compute_subscript_kern()
325 {
326   box::compute_subscript_kern(); // want 0 subscript kern
327 }
328
329 void uaccent_box::debug_print()
330 {
331   fprintf(stderr, "{ ");
332   p->debug_print();
333   fprintf(stderr, " } uaccent { ");
334   ab->debug_print();
335   fprintf(stderr, " }");
336 }
337
338 class underline_char_box : public simple_box {
339 public:
340   underline_char_box();
341   void output();
342   void debug_print();
343 };
344
345 underline_char_box::underline_char_box()
346 {
347 }
348
349 void underline_char_box::output()
350 {
351   if (output_format == troff) {
352     printf("\\v'%dM/2u'", 7*default_rule_thickness);
353     printf((draw_flag ? "\\D'l%dM 0'" : "\\l'%dM\\&\\(ru'"),
354            accent_width);
355     printf("\\v'-%dM/2u'", 7*default_rule_thickness);
356   }
357   else if (output_format == mathml)
358     printf("<mo>&lowbar;</mo>");
359 }
360
361 void underline_char_box::debug_print()
362 {
363   fprintf(stderr, "<underline char>");
364 }
365
366
367 class underline_box : public pointer_box {
368 public:
369   underline_box(box *);
370   int compute_metrics(int);
371   void output();
372   void compute_subscript_kern();
373   void debug_print();
374 };
375
376 box *make_underline_box(box *p)
377 {
378   if (p->is_char())
379     return new uaccent_box(p, new underline_char_box);
380   else
381     return new underline_box(p);
382 }
383
384 underline_box::underline_box(box *pp) : pointer_box(pp)
385 {
386 }
387
388 int underline_box::compute_metrics(int style)
389 {
390   int r = p->compute_metrics(style);
391   // 10
392   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]+%dM\n",
393          uid, p->uid, default_rule_thickness*5);
394   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
395   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
396   return r;
397 }
398
399 void underline_box::output()
400 {
401   if (output_format == troff) {
402     // 10
403     printf("\\Z" DELIMITER_CHAR);
404     printf("\\v'\\n[" DEPTH_FORMAT "]u+(%dM/2u)'",
405            p->uid, 7*default_rule_thickness);
406     if (draw_flag)
407       printf("\\D'l\\n[" WIDTH_FORMAT "]u 0'", p->uid);
408     else
409       printf("\\l'\\n[" WIDTH_FORMAT "]u\\&\\(ru'", p->uid);
410     printf(DELIMITER_CHAR);
411     p->output();
412   }
413   else if (output_format == mathml) {
414     printf("<munder accent='true'>");
415     p->output();
416     printf("<mo>&macr;</mo></munder>");
417   }
418 }
419
420 // we want an underline box to have 0 subscript kern
421
422 void underline_box::compute_subscript_kern()
423 {
424   box::compute_subscript_kern();
425 }
426
427 void underline_box::debug_print()
428 {
429   fprintf(stderr, "{ ");
430   p->debug_print();
431   fprintf(stderr, " } under");
432 }
433
434 size_box::size_box(char *s, box *pp) : pointer_box(pp), size(s)
435 {
436 }
437
438 int size_box::compute_metrics(int style)
439 {
440   printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid);
441   printf(".ps %s\n", size);
442   printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid);
443   int r = p->compute_metrics(style);
444   printf(".ps \\n[" SIZE_FORMAT "]u\n", uid);
445   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
446   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
447   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
448   return r;
449 }
450
451 void size_box::output()
452 {
453   if (output_format == troff) {
454     printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid);
455     p->output();
456     printf("\\s[\\n[" SIZE_FORMAT "]u]", uid);
457   }
458   else if (output_format == mathml) {
459     printf("<mstyle mathsize='%s'>", size);
460     p->output();
461     printf("</mstyle>");
462   }
463 }
464
465 size_box::~size_box()
466 {
467   a_delete size;
468 }
469
470 void size_box::debug_print()
471 {
472   fprintf(stderr, "size %s { ", size);
473   p->debug_print();
474   fprintf(stderr, " }");
475 }
476
477
478 font_box::font_box(char *s, box *pp) : pointer_box(pp), f(s)
479 {
480 }
481
482 font_box::~font_box()
483 {
484   a_delete f;
485 }
486
487 int font_box::compute_metrics(int style)
488 {
489   const char *old_roman_font = current_roman_font;
490   current_roman_font = f;
491   printf(".nr " FONT_FORMAT " \\n[.f]\n", uid);
492   printf(".ft %s\n", f);
493   int r = p->compute_metrics(style);
494   current_roman_font = old_roman_font;
495   printf(".ft \\n[" FONT_FORMAT "]\n", uid);
496   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
497   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
498   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
499   return r;
500 }
501
502 void font_box::output()
503 {
504   if (output_format == troff) {
505     printf("\\f[%s]", f);
506     const char *old_roman_font = current_roman_font;
507     current_roman_font = f;
508     p->output();
509     current_roman_font = old_roman_font;
510     printf("\\f[\\n[" FONT_FORMAT "]]", uid);
511   }
512   else if (output_format == mathml) {
513     const char *mlfont = f;
514     // bold and italic are already in MathML; translate eqn roman here
515     switch (f[0]) {
516     case 'I':
517     case 'i':
518       mlfont = "italic";
519       break;
520     case 'B':
521     case 'b':
522       mlfont = "bold";
523       break;
524     case 'R':
525     case 'r':
526     default:
527       mlfont = "normal";
528       break;
529     }
530     printf("<mstyle mathvariant='%s'>", mlfont);
531     p->output();
532     printf("</mstyle>");
533   }
534 }
535
536 void font_box::debug_print()
537 {
538   fprintf(stderr, "font %s { ", f);
539   p->debug_print();
540   fprintf(stderr, " }");
541 }
542
543 fat_box::fat_box(box *pp) : pointer_box(pp)
544 {
545 }
546
547 int fat_box::compute_metrics(int style)
548 {
549   int r = p->compute_metrics(style);
550   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]+%dM\n",
551          uid, p->uid, fat_offset);
552   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
553   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
554   return r;
555 }
556
557 void fat_box::output()
558 {
559   if (output_format == troff) {
560     p->output();
561     printf("\\h'-\\n[" WIDTH_FORMAT "]u'", p->uid);
562     printf("\\h'%dM'", fat_offset);
563     p->output();
564   }
565   else if (output_format == mathml) {
566     printf("<mstyle mathvariant='double-struck'>");
567     p->output();
568     printf("</mstyle>");
569   }
570 }
571
572
573 void fat_box::debug_print()
574 {
575   fprintf(stderr, "fat { ");
576   p->debug_print();
577   fprintf(stderr, " }");
578 }
579
580
581 vmotion_box::vmotion_box(int i, box *pp) : pointer_box(pp), n(i)
582 {
583 }
584
585 int vmotion_box::compute_metrics(int style)
586 {
587   int r = p->compute_metrics(style);
588   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
589   if (n > 0) {
590     printf(".nr " HEIGHT_FORMAT " %dM+\\n[" HEIGHT_FORMAT "]\n",
591            uid, n, p->uid);
592     printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
593   }
594   else {
595     printf(".nr " DEPTH_FORMAT " %dM+\\n[" DEPTH_FORMAT "]>?0\n",
596            uid, -n, p->uid);
597     printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n",
598            uid, p->uid);
599   }
600   return r;
601 }
602
603 void vmotion_box::output()
604 {
605   if (output_format == troff) {
606     printf("\\v'%dM'", -n);
607     p->output();
608     printf("\\v'%dM'", n);
609   }
610   else if (output_format == mathml) {
611     printf("<merror>eqn vertical motion cannot be expressed "
612            "in MathML</merror>");
613     p->output();
614   }
615 }
616
617 void vmotion_box::debug_print()
618 {
619   if (n >= 0)
620     fprintf(stderr, "up %d { ", n);
621   else
622     fprintf(stderr, "down %d { ", -n);
623   p->debug_print();
624   fprintf(stderr, " }");
625 }
626
627 hmotion_box::hmotion_box(int i, box *pp) : pointer_box(pp), n(i)
628 {
629 }
630
631 int hmotion_box::compute_metrics(int style)
632 {
633   int r = p->compute_metrics(style);
634   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]+%dM\n",
635          uid, p->uid, n);
636   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
637   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
638   if (r)
639     printf(".nr " MARK_REG " +%dM\n", n);
640   return r;
641 }
642
643 void hmotion_box::output()
644 {
645   if (output_format == troff) {
646     printf("\\h'%dM'", n);
647     p->output();
648   }
649   else if (output_format == mathml) {
650     printf("<merror>eqn horizontal motion cannot be expessed "
651            "in MathML</merror>");
652     p->output();
653   }
654 }
655
656 void hmotion_box::debug_print()
657 {
658   if (n >= 0)
659     fprintf(stderr, "fwd %d { ", n);
660   else
661     fprintf(stderr, "back %d { ", -n);
662   p->debug_print();
663   fprintf(stderr, " }");
664 }
665
666 vcenter_box::vcenter_box(box *pp) : pointer_box(pp)
667 {
668 }
669
670 int vcenter_box::compute_metrics(int style)
671 {
672   int r = p->compute_metrics(style);
673   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
674   printf(".nr " SUP_RAISE_FORMAT " \\n[" DEPTH_FORMAT "]-\\n["
675          HEIGHT_FORMAT "]/2+%dM\n",
676          uid, p->uid, p->uid, axis_height);
677   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+\\n["
678          SUP_RAISE_FORMAT "]>?0\n", uid, p->uid, uid);
679   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]-\\n["
680          SUP_RAISE_FORMAT "]>?0\n", uid, p->uid, uid);
681
682   return r;
683 }
684
685 void vcenter_box::output()
686 {
687   if (output_format == troff)
688     printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
689   p->output();
690   if (output_format == troff)
691     printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
692 }
693
694 void vcenter_box::debug_print()
695 {
696   fprintf(stderr, "vcenter { ");
697   p->debug_print();
698   fprintf(stderr, " }");
699 }
700