2001-01-03 Philip Blundell <pb@futuretv.com>
[binutils.git] / bfd / doc / chew.c
blob52de92e01e00e6306226d9e59b78f331fcef287d
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
6 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
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
26 sac
28 Basically, this is a sort of string forth, maybe we should call it
29 struth?
31 You define new words thus:
32 : <newword> <oldwords> ;
36 /* Primitives provided by the program:
38 Two stacks are provided, a string stack and an integer stack.
40 Internal state variables:
41 internal_wanted - indicates whether `-i' was passed
42 internal_mode - user-settable
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
80 A command must be all upper-case, and alone on a line.
82 Foo. */
84 #include <ansidecl.h>
85 #include "sysdep.h"
86 #include <assert.h>
87 #include <stdio.h>
88 #include <ctype.h>
90 #define DEF_SIZE 5000
91 #define STACK 50
93 int internal_wanted;
94 int internal_mode;
96 int warning;
98 /* Here is a string type ... */
100 typedef struct buffer
102 char *ptr;
103 unsigned long write_idx;
104 unsigned long size;
105 } string_type;
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
122 static void
123 init_string_with_size (buffer, size)
124 string_type *buffer;
125 unsigned int size;
127 buffer->write_idx = 0;
128 buffer->size = size;
129 buffer->ptr = malloc (size);
132 static void
133 init_string (buffer)
134 string_type *buffer;
136 init_string_with_size (buffer, DEF_SIZE);
139 static int
140 find (str, what)
141 string_type *str;
142 char *what;
144 unsigned int i;
145 char *p;
146 p = what;
147 for (i = 0; i < str->write_idx && *p; i++)
149 if (*p == str->ptr[i])
150 p++;
151 else
152 p = what;
154 return (*p == 0);
157 static void
158 write_buffer (buffer, f)
159 string_type *buffer;
160 FILE *f;
162 fwrite (buffer->ptr, buffer->write_idx, 1, f);
165 static void
166 delete_string (buffer)
167 string_type *buffer;
169 free (buffer->ptr);
172 static char *
173 addr (buffer, idx)
174 string_type *buffer;
175 unsigned int idx;
177 return buffer->ptr + idx;
180 static char
181 at (buffer, pos)
182 string_type *buffer;
183 unsigned int pos;
185 if (pos >= buffer->write_idx)
186 return 0;
187 return buffer->ptr[pos];
190 static void
191 catchar (buffer, ch)
192 string_type *buffer;
193 int ch;
195 if (buffer->write_idx == buffer->size)
197 buffer->size *= 2;
198 buffer->ptr = realloc (buffer->ptr, buffer->size);
201 buffer->ptr[buffer->write_idx++] = ch;
204 static void
205 overwrite_string (dst, src)
206 string_type *dst;
207 string_type *src;
209 free (dst->ptr);
210 dst->size = src->size;
211 dst->write_idx = src->write_idx;
212 dst->ptr = src->ptr;
215 static void
216 catbuf (buffer, buf, len)
217 string_type *buffer;
218 char *buf;
219 unsigned int len;
221 if (buffer->write_idx + len >= buffer->size)
223 while (buffer->write_idx + len >= buffer->size)
224 buffer->size *= 2;
225 buffer->ptr = realloc (buffer->ptr, buffer->size);
227 memcpy (buffer->ptr + buffer->write_idx, buf, len);
228 buffer->write_idx += len;
231 static void
232 cattext (buffer, string)
233 string_type *buffer;
234 char *string;
236 catbuf (buffer, string, (unsigned int) strlen (string));
239 static void
240 catstr (dst, src)
241 string_type *dst;
242 string_type *src;
244 catbuf (dst, src->ptr, src->write_idx);
247 static unsigned int
248 skip_white_and_stars (src, idx)
249 string_type *src;
250 unsigned int idx;
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;
264 /***********************************************************************/
266 string_type stack[STACK];
267 string_type *tos;
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];
278 typedef int *word_type;
280 struct dict_struct
282 char *word;
283 struct dict_struct *next;
284 stinst_type *code;
285 int code_length;
286 int code_end;
287 int var;
290 typedef struct dict_struct dict_type;
292 #define WORD(x) static void x()
294 static void
295 die (msg)
296 char *msg;
298 fprintf (stderr, "%s\n", msg);
299 exit (1);
302 static void
303 check_range ()
305 if (tos < stack)
306 die ("underflow in string stack");
307 if (tos >= stack + STACK)
308 die ("overflow in string stack");
311 static void
312 icheck_range ()
314 if (isp < istack)
315 die ("underflow in integer stack");
316 if (isp >= istack + STACK)
317 die ("overflow in integer stack");
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
356 static void
357 exec (word)
358 dict_type *word;
360 pc = word->code;
361 while (*pc)
362 (*pc) ();
365 WORD (call)
367 stinst_type *oldpc = pc;
368 dict_type *e;
369 e = (dict_type *) (pc[1]);
370 exec (e);
371 pc = oldpc + 2;
374 WORD (remchar)
376 if (tos->write_idx)
377 tos->write_idx--;
378 pc++;
381 static void
382 strip_trailing_newlines ()
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++;
391 WORD (push_number)
393 isp++;
394 icheck_range ();
395 pc++;
396 *isp = (long) (*pc);
397 pc++;
400 WORD (push_text)
402 tos++;
403 check_range ();
404 init_string (tos);
405 pc++;
406 cattext (tos, *((char **) pc));
407 pc++;
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. */
415 static void
416 remove_noncomments (src, dst)
417 string_type *src;
418 string_type *dst;
420 unsigned int idx = 0;
422 while (at (src, idx))
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) == '*')
429 idx += 3;
431 idx = skip_white_and_stars (src, idx);
433 /* Remove leading dot */
434 if (at (src, idx) == '.')
435 idx++;
437 /* Copy to the end of the line, or till the end of the
438 comment. */
439 while (at (src, idx))
441 if (at (src, idx) == '\n')
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);
450 else if (at (src, idx) == '*' && at (src, idx + 1) == '/')
452 idx += 2;
453 cattext (dst, "\nENDDD\n");
454 break;
456 else
458 catchar (dst, at (src, idx));
459 idx++;
463 else
464 idx++;
468 static void
469 print_stack_level ()
471 fprintf (stderr, "current string stack depth = %d, ", tos - stack);
472 fprintf (stderr, "current integer stack depth = %d\n", isp - istack);
473 pc++;
476 /* turn:
477 foobar name(stuff);
478 into:
479 foobar
480 name PARAMS ((stuff));
481 and a blank line.
484 static void
485 paramstuff (void)
487 unsigned int openp;
488 unsigned int fname;
489 unsigned int idx;
490 string_type out;
491 init_string (&out);
493 /* Make sure that it's not already param'd or proto'd. */
494 if (find (tos, "PARAMS") || find (tos, "PROTO") || !find (tos, "("))
496 catstr (&out, tos);
498 else
500 /* Find the open paren. */
501 for (openp = 0; at (tos, openp) != '(' && at (tos, openp); openp++)
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--;
514 fname++;
516 for (idx = 0; idx < fname; idx++) /* Output type */
518 catchar (&out, at (tos, idx));
521 cattext (&out, "\n"); /* Insert a newline between type and fnname */
523 for (idx = fname; idx < openp; idx++) /* Output fnname */
525 catchar (&out, at (tos, idx));
528 cattext (&out, " PARAMS (");
530 while (at (tos, idx) && at (tos, idx) != ';')
532 catchar (&out, at (tos, idx));
533 idx++;
535 cattext (&out, ");\n\n");
537 overwrite_string (tos, &out);
538 pc++;
542 /* turn {*
543 and *} into comments */
545 WORD (translatecomments)
547 unsigned int idx = 0;
548 string_type out;
549 init_string (&out);
551 while (at (tos, idx))
553 if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
555 cattext (&out, "/*");
556 idx += 2;
558 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
560 cattext (&out, "*/");
561 idx += 2;
563 else
565 catchar (&out, at (tos, idx));
566 idx++;
570 overwrite_string (tos, &out);
572 pc++;
575 #if 0
577 /* This is not currently used. */
579 /* turn everything not starting with a . into a comment */
581 WORD (manglecomments)
583 unsigned int idx = 0;
584 string_type out;
585 init_string (&out);
587 while (at (tos, idx))
589 if (at (tos, idx) == '\n' && at (tos, idx + 1) == '*')
591 cattext (&out, " /*");
592 idx += 2;
594 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
596 cattext (&out, "*/");
597 idx += 2;
599 else
601 catchar (&out, at (tos, idx));
602 idx++;
606 overwrite_string (tos, &out);
608 pc++;
611 #endif
613 /* Mod tos so that only lines with leading dots remain */
614 static void
615 outputdots (void)
617 unsigned int idx = 0;
618 string_type out;
619 init_string (&out);
621 while (at (tos, idx))
623 if (at (tos, idx) == '\n' && at (tos, idx + 1) == '.')
625 char c;
626 idx += 2;
628 while ((c = at (tos, idx)) && c != '\n')
630 if (c == '{' && at (tos, idx + 1) == '*')
632 cattext (&out, "/*");
633 idx += 2;
635 else if (c == '*' && at (tos, idx + 1) == '}')
637 cattext (&out, "*/");
638 idx += 2;
640 else
642 catchar (&out, c);
643 idx++;
646 catchar (&out, '\n');
648 else
650 idx++;
654 overwrite_string (tos, &out);
655 pc++;
658 /* Find lines starting with . and | and put example around them on tos */
659 WORD (courierize)
661 string_type out;
662 unsigned int idx = 0;
663 int command = 0;
665 init_string (&out);
667 while (at (tos, idx))
669 if (at (tos, idx) == '\n'
670 && (at (tos, idx +1 ) == '.'
671 || at (tos, idx + 1) == '|'))
673 cattext (&out, "\n@example\n");
676 idx += 2;
678 while (at (tos, idx) && at (tos, idx) != '\n')
680 if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
682 cattext (&out, "/*");
683 idx += 2;
685 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
687 cattext (&out, "*/");
688 idx += 2;
690 else if (at (tos, idx) == '{' && !command)
692 cattext (&out, "@{");
693 idx++;
695 else if (at (tos, idx) == '}' && !command)
697 cattext (&out, "@}");
698 idx++;
700 else
702 if (at (tos, idx) == '@')
703 command = 1;
704 else if (isspace ((unsigned char) at (tos, idx))
705 || at (tos, idx) == '}')
706 command = 0;
707 catchar (&out, at (tos, idx));
708 idx++;
712 catchar (&out, '\n');
714 while (at (tos, idx) == '\n'
715 && ((at (tos, idx + 1) == '.')
716 || (at (tos, idx + 1) == '|')))
718 cattext (&out, "@end example");
720 else
722 catchar (&out, at (tos, idx));
723 idx++;
727 overwrite_string (tos, &out);
728 pc++;
731 /* Finds any lines starting with "o ", if there are any, then turns
732 on @itemize @bullet, and @items each of them. Then ends with @end
733 itemize, inplace at TOS*/
735 WORD (bulletize)
737 unsigned int idx = 0;
738 int on = 0;
739 string_type out;
740 init_string (&out);
742 while (at (tos, idx))
744 if (at (tos, idx) == '@'
745 && at (tos, idx + 1) == '*')
747 cattext (&out, "*");
748 idx += 2;
750 else if (at (tos, idx) == '\n'
751 && at (tos, idx + 1) == 'o'
752 && isspace ((unsigned char) at (tos, idx + 2)))
754 if (!on)
756 cattext (&out, "\n@itemize @bullet\n");
757 on = 1;
760 cattext (&out, "\n@item\n");
761 idx += 3;
763 else
765 catchar (&out, at (tos, idx));
766 if (on && at (tos, idx) == '\n'
767 && at (tos, idx + 1) == '\n'
768 && at (tos, idx + 2) != 'o')
770 cattext (&out, "@end itemize");
771 on = 0;
773 idx++;
777 if (on)
779 cattext (&out, "@end itemize\n");
782 delete_string (tos);
783 *tos = out;
784 pc++;
787 /* Turn <<foo>> into @code{foo} in place at TOS*/
789 WORD (do_fancy_stuff)
791 unsigned int idx = 0;
792 string_type out;
793 init_string (&out);
794 while (at (tos, idx))
796 if (at (tos, idx) == '<'
797 && at (tos, idx + 1) == '<'
798 && !isspace ((unsigned char) at (tos, idx + 2)))
800 /* This qualifies as a << startup. */
801 idx += 2;
802 cattext (&out, "@code{");
803 while (at (tos, idx)
804 && at (tos, idx) != '>' )
806 catchar (&out, at (tos, idx));
807 idx++;
810 cattext (&out, "}");
811 idx += 2;
813 else
815 catchar (&out, at (tos, idx));
816 idx++;
819 delete_string (tos);
820 *tos = out;
821 pc++;
825 /* A command is all upper case,and alone on a line. */
827 static int
828 iscommand (ptr, idx)
829 string_type *ptr;
830 unsigned int idx;
832 unsigned int len = 0;
833 while (at (ptr, idx))
835 if (isupper ((unsigned char) at (ptr, idx))
836 || at (ptr, idx) == ' ' || at (ptr, idx) == '_')
838 len++;
839 idx++;
841 else if (at (ptr, idx) == '\n')
843 if (len > 3)
844 return 1;
845 return 0;
847 else
848 return 0;
850 return 0;
853 static int
854 copy_past_newline (ptr, idx, dst)
855 string_type *ptr;
856 unsigned int idx;
857 string_type *dst;
859 int column = 0;
861 while (at (ptr, idx) && at (ptr, idx) != '\n')
863 if (at (ptr, idx) == '\t')
865 /* Expand tabs. Neither makeinfo nor TeX can cope well with
866 them. */
868 catchar (dst, ' ');
869 while (++column & 7);
871 else
873 catchar (dst, at (ptr, idx));
874 column++;
876 idx++;
879 catchar (dst, at (ptr, idx));
880 idx++;
881 return idx;
885 WORD (icopy_past_newline)
887 tos++;
888 check_range ();
889 init_string (tos);
890 idx = copy_past_newline (ptr, idx, tos);
891 pc++;
894 /* indent
895 Take the string at the top of the stack, do some prettying. */
897 WORD (kill_bogus_lines)
899 int sl;
901 int idx = 0;
902 int c;
903 int dot = 0;
905 string_type out;
906 init_string (&out);
907 /* Drop leading nl. */
908 while (at (tos, idx) == '\n')
910 idx++;
912 c = idx;
914 /* If the first char is a '.' prepend a newline so that it is
915 recognized properly later. */
916 if (at (tos, idx) == '.')
917 catchar (&out, '\n');
919 /* Find the last char. */
920 while (at (tos, idx))
922 idx++;
925 /* Find the last non white before the nl. */
926 idx--;
928 while (idx && isspace ((unsigned char) at (tos, idx)))
929 idx--;
930 idx++;
932 /* Copy buffer upto last char, but blank lines before and after
933 dots don't count. */
934 sl = 1;
936 while (c < idx)
938 if (at (tos, c) == '\n'
939 && at (tos, c + 1) == '\n'
940 && at (tos, c + 2) == '.')
942 /* Ignore two newlines before a dot. */
943 c++;
945 else if (at (tos, c) == '.' && sl)
947 /* remember that this line started with a dot. */
948 dot = 2;
950 else if (at (tos, c) == '\n'
951 && at (tos, c + 1) == '\n'
952 && dot)
954 c++;
955 /* Ignore two newlines when last line was dot. */
958 catchar (&out, at (tos, c));
959 if (at (tos, c) == '\n')
961 sl = 1;
963 if (dot == 2)
964 dot = 1;
965 else
966 dot = 0;
968 else
969 sl = 0;
971 c++;
975 /* Append nl. */
976 catchar (&out, '\n');
977 pc++;
978 delete_string (tos);
979 *tos = out;
983 WORD (indent)
985 string_type out;
986 int tab = 0;
987 int idx = 0;
988 int ol = 0;
989 init_string (&out);
990 while (at (tos, idx))
992 switch (at (tos, idx))
994 case '\n':
995 cattext (&out, "\n");
996 idx++;
997 if (tab && at (tos, idx))
999 cattext (&out, " ");
1001 ol = 0;
1002 break;
1003 case '(':
1004 tab++;
1005 if (ol == 0)
1006 cattext (&out, " ");
1007 idx++;
1008 cattext (&out, "(");
1009 ol = 1;
1010 break;
1011 case ')':
1012 tab--;
1013 cattext (&out, ")");
1014 idx++;
1015 ol = 1;
1017 break;
1018 default:
1019 catchar (&out, at (tos, idx));
1020 ol = 1;
1022 idx++;
1023 break;
1027 pc++;
1028 delete_string (tos);
1029 *tos = out;
1033 WORD (get_stuff_in_command)
1035 tos++;
1036 check_range ();
1037 init_string (tos);
1039 while (at (ptr, idx))
1041 if (iscommand (ptr, idx))
1042 break;
1043 idx = copy_past_newline (ptr, idx, tos);
1045 pc++;
1048 WORD (swap)
1050 string_type t;
1052 t = tos[0];
1053 tos[0] = tos[-1];
1054 tos[-1] = t;
1055 pc++;
1058 WORD (other_dup)
1060 tos++;
1061 check_range ();
1062 init_string (tos);
1063 catstr (tos, tos - 1);
1064 pc++;
1067 WORD (drop)
1069 tos--;
1070 check_range ();
1071 pc++;
1074 WORD (idrop)
1076 isp--;
1077 icheck_range ();
1078 pc++;
1081 WORD (icatstr)
1083 tos--;
1084 check_range ();
1085 catstr (tos, tos + 1);
1086 delete_string (tos + 1);
1087 pc++;
1090 WORD (skip_past_newline)
1092 while (at (ptr, idx)
1093 && at (ptr, idx) != '\n')
1094 idx++;
1095 idx++;
1096 pc++;
1099 WORD (internalmode)
1101 internal_mode = *(isp);
1102 isp--;
1103 icheck_range ();
1104 pc++;
1107 WORD (maybecatstr)
1109 if (internal_wanted == internal_mode)
1111 catstr (tos - 1, tos);
1113 delete_string (tos);
1114 tos--;
1115 check_range ();
1116 pc++;
1119 char *
1120 nextword (string, word)
1121 char *string;
1122 char **word;
1124 char *word_start;
1125 int idx;
1126 char *dst;
1127 char *src;
1129 int length = 0;
1131 while (isspace ((unsigned char) *string) || *string == '-')
1133 if (*string == '-')
1135 while (*string && *string != '\n')
1136 string++;
1139 else
1141 string++;
1144 if (!*string)
1145 return 0;
1147 word_start = string;
1148 if (*string == '"')
1152 string++;
1153 length++;
1154 if (*string == '\\')
1156 string += 2;
1157 length += 2;
1160 while (*string != '"');
1162 else
1164 while (!isspace ((unsigned char) *string))
1166 string++;
1167 length++;
1172 *word = malloc (length + 1);
1174 dst = *word;
1175 src = word_start;
1177 for (idx = 0; idx < length; idx++)
1179 if (src[idx] == '\\')
1180 switch (src[idx + 1])
1182 case 'n':
1183 *dst++ = '\n';
1184 idx++;
1185 break;
1186 case '"':
1187 case '\\':
1188 *dst++ = src[idx + 1];
1189 idx++;
1190 break;
1191 default:
1192 *dst++ = '\\';
1193 break;
1195 else
1196 *dst++ = src[idx];
1198 *dst++ = 0;
1200 if (*string)
1201 return string + 1;
1202 else
1203 return 0;
1206 dict_type *root;
1208 dict_type *
1209 lookup_word (word)
1210 char *word;
1212 dict_type *ptr = root;
1213 while (ptr)
1215 if (strcmp (ptr->word, word) == 0)
1216 return ptr;
1217 ptr = ptr->next;
1219 if (warning)
1220 fprintf (stderr, "Can't find %s\n", word);
1221 return 0;
1224 static void
1225 perform (void)
1227 tos = stack;
1229 while (at (ptr, idx))
1231 /* It's worth looking through the command list. */
1232 if (iscommand (ptr, idx))
1234 char *next;
1235 dict_type *word;
1237 (void) nextword (addr (ptr, idx), &next);
1239 word = lookup_word (next);
1241 if (word)
1243 exec (word);
1245 else
1247 if (warning)
1248 fprintf (stderr, "warning, %s is not recognised\n", next);
1249 skip_past_newline ();
1253 else
1254 skip_past_newline ();
1258 dict_type *
1259 newentry (word)
1260 char *word;
1262 dict_type *new = (dict_type *) malloc (sizeof (dict_type));
1263 new->word = word;
1264 new->next = root;
1265 root = new;
1266 new->code = (stinst_type *) malloc (sizeof (stinst_type));
1267 new->code_length = 1;
1268 new->code_end = 0;
1269 return new;
1272 unsigned int
1273 add_to_definition (entry, word)
1274 dict_type *entry;
1275 stinst_type word;
1277 if (entry->code_end == entry->code_length)
1279 entry->code_length += 2;
1280 entry->code =
1281 (stinst_type *) realloc ((char *) (entry->code),
1282 entry->code_length * sizeof (word_type));
1284 entry->code[entry->code_end] = word;
1286 return entry->code_end++;
1289 void
1290 add_intrinsic (name, func)
1291 char *name;
1292 void (*func) ();
1294 dict_type *new = newentry (name);
1295 add_to_definition (new, func);
1296 add_to_definition (new, 0);
1299 void
1300 add_var (name)
1301 char *name;
1303 dict_type *new = newentry (name);
1304 add_to_definition (new, push_number);
1305 add_to_definition (new, (stinst_type) (&(new->var)));
1306 add_to_definition (new, 0);
1309 void
1310 compile (string)
1311 char *string;
1313 /* Add words to the dictionary. */
1314 char *word;
1315 string = nextword (string, &word);
1316 while (string && *string && word[0])
1318 if (strcmp (word, "var") == 0)
1320 string = nextword (string, &word);
1322 add_var (word);
1323 string = nextword (string, &word);
1325 else if (word[0] == ':')
1327 dict_type *ptr;
1328 /* Compile a word and add to dictionary. */
1329 string = nextword (string, &word);
1331 ptr = newentry (word);
1332 string = nextword (string, &word);
1333 while (word[0] != ';')
1335 switch (word[0])
1337 case '"':
1338 /* got a string, embed magic push string
1339 function */
1340 add_to_definition (ptr, push_text);
1341 add_to_definition (ptr, (stinst_type) (word + 1));
1342 break;
1343 case '0':
1344 case '1':
1345 case '2':
1346 case '3':
1347 case '4':
1348 case '5':
1349 case '6':
1350 case '7':
1351 case '8':
1352 case '9':
1353 /* Got a number, embedd the magic push number
1354 function */
1355 add_to_definition (ptr, push_number);
1356 add_to_definition (ptr, (stinst_type) atol (word));
1357 break;
1358 default:
1359 add_to_definition (ptr, call);
1360 add_to_definition (ptr, (stinst_type) lookup_word (word));
1363 string = nextword (string, &word);
1365 add_to_definition (ptr, 0);
1366 string = nextword (string, &word);
1368 else
1370 fprintf (stderr, "syntax error at %s\n", string - 1);
1375 static void
1376 bang (void)
1378 *(long *) ((isp[0])) = isp[-1];
1379 isp -= 2;
1380 icheck_range ();
1381 pc++;
1384 WORD (atsign)
1386 isp[0] = *(long *) (isp[0]);
1387 pc++;
1390 WORD (hello)
1392 printf ("hello\n");
1393 pc++;
1396 WORD (stdout_)
1398 isp++;
1399 icheck_range ();
1400 *isp = 1;
1401 pc++;
1404 WORD (stderr_)
1406 isp++;
1407 icheck_range ();
1408 *isp = 2;
1409 pc++;
1412 WORD (print)
1414 if (*isp == 1)
1415 write_buffer (tos, stdout);
1416 else if (*isp == 2)
1417 write_buffer (tos, stderr);
1418 else
1419 fprintf (stderr, "print: illegal print destination `%ld'\n", *isp);
1420 isp--;
1421 tos--;
1422 icheck_range ();
1423 check_range ();
1424 pc++;
1427 static void
1428 read_in (str, file)
1429 string_type *str;
1430 FILE *file;
1432 char buff[10000];
1433 unsigned int r;
1436 r = fread (buff, 1, sizeof (buff), file);
1437 catbuf (str, buff, r);
1439 while (r);
1440 buff[0] = 0;
1442 catbuf (str, buff, 1);
1445 static void
1446 usage (void)
1448 fprintf (stderr, "usage: -[d|i|g] <file >file\n");
1449 exit (33);
1452 /* There is no reliable way to declare exit. Sometimes it returns
1453 int, and sometimes it returns void. Sometimes it changes between
1454 OS releases. Trying to get it declared correctly in the hosts file
1455 is a pointless waste of time. */
1457 static void
1458 chew_exit ()
1460 exit (0);
1464 main (ac, av)
1465 int ac;
1466 char *av[];
1468 unsigned int i;
1469 string_type buffer;
1470 string_type pptr;
1472 init_string (&buffer);
1473 init_string (&pptr);
1474 init_string (stack + 0);
1475 tos = stack + 1;
1476 ptr = &pptr;
1478 add_intrinsic ("push_text", push_text);
1479 add_intrinsic ("!", bang);
1480 add_intrinsic ("@", atsign);
1481 add_intrinsic ("hello", hello);
1482 add_intrinsic ("stdout", stdout_);
1483 add_intrinsic ("stderr", stderr_);
1484 add_intrinsic ("print", print);
1485 add_intrinsic ("skip_past_newline", skip_past_newline);
1486 add_intrinsic ("catstr", icatstr);
1487 add_intrinsic ("copy_past_newline", icopy_past_newline);
1488 add_intrinsic ("dup", other_dup);
1489 add_intrinsic ("drop", drop);
1490 add_intrinsic ("idrop", idrop);
1491 add_intrinsic ("remchar", remchar);
1492 add_intrinsic ("get_stuff_in_command", get_stuff_in_command);
1493 add_intrinsic ("do_fancy_stuff", do_fancy_stuff);
1494 add_intrinsic ("bulletize", bulletize);
1495 add_intrinsic ("courierize", courierize);
1496 /* If the following line gives an error, exit() is not declared in the
1497 ../hosts/foo.h file for this host. Fix it there, not here! */
1498 /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1499 add_intrinsic ("exit", chew_exit);
1500 add_intrinsic ("swap", swap);
1501 add_intrinsic ("outputdots", outputdots);
1502 add_intrinsic ("paramstuff", paramstuff);
1503 add_intrinsic ("maybecatstr", maybecatstr);
1504 add_intrinsic ("translatecomments", translatecomments);
1505 add_intrinsic ("kill_bogus_lines", kill_bogus_lines);
1506 add_intrinsic ("indent", indent);
1507 add_intrinsic ("internalmode", internalmode);
1508 add_intrinsic ("print_stack_level", print_stack_level);
1509 add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines);
1511 /* Put a nl at the start. */
1512 catchar (&buffer, '\n');
1514 read_in (&buffer, stdin);
1515 remove_noncomments (&buffer, ptr);
1516 for (i = 1; i < (unsigned int) ac; i++)
1518 if (av[i][0] == '-')
1520 if (av[i][1] == 'f')
1522 string_type b;
1523 FILE *f;
1524 init_string (&b);
1526 f = fopen (av[i + 1], "r");
1527 if (!f)
1529 fprintf (stderr, "Can't open the input file %s\n",
1530 av[i + 1]);
1531 return 33;
1534 read_in (&b, f);
1535 compile (b.ptr);
1536 perform ();
1538 else if (av[i][1] == 'i')
1540 internal_wanted = 1;
1542 else if (av[i][1] == 'w')
1544 warning = 1;
1546 else
1547 usage ();
1550 write_buffer (stack + 0, stdout);
1551 if (tos != stack)
1553 fprintf (stderr, "finishing with current stack level %d\n",
1554 tos - stack);
1555 return 1;
1557 return 0;