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