Fix memory leak in RiscV assembler.
[binutils-gdb.git] / bfd / doc / chew.c
blobc0bd24c6bb8d677f2f5061c3e7a6990ffcc84b33
1 /* chew
2 Copyright (C) 1990-2023 Free Software Foundation, Inc.
3 Contributed by steve chamberlain @cygnus
5 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
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> ;
34 Variables are defined using:
35 variable NAME
39 /* Primitives provided by the program:
41 Two stacks are provided, a string stack and an integer stack.
43 Internal state variables:
44 internal_wanted - indicates whether `-i' was passed
45 internal_mode - user-settable
47 Commands:
48 push_text
49 ! - pop top of integer stack for address, pop next for value; store
50 @ - treat value on integer stack as the address of an integer; push
51 that integer on the integer stack after popping the "address"
52 hello - print "hello\n" to stdout
53 stdout - put stdout marker on TOS
54 stderr - put stderr marker on TOS
55 print - print TOS-1 on TOS (eg: "hello\n" stdout print)
56 skip_past_newline
57 catstr - fn icatstr
58 copy_past_newline - append input, up to and including newline into TOS
59 dup - fn other_dup
60 drop - discard TOS
61 idrop - ditto
62 remchar - delete last character from TOS
63 get_stuff_in_command
64 do_fancy_stuff - translate <<foo>> to @code{foo} in TOS
65 bulletize - if "o" lines found, prepend @itemize @bullet to TOS
66 and @item to each "o" line; append @end itemize
67 courierize - put @example around . and | lines, translate {* *} { }
68 exit - fn chew_exit
69 swap
70 outputdots - strip out lines without leading dots
71 maybecatstr - do catstr if internal_mode == internal_wanted, discard
72 value in any case
73 catstrif - do catstr if top of integer stack is nonzero
74 translatecomments - turn {* and *} into comment delimiters
75 kill_bogus_lines - get rid of extra newlines
76 indent
77 print_stack_level - print current stack depth to stderr
78 strip_trailing_newlines - go ahead, guess...
79 [quoted string] - push string onto string stack
80 [word starting with digit] - push atol(str) onto integer stack
82 internalmode - the internalmode variable (evaluates to address)
84 A command must be all upper-case, and alone on a line.
86 Foo. */
88 #include <assert.h>
89 #include <stdio.h>
90 #include <ctype.h>
91 #include <stdlib.h>
92 #include <string.h>
93 #include <stdint.h>
94 #include <inttypes.h>
96 #define DEF_SIZE 5000
97 #define STACK 50
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 /* Compiled programs consist of arrays of these. */
110 typedef union
112 void (*f) (void);
113 struct dict_struct *e;
114 char *s;
115 intptr_t l;
116 } pcu;
118 typedef struct dict_struct
120 char *word;
121 struct dict_struct *next;
122 pcu *code;
123 int code_length;
124 int code_end;
125 } dict_type;
127 int internal_wanted;
128 intptr_t *internal_mode;
130 int warning;
132 string_type stack[STACK];
133 string_type *tos;
135 unsigned int idx = 0; /* Pos in input buffer */
136 string_type *ptr; /* and the buffer */
138 intptr_t istack[STACK];
139 intptr_t *isp = &istack[0];
141 dict_type *root;
143 pcu *pc;
145 static void
146 die (char *msg)
148 fprintf (stderr, "%s\n", msg);
149 exit (1);
152 void *
153 xmalloc (size_t size)
155 void *newmem;
157 if (size == 0)
158 size = 1;
159 newmem = malloc (size);
160 if (!newmem)
161 die ("out of memory");
163 return newmem;
166 void *
167 xrealloc (void *oldmem, size_t size)
169 void *newmem;
171 if (size == 0)
172 size = 1;
173 if (!oldmem)
174 newmem = malloc (size);
175 else
176 newmem = realloc (oldmem, size);
177 if (!newmem)
178 die ("out of memory");
180 return newmem;
183 char *
184 xstrdup (const char *s)
186 size_t len = strlen (s) + 1;
187 char *ret = xmalloc (len);
188 return memcpy (ret, s, len);
191 static void
192 init_string_with_size (string_type *buffer, unsigned int size)
194 buffer->write_idx = 0;
195 buffer->size = size;
196 buffer->ptr = xmalloc (size);
199 static void
200 init_string (string_type *buffer)
202 init_string_with_size (buffer, DEF_SIZE);
205 static int
206 find (string_type *str, char *what)
208 unsigned int i;
209 char *p;
210 p = what;
211 for (i = 0; i < str->write_idx && *p; i++)
213 if (*p == str->ptr[i])
214 p++;
215 else
216 p = what;
218 return (*p == 0);
221 static void
222 write_buffer (string_type *buffer, FILE *f)
224 if (buffer->write_idx != 0
225 && fwrite (buffer->ptr, buffer->write_idx, 1, f) != 1)
226 die ("cannot write output");
229 static void
230 delete_string (string_type *buffer)
232 free (buffer->ptr);
233 buffer->ptr = NULL;
236 static char *
237 addr (string_type *buffer, unsigned int idx)
239 return buffer->ptr + idx;
242 static char
243 at (string_type *buffer, unsigned int pos)
245 if (pos >= buffer->write_idx)
246 return 0;
247 return buffer->ptr[pos];
250 static void
251 catchar (string_type *buffer, int ch)
253 if (buffer->write_idx == buffer->size)
255 buffer->size *= 2;
256 buffer->ptr = xrealloc (buffer->ptr, buffer->size);
259 buffer->ptr[buffer->write_idx++] = ch;
262 static void
263 overwrite_string (string_type *dst, string_type *src)
265 free (dst->ptr);
266 dst->size = src->size;
267 dst->write_idx = src->write_idx;
268 dst->ptr = src->ptr;
271 static void
272 catbuf (string_type *buffer, char *buf, unsigned int len)
274 if (buffer->write_idx + len >= buffer->size)
276 while (buffer->write_idx + len >= buffer->size)
277 buffer->size *= 2;
278 buffer->ptr = xrealloc (buffer->ptr, buffer->size);
280 memcpy (buffer->ptr + buffer->write_idx, buf, len);
281 buffer->write_idx += len;
284 static void
285 cattext (string_type *buffer, char *string)
287 catbuf (buffer, string, (unsigned int) strlen (string));
290 static void
291 catstr (string_type *dst, string_type *src)
293 catbuf (dst, src->ptr, src->write_idx);
296 static unsigned int
297 skip_white_and_stars (string_type *src, unsigned int idx)
299 char c;
300 while ((c = at (src, idx)),
301 isspace ((unsigned char) c)
302 || (c == '*'
303 /* Don't skip past end-of-comment or star as first
304 character on its line. */
305 && at (src, idx +1) != '/'
306 && at (src, idx -1) != '\n'))
307 idx++;
308 return idx;
311 static unsigned int
312 skip_past_newline_1 (string_type *ptr, unsigned int idx)
314 while (at (ptr, idx)
315 && at (ptr, idx) != '\n')
316 idx++;
317 if (at (ptr, idx) == '\n')
318 return idx + 1;
319 return idx;
322 static void
323 check_range (void)
325 if (tos < stack)
326 die ("underflow in string stack");
327 if (tos >= stack + STACK)
328 die ("overflow in string stack");
331 static void
332 icheck_range (void)
334 if (isp < istack)
335 die ("underflow in integer stack");
336 if (isp >= istack + STACK)
337 die ("overflow in integer stack");
340 static void
341 exec (dict_type *word)
343 pc = word->code;
344 while (pc->f)
345 pc->f ();
348 static void
349 call (void)
351 pcu *oldpc = pc;
352 dict_type *e = pc[1].e;
353 exec (e);
354 pc = oldpc + 2;
357 static void
358 remchar (void)
360 if (tos->write_idx)
361 tos->write_idx--;
362 pc++;
365 static void
366 strip_trailing_newlines (void)
368 while ((isspace ((unsigned char) at (tos, tos->write_idx - 1))
369 || at (tos, tos->write_idx - 1) == '\n')
370 && tos->write_idx > 0)
371 tos->write_idx--;
372 pc++;
375 static void
376 push_number (void)
378 isp++;
379 icheck_range ();
380 pc++;
381 *isp = pc->l;
382 pc++;
385 /* This is a wrapper for push_number just so we can correctly free the
386 variable at the end. */
387 static void
388 push_variable (void)
390 push_number ();
393 static void
394 push_text (void)
396 tos++;
397 check_range ();
398 init_string (tos);
399 pc++;
400 cattext (tos, pc->s);
401 pc++;
404 /* This function removes everything not inside comments starting on
405 the first char of the line from the string, also when copying
406 comments, removes blank space and leading *'s.
407 Blank lines are turned into one blank line. */
409 static void
410 remove_noncomments (string_type *src, string_type *dst)
412 unsigned int idx = 0;
414 while (at (src, idx))
416 /* Now see if we have a comment at the start of the line. */
417 if (at (src, idx) == '\n'
418 && at (src, idx + 1) == '/'
419 && at (src, idx + 2) == '*')
421 idx += 3;
423 idx = skip_white_and_stars (src, idx);
425 /* Remove leading dot */
426 if (at (src, idx) == '.')
427 idx++;
429 /* Copy to the end of the line, or till the end of the
430 comment. */
431 while (at (src, idx))
433 if (at (src, idx) == '\n')
435 /* end of line, echo and scrape of leading blanks */
436 if (at (src, idx + 1) == '\n')
437 catchar (dst, '\n');
438 catchar (dst, '\n');
439 idx++;
440 idx = skip_white_and_stars (src, idx);
442 else if (at (src, idx) == '*' && at (src, idx + 1) == '/')
444 idx += 2;
445 cattext (dst, "\nENDDD\n");
446 break;
448 else
450 catchar (dst, at (src, idx));
451 idx++;
455 else
456 idx++;
460 static void
461 print_stack_level (void)
463 fprintf (stderr, "current string stack depth = %ld, ",
464 (long) (tos - stack));
465 fprintf (stderr, "current integer stack depth = %ld\n",
466 (long) (isp - istack));
467 pc++;
470 /* turn {*
471 and *} into comments */
473 static void
474 translatecomments (void)
476 unsigned int idx = 0;
477 string_type out;
478 init_string (&out);
480 while (at (tos, idx))
482 if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
484 cattext (&out, "/*");
485 idx += 2;
487 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
489 cattext (&out, "*/");
490 idx += 2;
492 else
494 catchar (&out, at (tos, idx));
495 idx++;
499 overwrite_string (tos, &out);
501 pc++;
504 /* Mod tos so that only lines with leading dots remain */
505 static void
506 outputdots (void)
508 unsigned int idx = 0;
509 string_type out;
510 init_string (&out);
512 while (at (tos, idx))
514 /* Every iteration begins at the start of a line. */
515 if (at (tos, idx) == '.')
517 char c;
518 int spaces;
520 idx++;
521 spaces = 0;
522 while ((c = at (tos, idx)) && c != '\n')
524 if (spaces >= 0)
526 if (c == ' ')
528 spaces++;
529 idx++;
530 continue;
532 else
534 while (spaces >= 8)
536 catchar (&out, '\t');
537 spaces -= 8;
539 while (spaces-- > 0)
540 catchar (&out, ' ');
543 if (c == '{' && at (tos, idx + 1) == '*')
545 cattext (&out, "/*");
546 idx += 2;
548 else if (c == '*' && at (tos, idx + 1) == '}')
550 cattext (&out, "*/");
551 idx += 2;
553 else
555 catchar (&out, c);
556 idx++;
559 if (c == '\n')
560 idx++;
561 catchar (&out, '\n');
563 else
565 idx = skip_past_newline_1 (tos, idx);
569 overwrite_string (tos, &out);
570 pc++;
573 /* Find lines starting with . and | and put example around them on tos */
574 static void
575 courierize (void)
577 string_type out;
578 unsigned int idx = 0;
579 int command = 0;
581 init_string (&out);
583 while (at (tos, idx))
585 if (at (tos, idx) == '\n'
586 && (at (tos, idx +1 ) == '.'
587 || at (tos, idx + 1) == '|'))
589 cattext (&out, "\n@example\n");
592 idx += 2;
594 while (at (tos, idx) && at (tos, idx) != '\n')
596 if (command > 1)
598 /* We are inside {} parameters of some command;
599 Just pass through until matching brace. */
600 if (at (tos, idx) == '{')
601 ++command;
602 else if (at (tos, idx) == '}')
603 --command;
605 else if (command != 0)
607 if (at (tos, idx) == '{')
608 ++command;
609 else if (!islower ((unsigned char) at (tos, idx)))
610 --command;
612 else if (at (tos, idx) == '@'
613 && islower ((unsigned char) at (tos, idx + 1)))
615 ++command;
617 else if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
619 cattext (&out, "/*");
620 idx += 2;
621 continue;
623 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
625 cattext (&out, "*/");
626 idx += 2;
627 continue;
629 else if (at (tos, idx) == '{'
630 || at (tos, idx) == '}')
632 catchar (&out, '@');
635 catchar (&out, at (tos, idx));
636 idx++;
638 catchar (&out, '\n');
640 while (at (tos, idx) == '\n'
641 && ((at (tos, idx + 1) == '.')
642 || (at (tos, idx + 1) == '|')))
644 cattext (&out, "@end example");
646 else
648 catchar (&out, at (tos, idx));
649 idx++;
653 overwrite_string (tos, &out);
654 pc++;
657 /* Finds any lines starting with "o ", if there are any, then turns
658 on @itemize @bullet, and @items each of them. Then ends with @end
659 itemize, inplace at TOS*/
661 static void
662 bulletize (void)
664 unsigned int idx = 0;
665 int on = 0;
666 string_type out;
667 init_string (&out);
669 while (at (tos, idx))
671 if (at (tos, idx) == '@'
672 && at (tos, idx + 1) == '*')
674 cattext (&out, "*");
675 idx += 2;
677 else if (at (tos, idx) == '\n'
678 && at (tos, idx + 1) == 'o'
679 && isspace ((unsigned char) at (tos, idx + 2)))
681 if (!on)
683 cattext (&out, "\n@itemize @bullet\n");
684 on = 1;
687 cattext (&out, "\n@item\n");
688 idx += 3;
690 else
692 catchar (&out, at (tos, idx));
693 if (on && at (tos, idx) == '\n'
694 && at (tos, idx + 1) == '\n'
695 && at (tos, idx + 2) != 'o')
697 cattext (&out, "@end itemize");
698 on = 0;
700 idx++;
704 if (on)
706 cattext (&out, "@end itemize\n");
709 delete_string (tos);
710 *tos = out;
711 pc++;
714 /* Turn <<foo>> into @code{foo} in place at TOS*/
716 static void
717 do_fancy_stuff (void)
719 unsigned int idx = 0;
720 string_type out;
721 init_string (&out);
722 while (at (tos, idx))
724 if (at (tos, idx) == '<'
725 && at (tos, idx + 1) == '<'
726 && !isspace ((unsigned char) at (tos, idx + 2)))
728 /* This qualifies as a << startup. */
729 idx += 2;
730 cattext (&out, "@code{");
731 while (at (tos, idx)
732 && at (tos, idx) != '>' )
734 catchar (&out, at (tos, idx));
735 idx++;
738 cattext (&out, "}");
739 idx += 2;
741 else
743 catchar (&out, at (tos, idx));
744 idx++;
747 delete_string (tos);
748 *tos = out;
749 pc++;
753 /* A command is all upper case,and alone on a line. */
755 static int
756 iscommand (string_type *ptr, unsigned int idx)
758 unsigned int len = 0;
759 while (at (ptr, idx))
761 if (isupper ((unsigned char) at (ptr, idx))
762 || at (ptr, idx) == ' ' || at (ptr, idx) == '_')
764 len++;
765 idx++;
767 else if (at (ptr, idx) == '\n')
769 if (len > 3)
770 return 1;
771 return 0;
773 else
774 return 0;
776 return 0;
779 static int
780 copy_past_newline (string_type *ptr, unsigned int idx, string_type *dst)
782 int column = 0;
784 while (at (ptr, idx) && at (ptr, idx) != '\n')
786 if (at (ptr, idx) == '\t')
788 /* Expand tabs. Neither makeinfo nor TeX can cope well with
789 them. */
791 catchar (dst, ' ');
792 while (++column & 7);
794 else
796 catchar (dst, at (ptr, idx));
797 column++;
799 idx++;
802 catchar (dst, at (ptr, idx));
803 idx++;
804 return idx;
808 static void
809 icopy_past_newline (void)
811 tos++;
812 check_range ();
813 init_string (tos);
814 idx = copy_past_newline (ptr, idx, tos);
815 pc++;
818 static void
819 kill_bogus_lines (void)
821 int sl;
823 int idx = 0;
824 int c;
825 int dot = 0;
827 string_type out;
828 init_string (&out);
829 /* Drop leading nl. */
830 while (at (tos, idx) == '\n')
832 idx++;
834 c = idx;
836 /* If the first char is a '.' prepend a newline so that it is
837 recognized properly later. */
838 if (at (tos, idx) == '.')
839 catchar (&out, '\n');
841 /* Find the last char. */
842 while (at (tos, idx))
844 idx++;
847 /* Find the last non white before the nl. */
848 idx--;
850 while (idx && isspace ((unsigned char) at (tos, idx)))
851 idx--;
852 idx++;
854 /* Copy buffer upto last char, but blank lines before and after
855 dots don't count. */
856 sl = 1;
858 while (c < idx)
860 if (at (tos, c) == '\n'
861 && at (tos, c + 1) == '\n'
862 && at (tos, c + 2) == '.')
864 /* Ignore two newlines before a dot. */
865 c++;
867 else if (at (tos, c) == '.' && sl)
869 /* remember that this line started with a dot. */
870 dot = 2;
872 else if (at (tos, c) == '\n'
873 && at (tos, c + 1) == '\n'
874 && dot)
876 c++;
877 /* Ignore two newlines when last line was dot. */
880 catchar (&out, at (tos, c));
881 if (at (tos, c) == '\n')
883 sl = 1;
885 if (dot == 2)
886 dot = 1;
887 else
888 dot = 0;
890 else
891 sl = 0;
893 c++;
897 /* Append nl. */
898 catchar (&out, '\n');
899 pc++;
900 delete_string (tos);
901 *tos = out;
905 static void
906 collapse_whitespace (void)
908 int last_was_ws = 0;
909 int idx;
911 string_type out;
912 init_string (&out);
914 for (idx = 0; at (tos, idx) != 0; ++idx)
916 char c = at (tos, idx);
917 if (isspace (c))
919 if (!last_was_ws)
921 catchar (&out, ' ');
922 last_was_ws = 1;
925 else
927 catchar (&out, c);
928 last_was_ws = 0;
932 pc++;
933 delete_string (tos);
934 *tos = out;
937 /* indent
938 Take the string at the top of the stack, do some prettying. */
940 static void
941 indent (void)
943 string_type out;
944 int tab = 0;
945 int idx = 0;
946 int ol = 0;
947 init_string (&out);
948 while (at (tos, idx))
950 switch (at (tos, idx))
952 case '\n':
953 catchar (&out, '\n');
954 idx++;
955 if (tab && at (tos, idx))
957 int i;
958 for (i = 0; i < tab - 1; i += 2)
959 catchar (&out, '\t');
960 if (i < tab)
961 cattext (&out, " ");
963 ol = 0;
964 break;
965 case '(':
966 if (ol == 0)
968 int i;
969 for (i = 1; i < tab - 1; i += 2)
970 catchar (&out, '\t');
971 if (i < tab)
972 cattext (&out, " ");
973 cattext (&out, " ");
975 tab++;
976 idx++;
977 catchar (&out, '(');
978 ol = 1;
979 break;
980 case ')':
981 tab--;
982 catchar (&out, ')');
983 idx++;
984 ol = 1;
985 break;
986 default:
987 catchar (&out, at (tos, idx));
988 ol = 1;
989 idx++;
990 break;
994 pc++;
995 delete_string (tos);
996 *tos = out;
1000 static void
1001 get_stuff_in_command (void)
1003 tos++;
1004 check_range ();
1005 init_string (tos);
1007 while (at (ptr, idx))
1009 if (iscommand (ptr, idx))
1010 break;
1011 idx = copy_past_newline (ptr, idx, tos);
1013 pc++;
1016 static void
1017 swap (void)
1019 string_type t;
1021 t = tos[0];
1022 tos[0] = tos[-1];
1023 tos[-1] = t;
1024 pc++;
1027 static void
1028 other_dup (void)
1030 tos++;
1031 check_range ();
1032 init_string (tos);
1033 catstr (tos, tos - 1);
1034 pc++;
1037 static void
1038 drop (void)
1040 tos--;
1041 check_range ();
1042 delete_string (tos + 1);
1043 pc++;
1046 static void
1047 idrop (void)
1049 isp--;
1050 icheck_range ();
1051 pc++;
1054 static void
1055 icatstr (void)
1057 tos--;
1058 check_range ();
1059 catstr (tos, tos + 1);
1060 delete_string (tos + 1);
1061 pc++;
1064 static void
1065 skip_past_newline (void)
1067 idx = skip_past_newline_1 (ptr, idx);
1068 pc++;
1071 static void
1072 maybecatstr (void)
1074 if (internal_wanted == *internal_mode)
1076 catstr (tos - 1, tos);
1078 delete_string (tos);
1079 tos--;
1080 check_range ();
1081 pc++;
1084 static void
1085 catstrif (void)
1087 int cond = isp[0];
1088 isp--;
1089 icheck_range ();
1090 if (cond)
1091 catstr (tos - 1, tos);
1092 delete_string (tos);
1093 tos--;
1094 check_range ();
1095 pc++;
1098 char *
1099 nextword (char *string, char **word)
1101 char *word_start;
1102 int idx;
1103 char *dst;
1104 char *src;
1106 int length = 0;
1108 while (isspace ((unsigned char) *string) || *string == '-')
1110 if (*string == '-')
1112 while (*string && *string != '\n')
1113 string++;
1116 else
1118 string++;
1121 if (!*string)
1123 *word = NULL;
1124 return NULL;
1127 word_start = string;
1128 if (*string == '"')
1132 string++;
1133 length++;
1134 if (*string == '\\')
1136 string += 2;
1137 length += 2;
1140 while (*string != '"');
1142 else
1144 while (!isspace ((unsigned char) *string))
1146 string++;
1147 length++;
1152 *word = xmalloc (length + 1);
1154 dst = *word;
1155 src = word_start;
1157 for (idx = 0; idx < length; idx++)
1159 if (src[idx] == '\\')
1160 switch (src[idx + 1])
1162 case 'n':
1163 *dst++ = '\n';
1164 idx++;
1165 break;
1166 case '"':
1167 case '\\':
1168 *dst++ = src[idx + 1];
1169 idx++;
1170 break;
1171 default:
1172 *dst++ = '\\';
1173 break;
1175 else
1176 *dst++ = src[idx];
1178 *dst++ = 0;
1180 if (*string)
1181 return string + 1;
1182 else
1183 return NULL;
1186 dict_type *
1187 lookup_word (char *word)
1189 dict_type *ptr = root;
1190 while (ptr)
1192 if (strcmp (ptr->word, word) == 0)
1193 return ptr;
1194 ptr = ptr->next;
1196 if (warning)
1197 fprintf (stderr, "Can't find %s\n", word);
1198 return NULL;
1201 static void
1202 free_words (void)
1204 dict_type *ptr = root;
1206 while (ptr)
1208 dict_type *next;
1210 free (ptr->word);
1211 if (ptr->code)
1213 int i;
1214 for (i = 0; i < ptr->code_end - 1; i ++)
1215 if (ptr->code[i].f == push_text
1216 && ptr->code[i + 1].s)
1218 free (ptr->code[i + 1].s - 1);
1219 ++i;
1221 else if (ptr->code[i].f == push_variable)
1223 free ((void *) ptr->code[i + 1].l);
1224 ++i;
1226 free (ptr->code);
1228 next = ptr->next;
1229 free (ptr);
1230 ptr = next;
1234 static void
1235 perform (void)
1237 tos = stack;
1239 while (at (ptr, idx))
1241 /* It's worth looking through the command list. */
1242 if (iscommand (ptr, idx))
1244 char *next;
1245 dict_type *word;
1247 (void) nextword (addr (ptr, idx), &next);
1249 word = lookup_word (next);
1251 if (word)
1253 exec (word);
1255 else
1257 if (warning)
1258 fprintf (stderr, "warning, %s is not recognised\n", next);
1259 idx = skip_past_newline_1 (ptr, idx);
1261 free (next);
1263 else
1264 idx = skip_past_newline_1 (ptr, idx);
1268 dict_type *
1269 newentry (char *word)
1271 dict_type *new_d = xmalloc (sizeof (*new_d));
1272 new_d->word = word;
1273 new_d->next = root;
1274 root = new_d;
1275 new_d->code = xmalloc (sizeof (*new_d->code));
1276 new_d->code_length = 1;
1277 new_d->code_end = 0;
1278 return new_d;
1281 unsigned int
1282 add_to_definition (dict_type *entry, pcu word)
1284 if (entry->code_end == entry->code_length)
1286 entry->code_length += 2;
1287 entry->code = xrealloc (entry->code,
1288 entry->code_length * sizeof (*entry->code));
1290 entry->code[entry->code_end] = word;
1292 return entry->code_end++;
1295 void
1296 add_intrinsic (char *name, void (*func) (void))
1298 dict_type *new_d = newentry (xstrdup (name));
1299 pcu p = { func };
1300 add_to_definition (new_d, p);
1301 p.f = 0;
1302 add_to_definition (new_d, p);
1305 static void
1306 add_variable (char *name, intptr_t *loc)
1308 dict_type *new_d = newentry (name);
1309 pcu p = { push_variable };
1310 add_to_definition (new_d, p);
1311 p.l = (intptr_t) loc;
1312 add_to_definition (new_d, p);
1313 p.f = 0;
1314 add_to_definition (new_d, p);
1317 static void
1318 add_intrinsic_variable (const char *name, intptr_t *loc)
1320 add_variable (xstrdup (name), loc);
1323 void
1324 compile (char *string)
1326 /* Add words to the dictionary. */
1327 char *word;
1329 string = nextword (string, &word);
1330 while (string && *string && word[0])
1332 if (word[0] == ':')
1334 dict_type *ptr;
1335 pcu p;
1337 /* Compile a word and add to dictionary. */
1338 free (word);
1339 string = nextword (string, &word);
1340 if (!string)
1341 continue;
1342 ptr = newentry (word);
1343 string = nextword (string, &word);
1344 if (!string)
1346 free (ptr->code);
1347 free (ptr);
1348 continue;
1351 while (word[0] != ';')
1353 switch (word[0])
1355 case '"':
1356 /* got a string, embed magic push string
1357 function */
1358 p.f = push_text;
1359 add_to_definition (ptr, p);
1360 p.s = word + 1;
1361 add_to_definition (ptr, p);
1362 break;
1363 case '0':
1364 case '1':
1365 case '2':
1366 case '3':
1367 case '4':
1368 case '5':
1369 case '6':
1370 case '7':
1371 case '8':
1372 case '9':
1373 /* Got a number, embedd the magic push number
1374 function */
1375 p.f = push_number;
1376 add_to_definition (ptr, p);
1377 p.l = atol (word);
1378 add_to_definition (ptr, p);
1379 free (word);
1380 break;
1381 default:
1382 p.f = call;
1383 add_to_definition (ptr, p);
1384 p.e = lookup_word (word);
1385 add_to_definition (ptr, p);
1386 free (word);
1389 string = nextword (string, &word);
1391 p.f = 0;
1392 add_to_definition (ptr, p);
1393 free (word);
1394 string = nextword (string, &word);
1396 else if (strcmp (word, "variable") == 0)
1398 free (word);
1399 string = nextword (string, &word);
1400 if (!string)
1401 continue;
1402 intptr_t *loc = xmalloc (sizeof (intptr_t));
1403 *loc = 0;
1404 add_variable (word, loc);
1405 string = nextword (string, &word);
1407 else
1409 fprintf (stderr, "syntax error at %s\n", string - 1);
1412 free (word);
1415 static void
1416 bang (void)
1418 *(intptr_t *) ((isp[0])) = isp[-1];
1419 isp -= 2;
1420 icheck_range ();
1421 pc++;
1424 static void
1425 atsign (void)
1427 isp[0] = *(intptr_t *) (isp[0]);
1428 pc++;
1431 static void
1432 hello (void)
1434 printf ("hello\n");
1435 pc++;
1438 static void
1439 stdout_ (void)
1441 isp++;
1442 icheck_range ();
1443 *isp = 1;
1444 pc++;
1447 static void
1448 stderr_ (void)
1450 isp++;
1451 icheck_range ();
1452 *isp = 2;
1453 pc++;
1456 static void
1457 print (void)
1459 if (*isp == 1)
1460 write_buffer (tos, stdout);
1461 else if (*isp == 2)
1462 write_buffer (tos, stderr);
1463 else
1464 fprintf (stderr, "print: illegal print destination `%" PRIdPTR "'\n", *isp);
1465 isp--;
1466 tos--;
1467 icheck_range ();
1468 check_range ();
1469 pc++;
1472 static void
1473 read_in (string_type *str, FILE *file)
1475 char buff[10000];
1476 unsigned int r;
1479 r = fread (buff, 1, sizeof (buff), file);
1480 catbuf (str, buff, r);
1482 while (r);
1483 buff[0] = 0;
1485 catbuf (str, buff, 1);
1488 static void
1489 usage (void)
1491 fprintf (stderr, "usage: -[d|i|g] <file >file\n");
1492 exit (33);
1495 /* There is no reliable way to declare exit. Sometimes it returns
1496 int, and sometimes it returns void. Sometimes it changes between
1497 OS releases. Trying to get it declared correctly in the hosts file
1498 is a pointless waste of time. */
1500 static void
1501 chew_exit (void)
1503 exit (0);
1507 main (int ac, char *av[])
1509 unsigned int i;
1510 string_type buffer;
1511 string_type pptr;
1513 init_string (&buffer);
1514 init_string (&pptr);
1515 init_string (stack + 0);
1516 tos = stack + 1;
1517 ptr = &pptr;
1519 add_intrinsic ("push_text", push_text);
1520 add_intrinsic ("!", bang);
1521 add_intrinsic ("@", atsign);
1522 add_intrinsic ("hello", hello);
1523 add_intrinsic ("stdout", stdout_);
1524 add_intrinsic ("stderr", stderr_);
1525 add_intrinsic ("print", print);
1526 add_intrinsic ("skip_past_newline", skip_past_newline);
1527 add_intrinsic ("catstr", icatstr);
1528 add_intrinsic ("copy_past_newline", icopy_past_newline);
1529 add_intrinsic ("dup", other_dup);
1530 add_intrinsic ("drop", drop);
1531 add_intrinsic ("idrop", idrop);
1532 add_intrinsic ("remchar", remchar);
1533 add_intrinsic ("get_stuff_in_command", get_stuff_in_command);
1534 add_intrinsic ("do_fancy_stuff", do_fancy_stuff);
1535 add_intrinsic ("bulletize", bulletize);
1536 add_intrinsic ("courierize", courierize);
1537 /* If the following line gives an error, exit() is not declared in the
1538 ../hosts/foo.h file for this host. Fix it there, not here! */
1539 /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1540 add_intrinsic ("exit", chew_exit);
1541 add_intrinsic ("swap", swap);
1542 add_intrinsic ("outputdots", outputdots);
1543 add_intrinsic ("maybecatstr", maybecatstr);
1544 add_intrinsic ("catstrif", catstrif);
1545 add_intrinsic ("translatecomments", translatecomments);
1546 add_intrinsic ("kill_bogus_lines", kill_bogus_lines);
1547 add_intrinsic ("indent", indent);
1548 add_intrinsic ("print_stack_level", print_stack_level);
1549 add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines);
1550 add_intrinsic ("collapse_whitespace", collapse_whitespace);
1552 internal_mode = xmalloc (sizeof (intptr_t));
1553 *internal_mode = 0;
1554 add_intrinsic_variable ("internalmode", internal_mode);
1556 /* Put a nl at the start. */
1557 catchar (&buffer, '\n');
1559 read_in (&buffer, stdin);
1560 remove_noncomments (&buffer, ptr);
1561 for (i = 1; i < (unsigned int) ac; i++)
1563 if (av[i][0] == '-')
1565 if (av[i][1] == 'f')
1567 string_type b;
1568 FILE *f;
1569 init_string (&b);
1571 f = fopen (av[i + 1], "r");
1572 if (!f)
1574 fprintf (stderr, "Can't open the input file %s\n",
1575 av[i + 1]);
1576 return 33;
1579 read_in (&b, f);
1580 compile (b.ptr);
1581 perform ();
1582 delete_string (&b);
1584 else if (av[i][1] == 'i')
1586 internal_wanted = 1;
1588 else if (av[i][1] == 'w')
1590 warning = 1;
1592 else
1593 usage ();
1596 write_buffer (stack + 0, stdout);
1597 free_words ();
1598 delete_string (&pptr);
1599 delete_string (&buffer);
1600 if (tos != stack)
1602 fprintf (stderr, "finishing with current stack level %ld\n",
1603 (long) (tos - stack));
1604 return 1;
1606 return 0;