2001-01-24 Kazu Hirata <kazu@hxi.com>
[deliverable/binutils-gdb.git] / bfd / doc / chew.c
1 /* chew
2 Copyright (C) 1990, 91, 92, 93, 94, 95, 96, 1998, 2000
3 Free Software Foundation, Inc.
4 Contributed by steve chamberlain @cygnus
5
6 This file is part of BFD, the Binary File Descriptor library.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21
22 /* Yet another way of extracting documentation from source.
23 No, I haven't finished it yet, but I hope you people like it better
24 than the old way
25
26 sac
27
28 Basically, this is a sort of string forth, maybe we should call it
29 struth?
30
31 You define new words thus:
32 : <newword> <oldwords> ;
33
34 */
35
36 /* Primitives provided by the program:
37
38 Two stacks are provided, a string stack and an integer stack.
39
40 Internal state variables:
41 internal_wanted - indicates whether `-i' was passed
42 internal_mode - user-settable
43
44 Commands:
45 push_text
46 ! - pop top of integer stack for address, pop next for value; store
47 @ - treat value on integer stack as the address of an integer; push
48 that integer on the integer stack after popping the "address"
49 hello - print "hello\n" to stdout
50 stdout - put stdout marker on TOS
51 stderr - put stderr marker on TOS
52 print - print TOS-1 on TOS (eg: "hello\n" stdout print)
53 skip_past_newline
54 catstr - fn icatstr
55 copy_past_newline - append input, up to and including newline into TOS
56 dup - fn other_dup
57 drop - discard TOS
58 idrop - ditto
59 remchar - delete last character from TOS
60 get_stuff_in_command
61 do_fancy_stuff - translate <<foo>> to @code{foo} in TOS
62 bulletize - if "o" lines found, prepend @itemize @bullet to TOS
63 and @item to each "o" line; append @end itemize
64 courierize - put @example around . and | lines, translate {* *} { }
65 exit - fn chew_exit
66 swap
67 outputdots - strip out lines without leading dots
68 paramstuff - convert full declaration into "PARAMS" form if not already
69 maybecatstr - do catstr if internal_mode == internal_wanted, discard
70 value in any case
71 translatecomments - turn {* and *} into comment delimiters
72 kill_bogus_lines - get rid of extra newlines
73 indent
74 internalmode - pop from integer stack, set `internalmode' to that value
75 print_stack_level - print current stack depth to stderr
76 strip_trailing_newlines - go ahead, guess...
77 [quoted string] - push string onto string stack
78 [word starting with digit] - push atol(str) onto integer stack
79
80 A command must be all upper-case, and alone on a line.
81
82 Foo. */
83
84 #include <ansidecl.h>
85 #include "sysdep.h"
86 #include <assert.h>
87 #include <stdio.h>
88 #include <ctype.h>
89
90 #define DEF_SIZE 5000
91 #define STACK 50
92
93 int internal_wanted;
94 int internal_mode;
95
96 int warning;
97
98 /* Here is a string type ... */
99
100 typedef struct buffer
101 {
102 char *ptr;
103 unsigned long write_idx;
104 unsigned long size;
105 } string_type;
106
107 #ifdef __STDC__
108 static void init_string_with_size (string_type *, unsigned int);
109 static void init_string (string_type *);
110 static int find (string_type *, char *);
111 static void write_buffer (string_type *, FILE *);
112 static void delete_string (string_type *);
113 static char *addr (string_type *, unsigned int);
114 static char at (string_type *, unsigned int);
115 static void catchar (string_type *, int);
116 static void overwrite_string (string_type *, string_type *);
117 static void catbuf (string_type *, char *, unsigned int);
118 static void cattext (string_type *, char *);
119 static void catstr (string_type *, string_type *);
120 #endif
121
122 static void
123 init_string_with_size (buffer, size)
124 string_type *buffer;
125 unsigned int size;
126 {
127 buffer->write_idx = 0;
128 buffer->size = size;
129 buffer->ptr = malloc (size);
130 }
131
132 static void
133 init_string (buffer)
134 string_type *buffer;
135 {
136 init_string_with_size (buffer, DEF_SIZE);
137 }
138
139 static int
140 find (str, what)
141 string_type *str;
142 char *what;
143 {
144 unsigned int i;
145 char *p;
146 p = what;
147 for (i = 0; i < str->write_idx && *p; i++)
148 {
149 if (*p == str->ptr[i])
150 p++;
151 else
152 p = what;
153 }
154 return (*p == 0);
155 }
156
157 static void
158 write_buffer (buffer, f)
159 string_type *buffer;
160 FILE *f;
161 {
162 fwrite (buffer->ptr, buffer->write_idx, 1, f);
163 }
164
165 static void
166 delete_string (buffer)
167 string_type *buffer;
168 {
169 free (buffer->ptr);
170 }
171
172 static char *
173 addr (buffer, idx)
174 string_type *buffer;
175 unsigned int idx;
176 {
177 return buffer->ptr + idx;
178 }
179
180 static char
181 at (buffer, pos)
182 string_type *buffer;
183 unsigned int pos;
184 {
185 if (pos >= buffer->write_idx)
186 return 0;
187 return buffer->ptr[pos];
188 }
189
190 static void
191 catchar (buffer, ch)
192 string_type *buffer;
193 int ch;
194 {
195 if (buffer->write_idx == buffer->size)
196 {
197 buffer->size *= 2;
198 buffer->ptr = realloc (buffer->ptr, buffer->size);
199 }
200
201 buffer->ptr[buffer->write_idx++] = ch;
202 }
203
204 static void
205 overwrite_string (dst, src)
206 string_type *dst;
207 string_type *src;
208 {
209 free (dst->ptr);
210 dst->size = src->size;
211 dst->write_idx = src->write_idx;
212 dst->ptr = src->ptr;
213 }
214
215 static void
216 catbuf (buffer, buf, len)
217 string_type *buffer;
218 char *buf;
219 unsigned int len;
220 {
221 if (buffer->write_idx + len >= buffer->size)
222 {
223 while (buffer->write_idx + len >= buffer->size)
224 buffer->size *= 2;
225 buffer->ptr = realloc (buffer->ptr, buffer->size);
226 }
227 memcpy (buffer->ptr + buffer->write_idx, buf, len);
228 buffer->write_idx += len;
229 }
230
231 static void
232 cattext (buffer, string)
233 string_type *buffer;
234 char *string;
235 {
236 catbuf (buffer, string, (unsigned int) strlen (string));
237 }
238
239 static void
240 catstr (dst, src)
241 string_type *dst;
242 string_type *src;
243 {
244 catbuf (dst, src->ptr, src->write_idx);
245 }
246
247 static unsigned int
248 skip_white_and_stars (src, idx)
249 string_type *src;
250 unsigned int idx;
251 {
252 char c;
253 while ((c = at (src, idx)),
254 isspace ((unsigned char) c)
255 || (c == '*'
256 /* Don't skip past end-of-comment or star as first
257 character on its line. */
258 && at (src, idx +1) != '/'
259 && at (src, idx -1) != '\n'))
260 idx++;
261 return idx;
262 }
263
264 /***********************************************************************/
265
266 string_type stack[STACK];
267 string_type *tos;
268
269 unsigned int idx = 0; /* Pos in input buffer */
270 string_type *ptr; /* and the buffer */
271 typedef void (*stinst_type)();
272 stinst_type *pc;
273 stinst_type sstack[STACK];
274 stinst_type *ssp = &sstack[0];
275 long istack[STACK];
276 long *isp = &istack[0];
277
278 typedef int *word_type;
279
280 struct dict_struct
281 {
282 char *word;
283 struct dict_struct *next;
284 stinst_type *code;
285 int code_length;
286 int code_end;
287 int var;
288 };
289
290 typedef struct dict_struct dict_type;
291
292 #define WORD(x) static void x()
293
294 static void
295 die (msg)
296 char *msg;
297 {
298 fprintf (stderr, "%s\n", msg);
299 exit (1);
300 }
301
302 static void
303 check_range ()
304 {
305 if (tos < stack)
306 die ("underflow in string stack");
307 if (tos >= stack + STACK)
308 die ("overflow in string stack");
309 }
310
311 static void
312 icheck_range ()
313 {
314 if (isp < istack)
315 die ("underflow in integer stack");
316 if (isp >= istack + STACK)
317 die ("overflow in integer stack");
318 }
319
320 #ifdef __STDC__
321 static void exec (dict_type *);
322 static void call (void);
323 static void remchar (void), strip_trailing_newlines (void), push_number (void);
324 static void push_text (void);
325 static void remove_noncomments (string_type *, string_type *);
326 static void print_stack_level (void);
327 static void paramstuff (void), translatecomments (void);
328 static void outputdots (void), courierize (void), bulletize (void);
329 static void do_fancy_stuff (void);
330 static int iscommand (string_type *, unsigned int);
331 static int copy_past_newline (string_type *, unsigned int, string_type *);
332 static void icopy_past_newline (void), kill_bogus_lines (void), indent (void);
333 static void get_stuff_in_command (void), swap (void), other_dup (void);
334 static void drop (void), idrop (void);
335 static void icatstr (void), skip_past_newline (void), internalmode (void);
336 static void maybecatstr (void);
337 static char *nextword (char *, char **);
338 dict_type *lookup_word (char *);
339 static void perform (void);
340 dict_type *newentry (char *);
341 unsigned int add_to_definition (dict_type *, stinst_type);
342 void add_intrinsic (char *, void (*)());
343 void add_var (char *);
344 void compile (char *);
345 static void bang (void);
346 static void atsign (void);
347 static void hello (void);
348 static void stdout_ (void);
349 static void stderr_ (void);
350 static void print (void);
351 static void read_in (string_type *, FILE *);
352 static void usage (void);
353 static void chew_exit (void);
354 #endif
355
356 static void
357 exec (word)
358 dict_type *word;
359 {
360 pc = word->code;
361 while (*pc)
362 (*pc) ();
363 }
364
365 WORD (call)
366 {
367 stinst_type *oldpc = pc;
368 dict_type *e;
369 e = (dict_type *) (pc[1]);
370 exec (e);
371 pc = oldpc + 2;
372 }
373
374 WORD (remchar)
375 {
376 if (tos->write_idx)
377 tos->write_idx--;
378 pc++;
379 }
380
381 static void
382 strip_trailing_newlines ()
383 {
384 while ((isspace ((unsigned char) at (tos, tos->write_idx - 1))
385 || at (tos, tos->write_idx - 1) == '\n')
386 && tos->write_idx > 0)
387 tos->write_idx--;
388 pc++;
389 }
390
391 WORD (push_number)
392 {
393 isp++;
394 icheck_range ();
395 pc++;
396 *isp = (long) (*pc);
397 pc++;
398 }
399
400 WORD (push_text)
401 {
402 tos++;
403 check_range ();
404 init_string (tos);
405 pc++;
406 cattext (tos, *((char **) pc));
407 pc++;
408 }
409
410 /* This function removes everything not inside comments starting on
411 the first char of the line from the string, also when copying
412 comments, removes blank space and leading *'s.
413 Blank lines are turned into one blank line. */
414
415 static void
416 remove_noncomments (src, dst)
417 string_type *src;
418 string_type *dst;
419 {
420 unsigned int idx = 0;
421
422 while (at (src, idx))
423 {
424 /* Now see if we have a comment at the start of the line. */
425 if (at (src, idx) == '\n'
426 && at (src, idx + 1) == '/'
427 && at (src, idx + 2) == '*')
428 {
429 idx += 3;
430
431 idx = skip_white_and_stars (src, idx);
432
433 /* Remove leading dot */
434 if (at (src, idx) == '.')
435 idx++;
436
437 /* Copy to the end of the line, or till the end of the
438 comment. */
439 while (at (src, idx))
440 {
441 if (at (src, idx) == '\n')
442 {
443 /* end of line, echo and scrape of leading blanks */
444 if (at (src, idx + 1) == '\n')
445 catchar (dst, '\n');
446 catchar (dst, '\n');
447 idx++;
448 idx = skip_white_and_stars (src, idx);
449 }
450 else if (at (src, idx) == '*' && at (src, idx + 1) == '/')
451 {
452 idx += 2;
453 cattext (dst, "\nENDDD\n");
454 break;
455 }
456 else
457 {
458 catchar (dst, at (src, idx));
459 idx++;
460 }
461 }
462 }
463 else
464 idx++;
465 }
466 }
467
468 static void
469 print_stack_level ()
470 {
471 fprintf (stderr, "current string stack depth = %d, ", tos - stack);
472 fprintf (stderr, "current integer stack depth = %d\n", isp - istack);
473 pc++;
474 }
475
476 /* turn:
477 foobar name(stuff);
478 into:
479 foobar
480 name PARAMS ((stuff));
481 and a blank line.
482 */
483
484 static void
485 paramstuff (void)
486 {
487 unsigned int openp;
488 unsigned int fname;
489 unsigned int idx;
490 string_type out;
491 init_string (&out);
492
493 /* Make sure that it's not already param'd or proto'd. */
494 if (find (tos, "PARAMS") || find (tos, "PROTO") || !find (tos, "("))
495 {
496 catstr (&out, tos);
497 }
498 else
499 {
500 /* Find the open paren. */
501 for (openp = 0; at (tos, openp) != '(' && at (tos, openp); openp++)
502 ;
503
504 fname = openp;
505 /* Step back to the fname. */
506 fname--;
507 while (fname && isspace ((unsigned char) at (tos, fname)))
508 fname--;
509 while (fname
510 && !isspace ((unsigned char) at (tos,fname))
511 && at (tos,fname) != '*')
512 fname--;
513
514 fname++;
515
516 for (idx = 0; idx < fname; idx++) /* Output type */
517 {
518 /* Omit a trailing whitespace. */
519 if (idx + 1 == fname && isspace ((unsigned char) at (tos, idx)))
520 break;
521
522 catchar (&out, at (tos, idx));
523 }
524
525 cattext (&out, "\n"); /* Insert a newline between type and fnname */
526
527 for (idx = fname; idx < openp; idx++) /* Output fnname */
528 {
529 catchar (&out, at (tos, idx));
530 }
531
532 cattext (&out, " PARAMS (");
533
534 while (at (tos, idx) && at (tos, idx) != ';')
535 {
536 catchar (&out, at (tos, idx));
537 idx++;
538 }
539 cattext (&out, ");\n\n");
540 }
541 overwrite_string (tos, &out);
542 pc++;
543
544 }
545
546 /* turn {*
547 and *} into comments */
548
549 WORD (translatecomments)
550 {
551 unsigned int idx = 0;
552 string_type out;
553 init_string (&out);
554
555 while (at (tos, idx))
556 {
557 if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
558 {
559 cattext (&out, "/*");
560 idx += 2;
561 }
562 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
563 {
564 cattext (&out, "*/");
565 idx += 2;
566 }
567 else
568 {
569 catchar (&out, at (tos, idx));
570 idx++;
571 }
572 }
573
574 overwrite_string (tos, &out);
575
576 pc++;
577 }
578
579 #if 0
580
581 /* This is not currently used. */
582
583 /* turn everything not starting with a . into a comment */
584
585 WORD (manglecomments)
586 {
587 unsigned int idx = 0;
588 string_type out;
589 init_string (&out);
590
591 while (at (tos, idx))
592 {
593 if (at (tos, idx) == '\n' && at (tos, idx + 1) == '*')
594 {
595 cattext (&out, " /*");
596 idx += 2;
597 }
598 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
599 {
600 cattext (&out, "*/");
601 idx += 2;
602 }
603 else
604 {
605 catchar (&out, at (tos, idx));
606 idx++;
607 }
608 }
609
610 overwrite_string (tos, &out);
611
612 pc++;
613 }
614
615 #endif
616
617 /* Mod tos so that only lines with leading dots remain */
618 static void
619 outputdots (void)
620 {
621 unsigned int idx = 0;
622 string_type out;
623 init_string (&out);
624
625 while (at (tos, idx))
626 {
627 if (at (tos, idx) == '\n' && at (tos, idx + 1) == '.')
628 {
629 char c;
630 idx += 2;
631
632 while ((c = at (tos, idx)) && c != '\n')
633 {
634 if (c == '{' && at (tos, idx + 1) == '*')
635 {
636 cattext (&out, "/*");
637 idx += 2;
638 }
639 else if (c == '*' && at (tos, idx + 1) == '}')
640 {
641 cattext (&out, "*/");
642 idx += 2;
643 }
644 else
645 {
646 catchar (&out, c);
647 idx++;
648 }
649 }
650 catchar (&out, '\n');
651 }
652 else
653 {
654 idx++;
655 }
656 }
657
658 overwrite_string (tos, &out);
659 pc++;
660 }
661
662 /* Find lines starting with . and | and put example around them on tos */
663 WORD (courierize)
664 {
665 string_type out;
666 unsigned int idx = 0;
667 int command = 0;
668
669 init_string (&out);
670
671 while (at (tos, idx))
672 {
673 if (at (tos, idx) == '\n'
674 && (at (tos, idx +1 ) == '.'
675 || at (tos, idx + 1) == '|'))
676 {
677 cattext (&out, "\n@example\n");
678 do
679 {
680 idx += 2;
681
682 while (at (tos, idx) && at (tos, idx) != '\n')
683 {
684 if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
685 {
686 cattext (&out, "/*");
687 idx += 2;
688 }
689 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
690 {
691 cattext (&out, "*/");
692 idx += 2;
693 }
694 else if (at (tos, idx) == '{' && !command)
695 {
696 cattext (&out, "@{");
697 idx++;
698 }
699 else if (at (tos, idx) == '}' && !command)
700 {
701 cattext (&out, "@}");
702 idx++;
703 }
704 else
705 {
706 if (at (tos, idx) == '@')
707 command = 1;
708 else if (isspace ((unsigned char) at (tos, idx))
709 || at (tos, idx) == '}')
710 command = 0;
711 catchar (&out, at (tos, idx));
712 idx++;
713 }
714
715 }
716 catchar (&out, '\n');
717 }
718 while (at (tos, idx) == '\n'
719 && ((at (tos, idx + 1) == '.')
720 || (at (tos, idx + 1) == '|')))
721 ;
722 cattext (&out, "@end example");
723 }
724 else
725 {
726 catchar (&out, at (tos, idx));
727 idx++;
728 }
729 }
730
731 overwrite_string (tos, &out);
732 pc++;
733 }
734
735 /* Finds any lines starting with "o ", if there are any, then turns
736 on @itemize @bullet, and @items each of them. Then ends with @end
737 itemize, inplace at TOS*/
738
739 WORD (bulletize)
740 {
741 unsigned int idx = 0;
742 int on = 0;
743 string_type out;
744 init_string (&out);
745
746 while (at (tos, idx))
747 {
748 if (at (tos, idx) == '@'
749 && at (tos, idx + 1) == '*')
750 {
751 cattext (&out, "*");
752 idx += 2;
753 }
754 else if (at (tos, idx) == '\n'
755 && at (tos, idx + 1) == 'o'
756 && isspace ((unsigned char) at (tos, idx + 2)))
757 {
758 if (!on)
759 {
760 cattext (&out, "\n@itemize @bullet\n");
761 on = 1;
762
763 }
764 cattext (&out, "\n@item\n");
765 idx += 3;
766 }
767 else
768 {
769 catchar (&out, at (tos, idx));
770 if (on && at (tos, idx) == '\n'
771 && at (tos, idx + 1) == '\n'
772 && at (tos, idx + 2) != 'o')
773 {
774 cattext (&out, "@end itemize");
775 on = 0;
776 }
777 idx++;
778
779 }
780 }
781 if (on)
782 {
783 cattext (&out, "@end itemize\n");
784 }
785
786 delete_string (tos);
787 *tos = out;
788 pc++;
789 }
790
791 /* Turn <<foo>> into @code{foo} in place at TOS*/
792
793 WORD (do_fancy_stuff)
794 {
795 unsigned int idx = 0;
796 string_type out;
797 init_string (&out);
798 while (at (tos, idx))
799 {
800 if (at (tos, idx) == '<'
801 && at (tos, idx + 1) == '<'
802 && !isspace ((unsigned char) at (tos, idx + 2)))
803 {
804 /* This qualifies as a << startup. */
805 idx += 2;
806 cattext (&out, "@code{");
807 while (at (tos, idx)
808 && at (tos, idx) != '>' )
809 {
810 catchar (&out, at (tos, idx));
811 idx++;
812
813 }
814 cattext (&out, "}");
815 idx += 2;
816 }
817 else
818 {
819 catchar (&out, at (tos, idx));
820 idx++;
821 }
822 }
823 delete_string (tos);
824 *tos = out;
825 pc++;
826
827 }
828
829 /* A command is all upper case,and alone on a line. */
830
831 static int
832 iscommand (ptr, idx)
833 string_type *ptr;
834 unsigned int idx;
835 {
836 unsigned int len = 0;
837 while (at (ptr, idx))
838 {
839 if (isupper ((unsigned char) at (ptr, idx))
840 || at (ptr, idx) == ' ' || at (ptr, idx) == '_')
841 {
842 len++;
843 idx++;
844 }
845 else if (at (ptr, idx) == '\n')
846 {
847 if (len > 3)
848 return 1;
849 return 0;
850 }
851 else
852 return 0;
853 }
854 return 0;
855 }
856
857 static int
858 copy_past_newline (ptr, idx, dst)
859 string_type *ptr;
860 unsigned int idx;
861 string_type *dst;
862 {
863 int column = 0;
864
865 while (at (ptr, idx) && at (ptr, idx) != '\n')
866 {
867 if (at (ptr, idx) == '\t')
868 {
869 /* Expand tabs. Neither makeinfo nor TeX can cope well with
870 them. */
871 do
872 catchar (dst, ' ');
873 while (++column & 7);
874 }
875 else
876 {
877 catchar (dst, at (ptr, idx));
878 column++;
879 }
880 idx++;
881
882 }
883 catchar (dst, at (ptr, idx));
884 idx++;
885 return idx;
886
887 }
888
889 WORD (icopy_past_newline)
890 {
891 tos++;
892 check_range ();
893 init_string (tos);
894 idx = copy_past_newline (ptr, idx, tos);
895 pc++;
896 }
897
898 /* indent
899 Take the string at the top of the stack, do some prettying. */
900
901 WORD (kill_bogus_lines)
902 {
903 int sl;
904
905 int idx = 0;
906 int c;
907 int dot = 0;
908
909 string_type out;
910 init_string (&out);
911 /* Drop leading nl. */
912 while (at (tos, idx) == '\n')
913 {
914 idx++;
915 }
916 c = idx;
917
918 /* If the first char is a '.' prepend a newline so that it is
919 recognized properly later. */
920 if (at (tos, idx) == '.')
921 catchar (&out, '\n');
922
923 /* Find the last char. */
924 while (at (tos, idx))
925 {
926 idx++;
927 }
928
929 /* Find the last non white before the nl. */
930 idx--;
931
932 while (idx && isspace ((unsigned char) at (tos, idx)))
933 idx--;
934 idx++;
935
936 /* Copy buffer upto last char, but blank lines before and after
937 dots don't count. */
938 sl = 1;
939
940 while (c < idx)
941 {
942 if (at (tos, c) == '\n'
943 && at (tos, c + 1) == '\n'
944 && at (tos, c + 2) == '.')
945 {
946 /* Ignore two newlines before a dot. */
947 c++;
948 }
949 else if (at (tos, c) == '.' && sl)
950 {
951 /* remember that this line started with a dot. */
952 dot = 2;
953 }
954 else if (at (tos, c) == '\n'
955 && at (tos, c + 1) == '\n'
956 && dot)
957 {
958 c++;
959 /* Ignore two newlines when last line was dot. */
960 }
961
962 catchar (&out, at (tos, c));
963 if (at (tos, c) == '\n')
964 {
965 sl = 1;
966
967 if (dot == 2)
968 dot = 1;
969 else
970 dot = 0;
971 }
972 else
973 sl = 0;
974
975 c++;
976
977 }
978
979 /* Append nl. */
980 catchar (&out, '\n');
981 pc++;
982 delete_string (tos);
983 *tos = out;
984
985 }
986
987 WORD (indent)
988 {
989 string_type out;
990 int tab = 0;
991 int idx = 0;
992 int ol = 0;
993 init_string (&out);
994 while (at (tos, idx))
995 {
996 switch (at (tos, idx))
997 {
998 case '\n':
999 cattext (&out, "\n");
1000 idx++;
1001 if (tab && at (tos, idx))
1002 {
1003 cattext (&out, " ");
1004 }
1005 ol = 0;
1006 break;
1007 case '(':
1008 tab++;
1009 if (ol == 0)
1010 cattext (&out, " ");
1011 idx++;
1012 cattext (&out, "(");
1013 ol = 1;
1014 break;
1015 case ')':
1016 tab--;
1017 cattext (&out, ")");
1018 idx++;
1019 ol = 1;
1020
1021 break;
1022 default:
1023 catchar (&out, at (tos, idx));
1024 ol = 1;
1025
1026 idx++;
1027 break;
1028 }
1029 }
1030
1031 pc++;
1032 delete_string (tos);
1033 *tos = out;
1034
1035 }
1036
1037 WORD (get_stuff_in_command)
1038 {
1039 tos++;
1040 check_range ();
1041 init_string (tos);
1042
1043 while (at (ptr, idx))
1044 {
1045 if (iscommand (ptr, idx))
1046 break;
1047 idx = copy_past_newline (ptr, idx, tos);
1048 }
1049 pc++;
1050 }
1051
1052 WORD (swap)
1053 {
1054 string_type t;
1055
1056 t = tos[0];
1057 tos[0] = tos[-1];
1058 tos[-1] = t;
1059 pc++;
1060 }
1061
1062 WORD (other_dup)
1063 {
1064 tos++;
1065 check_range ();
1066 init_string (tos);
1067 catstr (tos, tos - 1);
1068 pc++;
1069 }
1070
1071 WORD (drop)
1072 {
1073 tos--;
1074 check_range ();
1075 pc++;
1076 }
1077
1078 WORD (idrop)
1079 {
1080 isp--;
1081 icheck_range ();
1082 pc++;
1083 }
1084
1085 WORD (icatstr)
1086 {
1087 tos--;
1088 check_range ();
1089 catstr (tos, tos + 1);
1090 delete_string (tos + 1);
1091 pc++;
1092 }
1093
1094 WORD (skip_past_newline)
1095 {
1096 while (at (ptr, idx)
1097 && at (ptr, idx) != '\n')
1098 idx++;
1099 idx++;
1100 pc++;
1101 }
1102
1103 WORD (internalmode)
1104 {
1105 internal_mode = *(isp);
1106 isp--;
1107 icheck_range ();
1108 pc++;
1109 }
1110
1111 WORD (maybecatstr)
1112 {
1113 if (internal_wanted == internal_mode)
1114 {
1115 catstr (tos - 1, tos);
1116 }
1117 delete_string (tos);
1118 tos--;
1119 check_range ();
1120 pc++;
1121 }
1122
1123 char *
1124 nextword (string, word)
1125 char *string;
1126 char **word;
1127 {
1128 char *word_start;
1129 int idx;
1130 char *dst;
1131 char *src;
1132
1133 int length = 0;
1134
1135 while (isspace ((unsigned char) *string) || *string == '-')
1136 {
1137 if (*string == '-')
1138 {
1139 while (*string && *string != '\n')
1140 string++;
1141
1142 }
1143 else
1144 {
1145 string++;
1146 }
1147 }
1148 if (!*string)
1149 return 0;
1150
1151 word_start = string;
1152 if (*string == '"')
1153 {
1154 do
1155 {
1156 string++;
1157 length++;
1158 if (*string == '\\')
1159 {
1160 string += 2;
1161 length += 2;
1162 }
1163 }
1164 while (*string != '"');
1165 }
1166 else
1167 {
1168 while (!isspace ((unsigned char) *string))
1169 {
1170 string++;
1171 length++;
1172
1173 }
1174 }
1175
1176 *word = malloc (length + 1);
1177
1178 dst = *word;
1179 src = word_start;
1180
1181 for (idx = 0; idx < length; idx++)
1182 {
1183 if (src[idx] == '\\')
1184 switch (src[idx + 1])
1185 {
1186 case 'n':
1187 *dst++ = '\n';
1188 idx++;
1189 break;
1190 case '"':
1191 case '\\':
1192 *dst++ = src[idx + 1];
1193 idx++;
1194 break;
1195 default:
1196 *dst++ = '\\';
1197 break;
1198 }
1199 else
1200 *dst++ = src[idx];
1201 }
1202 *dst++ = 0;
1203
1204 if (*string)
1205 return string + 1;
1206 else
1207 return 0;
1208 }
1209
1210 dict_type *root;
1211
1212 dict_type *
1213 lookup_word (word)
1214 char *word;
1215 {
1216 dict_type *ptr = root;
1217 while (ptr)
1218 {
1219 if (strcmp (ptr->word, word) == 0)
1220 return ptr;
1221 ptr = ptr->next;
1222 }
1223 if (warning)
1224 fprintf (stderr, "Can't find %s\n", word);
1225 return 0;
1226 }
1227
1228 static void
1229 perform (void)
1230 {
1231 tos = stack;
1232
1233 while (at (ptr, idx))
1234 {
1235 /* It's worth looking through the command list. */
1236 if (iscommand (ptr, idx))
1237 {
1238 char *next;
1239 dict_type *word;
1240
1241 (void) nextword (addr (ptr, idx), &next);
1242
1243 word = lookup_word (next);
1244
1245 if (word)
1246 {
1247 exec (word);
1248 }
1249 else
1250 {
1251 if (warning)
1252 fprintf (stderr, "warning, %s is not recognised\n", next);
1253 skip_past_newline ();
1254 }
1255
1256 }
1257 else
1258 skip_past_newline ();
1259 }
1260 }
1261
1262 dict_type *
1263 newentry (word)
1264 char *word;
1265 {
1266 dict_type *new = (dict_type *) malloc (sizeof (dict_type));
1267 new->word = word;
1268 new->next = root;
1269 root = new;
1270 new->code = (stinst_type *) malloc (sizeof (stinst_type));
1271 new->code_length = 1;
1272 new->code_end = 0;
1273 return new;
1274 }
1275
1276 unsigned int
1277 add_to_definition (entry, word)
1278 dict_type *entry;
1279 stinst_type word;
1280 {
1281 if (entry->code_end == entry->code_length)
1282 {
1283 entry->code_length += 2;
1284 entry->code =
1285 (stinst_type *) realloc ((char *) (entry->code),
1286 entry->code_length * sizeof (word_type));
1287 }
1288 entry->code[entry->code_end] = word;
1289
1290 return entry->code_end++;
1291 }
1292
1293 void
1294 add_intrinsic (name, func)
1295 char *name;
1296 void (*func) ();
1297 {
1298 dict_type *new = newentry (name);
1299 add_to_definition (new, func);
1300 add_to_definition (new, 0);
1301 }
1302
1303 void
1304 add_var (name)
1305 char *name;
1306 {
1307 dict_type *new = newentry (name);
1308 add_to_definition (new, push_number);
1309 add_to_definition (new, (stinst_type) (&(new->var)));
1310 add_to_definition (new, 0);
1311 }
1312
1313 void
1314 compile (string)
1315 char *string;
1316 {
1317 /* Add words to the dictionary. */
1318 char *word;
1319 string = nextword (string, &word);
1320 while (string && *string && word[0])
1321 {
1322 if (strcmp (word, "var") == 0)
1323 {
1324 string = nextword (string, &word);
1325
1326 add_var (word);
1327 string = nextword (string, &word);
1328 }
1329 else if (word[0] == ':')
1330 {
1331 dict_type *ptr;
1332 /* Compile a word and add to dictionary. */
1333 string = nextword (string, &word);
1334
1335 ptr = newentry (word);
1336 string = nextword (string, &word);
1337 while (word[0] != ';')
1338 {
1339 switch (word[0])
1340 {
1341 case '"':
1342 /* got a string, embed magic push string
1343 function */
1344 add_to_definition (ptr, push_text);
1345 add_to_definition (ptr, (stinst_type) (word + 1));
1346 break;
1347 case '0':
1348 case '1':
1349 case '2':
1350 case '3':
1351 case '4':
1352 case '5':
1353 case '6':
1354 case '7':
1355 case '8':
1356 case '9':
1357 /* Got a number, embedd the magic push number
1358 function */
1359 add_to_definition (ptr, push_number);
1360 add_to_definition (ptr, (stinst_type) atol (word));
1361 break;
1362 default:
1363 add_to_definition (ptr, call);
1364 add_to_definition (ptr, (stinst_type) lookup_word (word));
1365 }
1366
1367 string = nextword (string, &word);
1368 }
1369 add_to_definition (ptr, 0);
1370 string = nextword (string, &word);
1371 }
1372 else
1373 {
1374 fprintf (stderr, "syntax error at %s\n", string - 1);
1375 }
1376 }
1377 }
1378
1379 static void
1380 bang (void)
1381 {
1382 *(long *) ((isp[0])) = isp[-1];
1383 isp -= 2;
1384 icheck_range ();
1385 pc++;
1386 }
1387
1388 WORD (atsign)
1389 {
1390 isp[0] = *(long *) (isp[0]);
1391 pc++;
1392 }
1393
1394 WORD (hello)
1395 {
1396 printf ("hello\n");
1397 pc++;
1398 }
1399
1400 WORD (stdout_)
1401 {
1402 isp++;
1403 icheck_range ();
1404 *isp = 1;
1405 pc++;
1406 }
1407
1408 WORD (stderr_)
1409 {
1410 isp++;
1411 icheck_range ();
1412 *isp = 2;
1413 pc++;
1414 }
1415
1416 WORD (print)
1417 {
1418 if (*isp == 1)
1419 write_buffer (tos, stdout);
1420 else if (*isp == 2)
1421 write_buffer (tos, stderr);
1422 else
1423 fprintf (stderr, "print: illegal print destination `%ld'\n", *isp);
1424 isp--;
1425 tos--;
1426 icheck_range ();
1427 check_range ();
1428 pc++;
1429 }
1430
1431 static void
1432 read_in (str, file)
1433 string_type *str;
1434 FILE *file;
1435 {
1436 char buff[10000];
1437 unsigned int r;
1438 do
1439 {
1440 r = fread (buff, 1, sizeof (buff), file);
1441 catbuf (str, buff, r);
1442 }
1443 while (r);
1444 buff[0] = 0;
1445
1446 catbuf (str, buff, 1);
1447 }
1448
1449 static void
1450 usage (void)
1451 {
1452 fprintf (stderr, "usage: -[d|i|g] <file >file\n");
1453 exit (33);
1454 }
1455
1456 /* There is no reliable way to declare exit. Sometimes it returns
1457 int, and sometimes it returns void. Sometimes it changes between
1458 OS releases. Trying to get it declared correctly in the hosts file
1459 is a pointless waste of time. */
1460
1461 static void
1462 chew_exit ()
1463 {
1464 exit (0);
1465 }
1466
1467 int
1468 main (ac, av)
1469 int ac;
1470 char *av[];
1471 {
1472 unsigned int i;
1473 string_type buffer;
1474 string_type pptr;
1475
1476 init_string (&buffer);
1477 init_string (&pptr);
1478 init_string (stack + 0);
1479 tos = stack + 1;
1480 ptr = &pptr;
1481
1482 add_intrinsic ("push_text", push_text);
1483 add_intrinsic ("!", bang);
1484 add_intrinsic ("@", atsign);
1485 add_intrinsic ("hello", hello);
1486 add_intrinsic ("stdout", stdout_);
1487 add_intrinsic ("stderr", stderr_);
1488 add_intrinsic ("print", print);
1489 add_intrinsic ("skip_past_newline", skip_past_newline);
1490 add_intrinsic ("catstr", icatstr);
1491 add_intrinsic ("copy_past_newline", icopy_past_newline);
1492 add_intrinsic ("dup", other_dup);
1493 add_intrinsic ("drop", drop);
1494 add_intrinsic ("idrop", idrop);
1495 add_intrinsic ("remchar", remchar);
1496 add_intrinsic ("get_stuff_in_command", get_stuff_in_command);
1497 add_intrinsic ("do_fancy_stuff", do_fancy_stuff);
1498 add_intrinsic ("bulletize", bulletize);
1499 add_intrinsic ("courierize", courierize);
1500 /* If the following line gives an error, exit() is not declared in the
1501 ../hosts/foo.h file for this host. Fix it there, not here! */
1502 /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1503 add_intrinsic ("exit", chew_exit);
1504 add_intrinsic ("swap", swap);
1505 add_intrinsic ("outputdots", outputdots);
1506 add_intrinsic ("paramstuff", paramstuff);
1507 add_intrinsic ("maybecatstr", maybecatstr);
1508 add_intrinsic ("translatecomments", translatecomments);
1509 add_intrinsic ("kill_bogus_lines", kill_bogus_lines);
1510 add_intrinsic ("indent", indent);
1511 add_intrinsic ("internalmode", internalmode);
1512 add_intrinsic ("print_stack_level", print_stack_level);
1513 add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines);
1514
1515 /* Put a nl at the start. */
1516 catchar (&buffer, '\n');
1517
1518 read_in (&buffer, stdin);
1519 remove_noncomments (&buffer, ptr);
1520 for (i = 1; i < (unsigned int) ac; i++)
1521 {
1522 if (av[i][0] == '-')
1523 {
1524 if (av[i][1] == 'f')
1525 {
1526 string_type b;
1527 FILE *f;
1528 init_string (&b);
1529
1530 f = fopen (av[i + 1], "r");
1531 if (!f)
1532 {
1533 fprintf (stderr, "Can't open the input file %s\n",
1534 av[i + 1]);
1535 return 33;
1536 }
1537
1538 read_in (&b, f);
1539 compile (b.ptr);
1540 perform ();
1541 }
1542 else if (av[i][1] == 'i')
1543 {
1544 internal_wanted = 1;
1545 }
1546 else if (av[i][1] == 'w')
1547 {
1548 warning = 1;
1549 }
1550 else
1551 usage ();
1552 }
1553 }
1554 write_buffer (stack + 0, stdout);
1555 if (tos != stack)
1556 {
1557 fprintf (stderr, "finishing with current stack level %d\n",
1558 tos - stack);
1559 return 1;
1560 }
1561 return 0;
1562 }
This page took 0.072254 seconds and 5 git commands to generate.