bfd/
[binutils.git] / bfd / doc / chew.c
blob7c060da2d1cb3068d86988f5267a2de1c05c00be
1 /* chew
2 Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 2000, 2001,
3 2002, 2003
4 Free Software Foundation, Inc.
5 Contributed by steve chamberlain @cygnus
7 This file is part of BFD, the Binary File Descriptor library.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23 /* Yet another way of extracting documentation from source.
24 No, I haven't finished it yet, but I hope you people like it better
25 than the old way
27 sac
29 Basically, this is a sort of string forth, maybe we should call it
30 struth?
32 You define new words thus:
33 : <newword> <oldwords> ;
37 /* Primitives provided by the program:
39 Two stacks are provided, a string stack and an integer stack.
41 Internal state variables:
42 internal_wanted - indicates whether `-i' was passed
43 internal_mode - user-settable
45 Commands:
46 push_text
47 ! - pop top of integer stack for address, pop next for value; store
48 @ - treat value on integer stack as the address of an integer; push
49 that integer on the integer stack after popping the "address"
50 hello - print "hello\n" to stdout
51 stdout - put stdout marker on TOS
52 stderr - put stderr marker on TOS
53 print - print TOS-1 on TOS (eg: "hello\n" stdout print)
54 skip_past_newline
55 catstr - fn icatstr
56 copy_past_newline - append input, up to and including newline into TOS
57 dup - fn other_dup
58 drop - discard TOS
59 idrop - ditto
60 remchar - delete last character from TOS
61 get_stuff_in_command
62 do_fancy_stuff - translate <<foo>> to @code{foo} in TOS
63 bulletize - if "o" lines found, prepend @itemize @bullet to TOS
64 and @item to each "o" line; append @end itemize
65 courierize - put @example around . and | lines, translate {* *} { }
66 exit - fn chew_exit
67 swap
68 outputdots - strip out lines without leading dots
69 paramstuff - convert full declaration into "PARAMS" form if not already
70 maybecatstr - do catstr if internal_mode == internal_wanted, discard
71 value in any case
72 translatecomments - turn {* and *} into comment delimiters
73 kill_bogus_lines - get rid of extra newlines
74 indent
75 internalmode - pop from integer stack, set `internalmode' to that value
76 print_stack_level - print current stack depth to stderr
77 strip_trailing_newlines - go ahead, guess...
78 [quoted string] - push string onto string stack
79 [word starting with digit] - push atol(str) onto integer stack
81 A command must be all upper-case, and alone on a line.
83 Foo. */
85 #include "ansidecl.h"
86 #include "sysdep.h"
87 #include <assert.h>
88 #include <stdio.h>
89 #include <ctype.h>
91 #define DEF_SIZE 5000
92 #define STACK 50
94 int internal_wanted;
95 int internal_mode;
97 int warning;
99 /* Here is a string type ... */
101 typedef struct buffer
103 char *ptr;
104 unsigned long write_idx;
105 unsigned long size;
106 } string_type;
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 #endif
123 static void
124 init_string_with_size (buffer, size)
125 string_type *buffer;
126 unsigned int size;
128 buffer->write_idx = 0;
129 buffer->size = size;
130 buffer->ptr = malloc (size);
133 static void
134 init_string (buffer)
135 string_type *buffer;
137 init_string_with_size (buffer, DEF_SIZE);
140 static int
141 find (str, what)
142 string_type *str;
143 char *what;
145 unsigned int i;
146 char *p;
147 p = what;
148 for (i = 0; i < str->write_idx && *p; i++)
150 if (*p == str->ptr[i])
151 p++;
152 else
153 p = what;
155 return (*p == 0);
158 static void
159 write_buffer (buffer, f)
160 string_type *buffer;
161 FILE *f;
163 fwrite (buffer->ptr, buffer->write_idx, 1, f);
166 static void
167 delete_string (buffer)
168 string_type *buffer;
170 free (buffer->ptr);
173 static char *
174 addr (buffer, idx)
175 string_type *buffer;
176 unsigned int idx;
178 return buffer->ptr + idx;
181 static char
182 at (buffer, pos)
183 string_type *buffer;
184 unsigned int pos;
186 if (pos >= buffer->write_idx)
187 return 0;
188 return buffer->ptr[pos];
191 static void
192 catchar (buffer, ch)
193 string_type *buffer;
194 int ch;
196 if (buffer->write_idx == buffer->size)
198 buffer->size *= 2;
199 buffer->ptr = realloc (buffer->ptr, buffer->size);
202 buffer->ptr[buffer->write_idx++] = ch;
205 static void
206 overwrite_string (dst, src)
207 string_type *dst;
208 string_type *src;
210 free (dst->ptr);
211 dst->size = src->size;
212 dst->write_idx = src->write_idx;
213 dst->ptr = src->ptr;
216 static void
217 catbuf (buffer, buf, len)
218 string_type *buffer;
219 char *buf;
220 unsigned int len;
222 if (buffer->write_idx + len >= buffer->size)
224 while (buffer->write_idx + len >= buffer->size)
225 buffer->size *= 2;
226 buffer->ptr = realloc (buffer->ptr, buffer->size);
228 memcpy (buffer->ptr + buffer->write_idx, buf, len);
229 buffer->write_idx += len;
232 static void
233 cattext (buffer, string)
234 string_type *buffer;
235 char *string;
237 catbuf (buffer, string, (unsigned int) strlen (string));
240 static void
241 catstr (dst, src)
242 string_type *dst;
243 string_type *src;
245 catbuf (dst, src->ptr, src->write_idx);
248 static unsigned int
249 skip_white_and_stars (src, idx)
250 string_type *src;
251 unsigned int idx;
253 char c;
254 while ((c = at (src, idx)),
255 isspace ((unsigned char) c)
256 || (c == '*'
257 /* Don't skip past end-of-comment or star as first
258 character on its line. */
259 && at (src, idx +1) != '/'
260 && at (src, idx -1) != '\n'))
261 idx++;
262 return idx;
265 /***********************************************************************/
267 string_type stack[STACK];
268 string_type *tos;
270 unsigned int idx = 0; /* Pos in input buffer */
271 string_type *ptr; /* and the buffer */
272 typedef void (*stinst_type)();
273 stinst_type *pc;
274 stinst_type sstack[STACK];
275 stinst_type *ssp = &sstack[0];
276 long istack[STACK];
277 long *isp = &istack[0];
279 typedef int *word_type;
281 struct dict_struct
283 char *word;
284 struct dict_struct *next;
285 stinst_type *code;
286 int code_length;
287 int code_end;
288 int var;
291 typedef struct dict_struct dict_type;
293 static void
294 die (msg)
295 char *msg;
297 fprintf (stderr, "%s\n", msg);
298 exit (1);
301 static void
302 check_range ()
304 if (tos < stack)
305 die ("underflow in string stack");
306 if (tos >= stack + STACK)
307 die ("overflow in string stack");
310 static void
311 icheck_range ()
313 if (isp < istack)
314 die ("underflow in integer stack");
315 if (isp >= istack + STACK)
316 die ("overflow in integer stack");
319 #ifdef __STDC__
320 static void exec (dict_type *);
321 static void call (void);
322 static void remchar (void), strip_trailing_newlines (void), push_number (void);
323 static void push_text (void);
324 static void remove_noncomments (string_type *, string_type *);
325 static void print_stack_level (void);
326 static void paramstuff (void), translatecomments (void);
327 static void outputdots (void), courierize (void), bulletize (void);
328 static void do_fancy_stuff (void);
329 static int iscommand (string_type *, unsigned int);
330 static int copy_past_newline (string_type *, unsigned int, string_type *);
331 static void icopy_past_newline (void), kill_bogus_lines (void), indent (void);
332 static void get_stuff_in_command (void), swap (void), other_dup (void);
333 static void drop (void), idrop (void);
334 static void icatstr (void), skip_past_newline (void), internalmode (void);
335 static void maybecatstr (void);
336 static char *nextword (char *, char **);
337 dict_type *lookup_word (char *);
338 static void perform (void);
339 dict_type *newentry (char *);
340 unsigned int add_to_definition (dict_type *, stinst_type);
341 void add_intrinsic (char *, void (*)());
342 void add_var (char *);
343 void compile (char *);
344 static void bang (void);
345 static void atsign (void);
346 static void hello (void);
347 static void stdout_ (void);
348 static void stderr_ (void);
349 static void print (void);
350 static void read_in (string_type *, FILE *);
351 static void usage (void);
352 static void chew_exit (void);
353 #endif
355 static void
356 exec (word)
357 dict_type *word;
359 pc = word->code;
360 while (*pc)
361 (*pc) ();
364 static void
365 call ()
367 stinst_type *oldpc = pc;
368 dict_type *e;
369 e = (dict_type *) (pc[1]);
370 exec (e);
371 pc = oldpc + 2;
374 static void
375 remchar ()
377 if (tos->write_idx)
378 tos->write_idx--;
379 pc++;
382 static void
383 strip_trailing_newlines ()
385 while ((isspace ((unsigned char) at (tos, tos->write_idx - 1))
386 || at (tos, tos->write_idx - 1) == '\n')
387 && tos->write_idx > 0)
388 tos->write_idx--;
389 pc++;
392 static void
393 push_number ()
395 isp++;
396 icheck_range ();
397 pc++;
398 *isp = (long) (*pc);
399 pc++;
402 static void
403 push_text ()
405 tos++;
406 check_range ();
407 init_string (tos);
408 pc++;
409 cattext (tos, *((char **) pc));
410 pc++;
413 /* This function removes everything not inside comments starting on
414 the first char of the line from the string, also when copying
415 comments, removes blank space and leading *'s.
416 Blank lines are turned into one blank line. */
418 static void
419 remove_noncomments (src, dst)
420 string_type *src;
421 string_type *dst;
423 unsigned int idx = 0;
425 while (at (src, idx))
427 /* Now see if we have a comment at the start of the line. */
428 if (at (src, idx) == '\n'
429 && at (src, idx + 1) == '/'
430 && at (src, idx + 2) == '*')
432 idx += 3;
434 idx = skip_white_and_stars (src, idx);
436 /* Remove leading dot */
437 if (at (src, idx) == '.')
438 idx++;
440 /* Copy to the end of the line, or till the end of the
441 comment. */
442 while (at (src, idx))
444 if (at (src, idx) == '\n')
446 /* end of line, echo and scrape of leading blanks */
447 if (at (src, idx + 1) == '\n')
448 catchar (dst, '\n');
449 catchar (dst, '\n');
450 idx++;
451 idx = skip_white_and_stars (src, idx);
453 else if (at (src, idx) == '*' && at (src, idx + 1) == '/')
455 idx += 2;
456 cattext (dst, "\nENDDD\n");
457 break;
459 else
461 catchar (dst, at (src, idx));
462 idx++;
466 else
467 idx++;
471 static void
472 print_stack_level ()
474 fprintf (stderr, "current string stack depth = %d, ", tos - stack);
475 fprintf (stderr, "current integer stack depth = %d\n", isp - istack);
476 pc++;
479 /* turn:
480 foobar name(stuff);
481 into:
482 foobar
483 name PARAMS ((stuff));
484 and a blank line.
487 static void
488 paramstuff ()
490 unsigned int openp;
491 unsigned int fname;
492 unsigned int idx;
493 unsigned int len;
494 string_type out;
495 init_string (&out);
497 #define NO_PARAMS 1
499 /* Make sure that it's not already param'd or proto'd. */
500 if (NO_PARAMS
501 || find (tos, "PARAMS") || find (tos, "PROTO") || !find (tos, "("))
503 catstr (&out, tos);
505 else
507 /* Find the open paren. */
508 for (openp = 0; at (tos, openp) != '(' && at (tos, openp); openp++)
511 fname = openp;
512 /* Step back to the fname. */
513 fname--;
514 while (fname && isspace ((unsigned char) at (tos, fname)))
515 fname--;
516 while (fname
517 && !isspace ((unsigned char) at (tos,fname))
518 && at (tos,fname) != '*')
519 fname--;
521 fname++;
523 /* Output type, omitting trailing whitespace character(s), if
524 any. */
525 for (len = fname; 0 < len; len--)
527 if (!isspace ((unsigned char) at (tos, len - 1)))
528 break;
530 for (idx = 0; idx < len; idx++)
531 catchar (&out, at (tos, idx));
533 cattext (&out, "\n"); /* Insert a newline between type and fnname */
535 /* Output function name, omitting trailing whitespace
536 character(s), if any. */
537 for (len = openp; 0 < len; len--)
539 if (!isspace ((unsigned char) at (tos, len - 1)))
540 break;
542 for (idx = fname; idx < len; idx++)
543 catchar (&out, at (tos, idx));
545 cattext (&out, " PARAMS (");
547 for (idx = openp; at (tos, idx) && at (tos, idx) != ';'; idx++)
548 catchar (&out, at (tos, idx));
550 cattext (&out, ");\n\n");
552 overwrite_string (tos, &out);
553 pc++;
557 /* turn {*
558 and *} into comments */
560 static void
561 translatecomments ()
563 unsigned int idx = 0;
564 string_type out;
565 init_string (&out);
567 while (at (tos, idx))
569 if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
571 cattext (&out, "/*");
572 idx += 2;
574 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
576 cattext (&out, "*/");
577 idx += 2;
579 else
581 catchar (&out, at (tos, idx));
582 idx++;
586 overwrite_string (tos, &out);
588 pc++;
591 #if 0
593 /* This is not currently used. */
595 /* turn everything not starting with a . into a comment */
597 static void
598 manglecomments ()
600 unsigned int idx = 0;
601 string_type out;
602 init_string (&out);
604 while (at (tos, idx))
606 if (at (tos, idx) == '\n' && at (tos, idx + 1) == '*')
608 cattext (&out, " /*");
609 idx += 2;
611 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
613 cattext (&out, "*/");
614 idx += 2;
616 else
618 catchar (&out, at (tos, idx));
619 idx++;
623 overwrite_string (tos, &out);
625 pc++;
628 #endif
630 /* Mod tos so that only lines with leading dots remain */
631 static void
632 outputdots ()
634 unsigned int idx = 0;
635 string_type out;
636 init_string (&out);
638 while (at (tos, idx))
640 if (at (tos, idx) == '\n' && at (tos, idx + 1) == '.')
642 char c;
643 idx += 2;
645 while ((c = at (tos, idx)) && c != '\n')
647 if (c == '{' && at (tos, idx + 1) == '*')
649 cattext (&out, "/*");
650 idx += 2;
652 else if (c == '*' && at (tos, idx + 1) == '}')
654 cattext (&out, "*/");
655 idx += 2;
657 else
659 catchar (&out, c);
660 idx++;
663 catchar (&out, '\n');
665 else
667 idx++;
671 overwrite_string (tos, &out);
672 pc++;
675 /* Find lines starting with . and | and put example around them on tos */
676 static void
677 courierize ()
679 string_type out;
680 unsigned int idx = 0;
681 int command = 0;
683 init_string (&out);
685 while (at (tos, idx))
687 if (at (tos, idx) == '\n'
688 && (at (tos, idx +1 ) == '.'
689 || at (tos, idx + 1) == '|'))
691 cattext (&out, "\n@example\n");
694 idx += 2;
696 while (at (tos, idx) && at (tos, idx) != '\n')
698 if (command > 1)
700 /* We are inside {} parameters of some command;
701 Just pass through until matching brace. */
702 if (at (tos, idx) == '{')
703 ++command;
704 else if (at (tos, idx) == '}')
705 --command;
707 else if (command != 0)
709 if (at (tos, idx) == '{')
710 ++command;
711 else if (!islower ((unsigned char) at (tos, idx)))
712 --command;
714 else if (at (tos, idx) == '@'
715 && islower ((unsigned char) at (tos, idx + 1)))
717 ++command;
719 else if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
721 cattext (&out, "/*");
722 idx += 2;
723 continue;
725 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
727 cattext (&out, "*/");
728 idx += 2;
729 continue;
731 else if (at (tos, idx) == '{'
732 || at (tos, idx) == '}')
734 catchar (&out, '@');
737 catchar (&out, at (tos, idx));
738 idx++;
740 catchar (&out, '\n');
742 while (at (tos, idx) == '\n'
743 && ((at (tos, idx + 1) == '.')
744 || (at (tos, idx + 1) == '|')))
746 cattext (&out, "@end example");
748 else
750 catchar (&out, at (tos, idx));
751 idx++;
755 overwrite_string (tos, &out);
756 pc++;
759 /* Finds any lines starting with "o ", if there are any, then turns
760 on @itemize @bullet, and @items each of them. Then ends with @end
761 itemize, inplace at TOS*/
763 static void
764 bulletize ()
766 unsigned int idx = 0;
767 int on = 0;
768 string_type out;
769 init_string (&out);
771 while (at (tos, idx))
773 if (at (tos, idx) == '@'
774 && at (tos, idx + 1) == '*')
776 cattext (&out, "*");
777 idx += 2;
779 else if (at (tos, idx) == '\n'
780 && at (tos, idx + 1) == 'o'
781 && isspace ((unsigned char) at (tos, idx + 2)))
783 if (!on)
785 cattext (&out, "\n@itemize @bullet\n");
786 on = 1;
789 cattext (&out, "\n@item\n");
790 idx += 3;
792 else
794 catchar (&out, at (tos, idx));
795 if (on && at (tos, idx) == '\n'
796 && at (tos, idx + 1) == '\n'
797 && at (tos, idx + 2) != 'o')
799 cattext (&out, "@end itemize");
800 on = 0;
802 idx++;
806 if (on)
808 cattext (&out, "@end itemize\n");
811 delete_string (tos);
812 *tos = out;
813 pc++;
816 /* Turn <<foo>> into @code{foo} in place at TOS*/
818 static void
819 do_fancy_stuff ()
821 unsigned int idx = 0;
822 string_type out;
823 init_string (&out);
824 while (at (tos, idx))
826 if (at (tos, idx) == '<'
827 && at (tos, idx + 1) == '<'
828 && !isspace ((unsigned char) at (tos, idx + 2)))
830 /* This qualifies as a << startup. */
831 idx += 2;
832 cattext (&out, "@code{");
833 while (at (tos, idx)
834 && at (tos, idx) != '>' )
836 catchar (&out, at (tos, idx));
837 idx++;
840 cattext (&out, "}");
841 idx += 2;
843 else
845 catchar (&out, at (tos, idx));
846 idx++;
849 delete_string (tos);
850 *tos = out;
851 pc++;
855 /* A command is all upper case,and alone on a line. */
857 static int
858 iscommand (ptr, idx)
859 string_type *ptr;
860 unsigned int idx;
862 unsigned int len = 0;
863 while (at (ptr, idx))
865 if (isupper ((unsigned char) at (ptr, idx))
866 || at (ptr, idx) == ' ' || at (ptr, idx) == '_')
868 len++;
869 idx++;
871 else if (at (ptr, idx) == '\n')
873 if (len > 3)
874 return 1;
875 return 0;
877 else
878 return 0;
880 return 0;
883 static int
884 copy_past_newline (ptr, idx, dst)
885 string_type *ptr;
886 unsigned int idx;
887 string_type *dst;
889 int column = 0;
891 while (at (ptr, idx) && at (ptr, idx) != '\n')
893 if (at (ptr, idx) == '\t')
895 /* Expand tabs. Neither makeinfo nor TeX can cope well with
896 them. */
898 catchar (dst, ' ');
899 while (++column & 7);
901 else
903 catchar (dst, at (ptr, idx));
904 column++;
906 idx++;
909 catchar (dst, at (ptr, idx));
910 idx++;
911 return idx;
915 static void
916 icopy_past_newline ()
918 tos++;
919 check_range ();
920 init_string (tos);
921 idx = copy_past_newline (ptr, idx, tos);
922 pc++;
925 /* indent
926 Take the string at the top of the stack, do some prettying. */
928 static void
929 kill_bogus_lines ()
931 int sl;
933 int idx = 0;
934 int c;
935 int dot = 0;
937 string_type out;
938 init_string (&out);
939 /* Drop leading nl. */
940 while (at (tos, idx) == '\n')
942 idx++;
944 c = idx;
946 /* If the first char is a '.' prepend a newline so that it is
947 recognized properly later. */
948 if (at (tos, idx) == '.')
949 catchar (&out, '\n');
951 /* Find the last char. */
952 while (at (tos, idx))
954 idx++;
957 /* Find the last non white before the nl. */
958 idx--;
960 while (idx && isspace ((unsigned char) at (tos, idx)))
961 idx--;
962 idx++;
964 /* Copy buffer upto last char, but blank lines before and after
965 dots don't count. */
966 sl = 1;
968 while (c < idx)
970 if (at (tos, c) == '\n'
971 && at (tos, c + 1) == '\n'
972 && at (tos, c + 2) == '.')
974 /* Ignore two newlines before a dot. */
975 c++;
977 else if (at (tos, c) == '.' && sl)
979 /* remember that this line started with a dot. */
980 dot = 2;
982 else if (at (tos, c) == '\n'
983 && at (tos, c + 1) == '\n'
984 && dot)
986 c++;
987 /* Ignore two newlines when last line was dot. */
990 catchar (&out, at (tos, c));
991 if (at (tos, c) == '\n')
993 sl = 1;
995 if (dot == 2)
996 dot = 1;
997 else
998 dot = 0;
1000 else
1001 sl = 0;
1003 c++;
1007 /* Append nl. */
1008 catchar (&out, '\n');
1009 pc++;
1010 delete_string (tos);
1011 *tos = out;
1015 static void
1016 indent ()
1018 string_type out;
1019 int tab = 0;
1020 int idx = 0;
1021 int ol = 0;
1022 init_string (&out);
1023 while (at (tos, idx))
1025 switch (at (tos, idx))
1027 case '\n':
1028 cattext (&out, "\n");
1029 idx++;
1030 if (tab && at (tos, idx))
1032 cattext (&out, " ");
1034 ol = 0;
1035 break;
1036 case '(':
1037 tab++;
1038 if (ol == 0)
1039 cattext (&out, " ");
1040 idx++;
1041 cattext (&out, "(");
1042 ol = 1;
1043 break;
1044 case ')':
1045 tab--;
1046 cattext (&out, ")");
1047 idx++;
1048 ol = 1;
1050 break;
1051 default:
1052 catchar (&out, at (tos, idx));
1053 ol = 1;
1055 idx++;
1056 break;
1060 pc++;
1061 delete_string (tos);
1062 *tos = out;
1066 static void
1067 get_stuff_in_command ()
1069 tos++;
1070 check_range ();
1071 init_string (tos);
1073 while (at (ptr, idx))
1075 if (iscommand (ptr, idx))
1076 break;
1077 idx = copy_past_newline (ptr, idx, tos);
1079 pc++;
1082 static void
1083 swap ()
1085 string_type t;
1087 t = tos[0];
1088 tos[0] = tos[-1];
1089 tos[-1] = t;
1090 pc++;
1093 static void
1094 other_dup ()
1096 tos++;
1097 check_range ();
1098 init_string (tos);
1099 catstr (tos, tos - 1);
1100 pc++;
1103 static void
1104 drop ()
1106 tos--;
1107 check_range ();
1108 pc++;
1111 static void
1112 idrop ()
1114 isp--;
1115 icheck_range ();
1116 pc++;
1119 static void
1120 icatstr ()
1122 tos--;
1123 check_range ();
1124 catstr (tos, tos + 1);
1125 delete_string (tos + 1);
1126 pc++;
1129 static void
1130 skip_past_newline ()
1132 while (at (ptr, idx)
1133 && at (ptr, idx) != '\n')
1134 idx++;
1135 idx++;
1136 pc++;
1139 static void
1140 internalmode ()
1142 internal_mode = *(isp);
1143 isp--;
1144 icheck_range ();
1145 pc++;
1148 static void
1149 maybecatstr ()
1151 if (internal_wanted == internal_mode)
1153 catstr (tos - 1, tos);
1155 delete_string (tos);
1156 tos--;
1157 check_range ();
1158 pc++;
1161 char *
1162 nextword (string, word)
1163 char *string;
1164 char **word;
1166 char *word_start;
1167 int idx;
1168 char *dst;
1169 char *src;
1171 int length = 0;
1173 while (isspace ((unsigned char) *string) || *string == '-')
1175 if (*string == '-')
1177 while (*string && *string != '\n')
1178 string++;
1181 else
1183 string++;
1186 if (!*string)
1187 return 0;
1189 word_start = string;
1190 if (*string == '"')
1194 string++;
1195 length++;
1196 if (*string == '\\')
1198 string += 2;
1199 length += 2;
1202 while (*string != '"');
1204 else
1206 while (!isspace ((unsigned char) *string))
1208 string++;
1209 length++;
1214 *word = malloc (length + 1);
1216 dst = *word;
1217 src = word_start;
1219 for (idx = 0; idx < length; idx++)
1221 if (src[idx] == '\\')
1222 switch (src[idx + 1])
1224 case 'n':
1225 *dst++ = '\n';
1226 idx++;
1227 break;
1228 case '"':
1229 case '\\':
1230 *dst++ = src[idx + 1];
1231 idx++;
1232 break;
1233 default:
1234 *dst++ = '\\';
1235 break;
1237 else
1238 *dst++ = src[idx];
1240 *dst++ = 0;
1242 if (*string)
1243 return string + 1;
1244 else
1245 return 0;
1248 dict_type *root;
1250 dict_type *
1251 lookup_word (word)
1252 char *word;
1254 dict_type *ptr = root;
1255 while (ptr)
1257 if (strcmp (ptr->word, word) == 0)
1258 return ptr;
1259 ptr = ptr->next;
1261 if (warning)
1262 fprintf (stderr, "Can't find %s\n", word);
1263 return 0;
1266 static void
1267 perform ()
1269 tos = stack;
1271 while (at (ptr, idx))
1273 /* It's worth looking through the command list. */
1274 if (iscommand (ptr, idx))
1276 char *next;
1277 dict_type *word;
1279 (void) nextword (addr (ptr, idx), &next);
1281 word = lookup_word (next);
1283 if (word)
1285 exec (word);
1287 else
1289 if (warning)
1290 fprintf (stderr, "warning, %s is not recognised\n", next);
1291 skip_past_newline ();
1295 else
1296 skip_past_newline ();
1300 dict_type *
1301 newentry (word)
1302 char *word;
1304 dict_type *new = (dict_type *) malloc (sizeof (dict_type));
1305 new->word = word;
1306 new->next = root;
1307 root = new;
1308 new->code = (stinst_type *) malloc (sizeof (stinst_type));
1309 new->code_length = 1;
1310 new->code_end = 0;
1311 return new;
1314 unsigned int
1315 add_to_definition (entry, word)
1316 dict_type *entry;
1317 stinst_type word;
1319 if (entry->code_end == entry->code_length)
1321 entry->code_length += 2;
1322 entry->code =
1323 (stinst_type *) realloc ((char *) (entry->code),
1324 entry->code_length * sizeof (word_type));
1326 entry->code[entry->code_end] = word;
1328 return entry->code_end++;
1331 void
1332 add_intrinsic (name, func)
1333 char *name;
1334 void (*func) ();
1336 dict_type *new = newentry (name);
1337 add_to_definition (new, func);
1338 add_to_definition (new, 0);
1341 void
1342 add_var (name)
1343 char *name;
1345 dict_type *new = newentry (name);
1346 add_to_definition (new, push_number);
1347 add_to_definition (new, (stinst_type) (&(new->var)));
1348 add_to_definition (new, 0);
1351 void
1352 compile (string)
1353 char *string;
1355 /* Add words to the dictionary. */
1356 char *word;
1357 string = nextword (string, &word);
1358 while (string && *string && word[0])
1360 if (strcmp (word, "var") == 0)
1362 string = nextword (string, &word);
1364 add_var (word);
1365 string = nextword (string, &word);
1367 else if (word[0] == ':')
1369 dict_type *ptr;
1370 /* Compile a word and add to dictionary. */
1371 string = nextword (string, &word);
1373 ptr = newentry (word);
1374 string = nextword (string, &word);
1375 while (word[0] != ';')
1377 switch (word[0])
1379 case '"':
1380 /* got a string, embed magic push string
1381 function */
1382 add_to_definition (ptr, push_text);
1383 add_to_definition (ptr, (stinst_type) (word + 1));
1384 break;
1385 case '0':
1386 case '1':
1387 case '2':
1388 case '3':
1389 case '4':
1390 case '5':
1391 case '6':
1392 case '7':
1393 case '8':
1394 case '9':
1395 /* Got a number, embedd the magic push number
1396 function */
1397 add_to_definition (ptr, push_number);
1398 add_to_definition (ptr, (stinst_type) atol (word));
1399 break;
1400 default:
1401 add_to_definition (ptr, call);
1402 add_to_definition (ptr, (stinst_type) lookup_word (word));
1405 string = nextword (string, &word);
1407 add_to_definition (ptr, 0);
1408 string = nextword (string, &word);
1410 else
1412 fprintf (stderr, "syntax error at %s\n", string - 1);
1417 static void
1418 bang ()
1420 *(long *) ((isp[0])) = isp[-1];
1421 isp -= 2;
1422 icheck_range ();
1423 pc++;
1426 static void
1427 atsign ()
1429 isp[0] = *(long *) (isp[0]);
1430 pc++;
1433 static void
1434 hello ()
1436 printf ("hello\n");
1437 pc++;
1440 static void
1441 stdout_ ()
1443 isp++;
1444 icheck_range ();
1445 *isp = 1;
1446 pc++;
1449 static void
1450 stderr_ ()
1452 isp++;
1453 icheck_range ();
1454 *isp = 2;
1455 pc++;
1458 static void
1459 print ()
1461 if (*isp == 1)
1462 write_buffer (tos, stdout);
1463 else if (*isp == 2)
1464 write_buffer (tos, stderr);
1465 else
1466 fprintf (stderr, "print: illegal print destination `%ld'\n", *isp);
1467 isp--;
1468 tos--;
1469 icheck_range ();
1470 check_range ();
1471 pc++;
1474 static void
1475 read_in (str, file)
1476 string_type *str;
1477 FILE *file;
1479 char buff[10000];
1480 unsigned int r;
1483 r = fread (buff, 1, sizeof (buff), file);
1484 catbuf (str, buff, r);
1486 while (r);
1487 buff[0] = 0;
1489 catbuf (str, buff, 1);
1492 static void
1493 usage ()
1495 fprintf (stderr, "usage: -[d|i|g] <file >file\n");
1496 exit (33);
1499 /* There is no reliable way to declare exit. Sometimes it returns
1500 int, and sometimes it returns void. Sometimes it changes between
1501 OS releases. Trying to get it declared correctly in the hosts file
1502 is a pointless waste of time. */
1504 static void
1505 chew_exit ()
1507 exit (0);
1511 main (ac, av)
1512 int ac;
1513 char *av[];
1515 unsigned int i;
1516 string_type buffer;
1517 string_type pptr;
1519 init_string (&buffer);
1520 init_string (&pptr);
1521 init_string (stack + 0);
1522 tos = stack + 1;
1523 ptr = &pptr;
1525 add_intrinsic ("push_text", push_text);
1526 add_intrinsic ("!", bang);
1527 add_intrinsic ("@", atsign);
1528 add_intrinsic ("hello", hello);
1529 add_intrinsic ("stdout", stdout_);
1530 add_intrinsic ("stderr", stderr_);
1531 add_intrinsic ("print", print);
1532 add_intrinsic ("skip_past_newline", skip_past_newline);
1533 add_intrinsic ("catstr", icatstr);
1534 add_intrinsic ("copy_past_newline", icopy_past_newline);
1535 add_intrinsic ("dup", other_dup);
1536 add_intrinsic ("drop", drop);
1537 add_intrinsic ("idrop", idrop);
1538 add_intrinsic ("remchar", remchar);
1539 add_intrinsic ("get_stuff_in_command", get_stuff_in_command);
1540 add_intrinsic ("do_fancy_stuff", do_fancy_stuff);
1541 add_intrinsic ("bulletize", bulletize);
1542 add_intrinsic ("courierize", courierize);
1543 /* If the following line gives an error, exit() is not declared in the
1544 ../hosts/foo.h file for this host. Fix it there, not here! */
1545 /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1546 add_intrinsic ("exit", chew_exit);
1547 add_intrinsic ("swap", swap);
1548 add_intrinsic ("outputdots", outputdots);
1549 add_intrinsic ("paramstuff", paramstuff);
1550 add_intrinsic ("maybecatstr", maybecatstr);
1551 add_intrinsic ("translatecomments", translatecomments);
1552 add_intrinsic ("kill_bogus_lines", kill_bogus_lines);
1553 add_intrinsic ("indent", indent);
1554 add_intrinsic ("internalmode", internalmode);
1555 add_intrinsic ("print_stack_level", print_stack_level);
1556 add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines);
1558 /* Put a nl at the start. */
1559 catchar (&buffer, '\n');
1561 read_in (&buffer, stdin);
1562 remove_noncomments (&buffer, ptr);
1563 for (i = 1; i < (unsigned int) ac; i++)
1565 if (av[i][0] == '-')
1567 if (av[i][1] == 'f')
1569 string_type b;
1570 FILE *f;
1571 init_string (&b);
1573 f = fopen (av[i + 1], "r");
1574 if (!f)
1576 fprintf (stderr, "Can't open the input file %s\n",
1577 av[i + 1]);
1578 return 33;
1581 read_in (&b, f);
1582 compile (b.ptr);
1583 perform ();
1585 else if (av[i][1] == 'i')
1587 internal_wanted = 1;
1589 else if (av[i][1] == 'w')
1591 warning = 1;
1593 else
1594 usage ();
1597 write_buffer (stack + 0, stdout);
1598 if (tos != stack)
1600 fprintf (stderr, "finishing with current stack level %d\n",
1601 tos - stack);
1602 return 1;
1604 return 0;