2 Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 2000, 2001,
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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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
29 Basically, this is a sort of string forth, maybe we should call it
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
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)
56 copy_past_newline - append input, up to and including newline into TOS
60 remchar - delete last character from TOS
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 {* *} { }
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
72 translatecomments - turn {* and *} into comment delimiters
73 kill_bogus_lines - get rid of extra newlines
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.
100 /* Here is a string type ... */
102 typedef struct buffer
105 unsigned long write_idx
;
110 static void init_string_with_size (string_type
*, unsigned int);
111 static void init_string (string_type
*);
112 static int find (string_type
*, char *);
113 static void write_buffer (string_type
*, FILE *);
114 static void delete_string (string_type
*);
115 static char *addr (string_type
*, unsigned int);
116 static char at (string_type
*, unsigned int);
117 static void catchar (string_type
*, int);
118 static void overwrite_string (string_type
*, string_type
*);
119 static void catbuf (string_type
*, char *, unsigned int);
120 static void cattext (string_type
*, char *);
121 static void catstr (string_type
*, string_type
*);
125 init_string_with_size (buffer
, size
)
129 buffer
->write_idx
= 0;
131 buffer
->ptr
= malloc (size
);
138 init_string_with_size (buffer
, DEF_SIZE
);
149 for (i
= 0; i
< str
->write_idx
&& *p
; i
++)
151 if (*p
== str
->ptr
[i
])
160 write_buffer (buffer
, f
)
164 fwrite (buffer
->ptr
, buffer
->write_idx
, 1, f
);
168 delete_string (buffer
)
179 return buffer
->ptr
+ idx
;
187 if (pos
>= buffer
->write_idx
)
189 return buffer
->ptr
[pos
];
197 if (buffer
->write_idx
== buffer
->size
)
200 buffer
->ptr
= realloc (buffer
->ptr
, buffer
->size
);
203 buffer
->ptr
[buffer
->write_idx
++] = ch
;
207 overwrite_string (dst
, src
)
212 dst
->size
= src
->size
;
213 dst
->write_idx
= src
->write_idx
;
218 catbuf (buffer
, buf
, len
)
223 if (buffer
->write_idx
+ len
>= buffer
->size
)
225 while (buffer
->write_idx
+ len
>= buffer
->size
)
227 buffer
->ptr
= realloc (buffer
->ptr
, buffer
->size
);
229 memcpy (buffer
->ptr
+ buffer
->write_idx
, buf
, len
);
230 buffer
->write_idx
+= len
;
234 cattext (buffer
, string
)
238 catbuf (buffer
, string
, (unsigned int) strlen (string
));
246 catbuf (dst
, src
->ptr
, src
->write_idx
);
250 skip_white_and_stars (src
, idx
)
255 while ((c
= at (src
, idx
)),
256 isspace ((unsigned char) c
)
258 /* Don't skip past end-of-comment or star as first
259 character on its line. */
260 && at (src
, idx
+1) != '/'
261 && at (src
, idx
-1) != '\n'))
266 /***********************************************************************/
268 string_type stack
[STACK
];
271 unsigned int idx
= 0; /* Pos in input buffer */
272 string_type
*ptr
; /* and the buffer */
273 typedef void (*stinst_type
)();
275 stinst_type sstack
[STACK
];
276 stinst_type
*ssp
= &sstack
[0];
278 long *isp
= &istack
[0];
280 typedef int *word_type
;
285 struct dict_struct
*next
;
292 typedef struct dict_struct dict_type
;
298 fprintf (stderr
, "%s\n", msg
);
306 die ("underflow in string stack");
307 if (tos
>= stack
+ STACK
)
308 die ("overflow in string stack");
315 die ("underflow in integer stack");
316 if (isp
>= istack
+ STACK
)
317 die ("overflow in integer stack");
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);
368 stinst_type
*oldpc
= pc
;
370 e
= (dict_type
*) (pc
[1]);
384 strip_trailing_newlines ()
386 while ((isspace ((unsigned char) at (tos
, tos
->write_idx
- 1))
387 || at (tos
, tos
->write_idx
- 1) == '\n')
388 && tos
->write_idx
> 0)
410 cattext (tos
, *((char **) pc
));
414 /* This function removes everything not inside comments starting on
415 the first char of the line from the string, also when copying
416 comments, removes blank space and leading *'s.
417 Blank lines are turned into one blank line. */
420 remove_noncomments (src
, dst
)
424 unsigned int idx
= 0;
426 while (at (src
, idx
))
428 /* Now see if we have a comment at the start of the line. */
429 if (at (src
, idx
) == '\n'
430 && at (src
, idx
+ 1) == '/'
431 && at (src
, idx
+ 2) == '*')
435 idx
= skip_white_and_stars (src
, idx
);
437 /* Remove leading dot */
438 if (at (src
, idx
) == '.')
441 /* Copy to the end of the line, or till the end of the
443 while (at (src
, idx
))
445 if (at (src
, idx
) == '\n')
447 /* end of line, echo and scrape of leading blanks */
448 if (at (src
, idx
+ 1) == '\n')
452 idx
= skip_white_and_stars (src
, idx
);
454 else if (at (src
, idx
) == '*' && at (src
, idx
+ 1) == '/')
457 cattext (dst
, "\nENDDD\n");
462 catchar (dst
, at (src
, idx
));
475 fprintf (stderr
, "current string stack depth = %d, ", tos
- stack
);
476 fprintf (stderr
, "current integer stack depth = %d\n", isp
- istack
);
484 name PARAMS ((stuff));
500 /* Make sure that it's not already param'd or proto'd. */
502 || find (tos
, "PARAMS") || find (tos
, "PROTO") || !find (tos
, "("))
508 /* Find the open paren. */
509 for (openp
= 0; at (tos
, openp
) != '(' && at (tos
, openp
); openp
++)
513 /* Step back to the fname. */
515 while (fname
&& isspace ((unsigned char) at (tos
, fname
)))
518 && !isspace ((unsigned char) at (tos
,fname
))
519 && at (tos
,fname
) != '*')
524 /* Output type, omitting trailing whitespace character(s), if
526 for (len
= fname
; 0 < len
; len
--)
528 if (!isspace ((unsigned char) at (tos
, len
- 1)))
531 for (idx
= 0; idx
< len
; idx
++)
532 catchar (&out
, at (tos
, idx
));
534 cattext (&out
, "\n"); /* Insert a newline between type and fnname */
536 /* Output function name, omitting trailing whitespace
537 character(s), if any. */
538 for (len
= openp
; 0 < len
; len
--)
540 if (!isspace ((unsigned char) at (tos
, len
- 1)))
543 for (idx
= fname
; idx
< len
; idx
++)
544 catchar (&out
, at (tos
, idx
));
546 cattext (&out
, " PARAMS (");
548 for (idx
= openp
; at (tos
, idx
) && at (tos
, idx
) != ';'; idx
++)
549 catchar (&out
, at (tos
, idx
));
551 cattext (&out
, ");\n\n");
553 overwrite_string (tos
, &out
);
559 and *} into comments */
564 unsigned int idx
= 0;
568 while (at (tos
, idx
))
570 if (at (tos
, idx
) == '{' && at (tos
, idx
+ 1) == '*')
572 cattext (&out
, "/*");
575 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
577 cattext (&out
, "*/");
582 catchar (&out
, at (tos
, idx
));
587 overwrite_string (tos
, &out
);
592 /* Mod tos so that only lines with leading dots remain */
596 unsigned int idx
= 0;
600 while (at (tos
, idx
))
602 if (at (tos
, idx
) == '\n' && at (tos
, idx
+ 1) == '.')
607 while ((c
= at (tos
, idx
)) && c
!= '\n')
609 if (c
== '{' && at (tos
, idx
+ 1) == '*')
611 cattext (&out
, "/*");
614 else if (c
== '*' && at (tos
, idx
+ 1) == '}')
616 cattext (&out
, "*/");
625 catchar (&out
, '\n');
633 overwrite_string (tos
, &out
);
637 /* Find lines starting with . and | and put example around them on tos */
642 unsigned int idx
= 0;
647 while (at (tos
, idx
))
649 if (at (tos
, idx
) == '\n'
650 && (at (tos
, idx
+1 ) == '.'
651 || at (tos
, idx
+ 1) == '|'))
653 cattext (&out
, "\n@example\n");
658 while (at (tos
, idx
) && at (tos
, idx
) != '\n')
662 /* We are inside {} parameters of some command;
663 Just pass through until matching brace. */
664 if (at (tos
, idx
) == '{')
666 else if (at (tos
, idx
) == '}')
669 else if (command
!= 0)
671 if (at (tos
, idx
) == '{')
673 else if (!islower ((unsigned char) at (tos
, idx
)))
676 else if (at (tos
, idx
) == '@'
677 && islower ((unsigned char) at (tos
, idx
+ 1)))
681 else if (at (tos
, idx
) == '{' && at (tos
, idx
+ 1) == '*')
683 cattext (&out
, "/*");
687 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
689 cattext (&out
, "*/");
693 else if (at (tos
, idx
) == '{'
694 || at (tos
, idx
) == '}')
699 catchar (&out
, at (tos
, idx
));
702 catchar (&out
, '\n');
704 while (at (tos
, idx
) == '\n'
705 && ((at (tos
, idx
+ 1) == '.')
706 || (at (tos
, idx
+ 1) == '|')))
708 cattext (&out
, "@end example");
712 catchar (&out
, at (tos
, idx
));
717 overwrite_string (tos
, &out
);
721 /* Finds any lines starting with "o ", if there are any, then turns
722 on @itemize @bullet, and @items each of them. Then ends with @end
723 itemize, inplace at TOS*/
728 unsigned int idx
= 0;
733 while (at (tos
, idx
))
735 if (at (tos
, idx
) == '@'
736 && at (tos
, idx
+ 1) == '*')
741 else if (at (tos
, idx
) == '\n'
742 && at (tos
, idx
+ 1) == 'o'
743 && isspace ((unsigned char) at (tos
, idx
+ 2)))
747 cattext (&out
, "\n@itemize @bullet\n");
751 cattext (&out
, "\n@item\n");
756 catchar (&out
, at (tos
, idx
));
757 if (on
&& at (tos
, idx
) == '\n'
758 && at (tos
, idx
+ 1) == '\n'
759 && at (tos
, idx
+ 2) != 'o')
761 cattext (&out
, "@end itemize");
770 cattext (&out
, "@end itemize\n");
778 /* Turn <<foo>> into @code{foo} in place at TOS*/
783 unsigned int idx
= 0;
786 while (at (tos
, idx
))
788 if (at (tos
, idx
) == '<'
789 && at (tos
, idx
+ 1) == '<'
790 && !isspace ((unsigned char) at (tos
, idx
+ 2)))
792 /* This qualifies as a << startup. */
794 cattext (&out
, "@code{");
796 && at (tos
, idx
) != '>' )
798 catchar (&out
, at (tos
, idx
));
807 catchar (&out
, at (tos
, idx
));
817 /* A command is all upper case,and alone on a line. */
824 unsigned int len
= 0;
825 while (at (ptr
, idx
))
827 if (isupper ((unsigned char) at (ptr
, idx
))
828 || at (ptr
, idx
) == ' ' || at (ptr
, idx
) == '_')
833 else if (at (ptr
, idx
) == '\n')
846 copy_past_newline (ptr
, idx
, dst
)
853 while (at (ptr
, idx
) && at (ptr
, idx
) != '\n')
855 if (at (ptr
, idx
) == '\t')
857 /* Expand tabs. Neither makeinfo nor TeX can cope well with
861 while (++column
& 7);
865 catchar (dst
, at (ptr
, idx
));
871 catchar (dst
, at (ptr
, idx
));
878 icopy_past_newline ()
883 idx
= copy_past_newline (ptr
, idx
, tos
);
888 Take the string at the top of the stack, do some prettying. */
901 /* Drop leading nl. */
902 while (at (tos
, idx
) == '\n')
908 /* If the first char is a '.' prepend a newline so that it is
909 recognized properly later. */
910 if (at (tos
, idx
) == '.')
911 catchar (&out
, '\n');
913 /* Find the last char. */
914 while (at (tos
, idx
))
919 /* Find the last non white before the nl. */
922 while (idx
&& isspace ((unsigned char) at (tos
, idx
)))
926 /* Copy buffer upto last char, but blank lines before and after
932 if (at (tos
, c
) == '\n'
933 && at (tos
, c
+ 1) == '\n'
934 && at (tos
, c
+ 2) == '.')
936 /* Ignore two newlines before a dot. */
939 else if (at (tos
, c
) == '.' && sl
)
941 /* remember that this line started with a dot. */
944 else if (at (tos
, c
) == '\n'
945 && at (tos
, c
+ 1) == '\n'
949 /* Ignore two newlines when last line was dot. */
952 catchar (&out
, at (tos
, c
));
953 if (at (tos
, c
) == '\n')
970 catchar (&out
, '\n');
985 while (at (tos
, idx
))
987 switch (at (tos
, idx
))
990 cattext (&out
, "\n");
992 if (tab
&& at (tos
, idx
))
1001 cattext (&out
, " ");
1003 cattext (&out
, "(");
1008 cattext (&out
, ")");
1014 catchar (&out
, at (tos
, idx
));
1023 delete_string (tos
);
1029 get_stuff_in_command ()
1035 while (at (ptr
, idx
))
1037 if (iscommand (ptr
, idx
))
1039 idx
= copy_past_newline (ptr
, idx
, tos
);
1061 catstr (tos
, tos
- 1);
1086 catstr (tos
, tos
+ 1);
1087 delete_string (tos
+ 1);
1092 skip_past_newline ()
1094 while (at (ptr
, idx
)
1095 && at (ptr
, idx
) != '\n')
1104 internal_mode
= *(isp
);
1113 if (internal_wanted
== internal_mode
)
1115 catstr (tos
- 1, tos
);
1117 delete_string (tos
);
1124 nextword (string
, word
)
1135 while (isspace ((unsigned char) *string
) || *string
== '-')
1139 while (*string
&& *string
!= '\n')
1151 word_start
= string
;
1158 if (*string
== '\\')
1164 while (*string
!= '"');
1168 while (!isspace ((unsigned char) *string
))
1176 *word
= malloc (length
+ 1);
1181 for (idx
= 0; idx
< length
; idx
++)
1183 if (src
[idx
] == '\\')
1184 switch (src
[idx
+ 1])
1192 *dst
++ = src
[idx
+ 1];
1216 dict_type
*ptr
= root
;
1219 if (strcmp (ptr
->word
, word
) == 0)
1224 fprintf (stderr
, "Can't find %s\n", word
);
1233 while (at (ptr
, idx
))
1235 /* It's worth looking through the command list. */
1236 if (iscommand (ptr
, idx
))
1241 (void) nextword (addr (ptr
, idx
), &next
);
1243 word
= lookup_word (next
);
1252 fprintf (stderr
, "warning, %s is not recognised\n", next
);
1253 skip_past_newline ();
1258 skip_past_newline ();
1266 dict_type
*new = (dict_type
*) malloc (sizeof (dict_type
));
1270 new->code
= (stinst_type
*) malloc (sizeof (stinst_type
));
1271 new->code_length
= 1;
1277 add_to_definition (entry
, word
)
1281 if (entry
->code_end
== entry
->code_length
)
1283 entry
->code_length
+= 2;
1285 (stinst_type
*) realloc ((char *) (entry
->code
),
1286 entry
->code_length
* sizeof (word_type
));
1288 entry
->code
[entry
->code_end
] = word
;
1290 return entry
->code_end
++;
1294 add_intrinsic (name
, func
)
1298 dict_type
*new = newentry (name
);
1299 add_to_definition (new, func
);
1300 add_to_definition (new, 0);
1307 dict_type
*new = newentry (name
);
1308 add_to_definition (new, push_number
);
1309 add_to_definition (new, (stinst_type
) (&(new->var
)));
1310 add_to_definition (new, 0);
1317 /* Add words to the dictionary. */
1319 string
= nextword (string
, &word
);
1320 while (string
&& *string
&& word
[0])
1322 if (strcmp (word
, "var") == 0)
1324 string
= nextword (string
, &word
);
1327 string
= nextword (string
, &word
);
1329 else if (word
[0] == ':')
1332 /* Compile a word and add to dictionary. */
1333 string
= nextword (string
, &word
);
1335 ptr
= newentry (word
);
1336 string
= nextword (string
, &word
);
1337 while (word
[0] != ';')
1342 /* got a string, embed magic push string
1344 add_to_definition (ptr
, push_text
);
1345 add_to_definition (ptr
, (stinst_type
) (word
+ 1));
1357 /* Got a number, embedd the magic push number
1359 add_to_definition (ptr
, push_number
);
1360 add_to_definition (ptr
, (stinst_type
) atol (word
));
1363 add_to_definition (ptr
, call
);
1364 add_to_definition (ptr
, (stinst_type
) lookup_word (word
));
1367 string
= nextword (string
, &word
);
1369 add_to_definition (ptr
, 0);
1370 string
= nextword (string
, &word
);
1374 fprintf (stderr
, "syntax error at %s\n", string
- 1);
1382 *(long *) ((isp
[0])) = isp
[-1];
1391 isp
[0] = *(long *) (isp
[0]);
1424 write_buffer (tos
, stdout
);
1426 write_buffer (tos
, stderr
);
1428 fprintf (stderr
, "print: illegal print destination `%ld'\n", *isp
);
1445 r
= fread (buff
, 1, sizeof (buff
), file
);
1446 catbuf (str
, buff
, r
);
1451 catbuf (str
, buff
, 1);
1457 fprintf (stderr
, "usage: -[d|i|g] <file >file\n");
1461 /* There is no reliable way to declare exit. Sometimes it returns
1462 int, and sometimes it returns void. Sometimes it changes between
1463 OS releases. Trying to get it declared correctly in the hosts file
1464 is a pointless waste of time. */
1481 init_string (&buffer
);
1482 init_string (&pptr
);
1483 init_string (stack
+ 0);
1487 add_intrinsic ("push_text", push_text
);
1488 add_intrinsic ("!", bang
);
1489 add_intrinsic ("@", atsign
);
1490 add_intrinsic ("hello", hello
);
1491 add_intrinsic ("stdout", stdout_
);
1492 add_intrinsic ("stderr", stderr_
);
1493 add_intrinsic ("print", print
);
1494 add_intrinsic ("skip_past_newline", skip_past_newline
);
1495 add_intrinsic ("catstr", icatstr
);
1496 add_intrinsic ("copy_past_newline", icopy_past_newline
);
1497 add_intrinsic ("dup", other_dup
);
1498 add_intrinsic ("drop", drop
);
1499 add_intrinsic ("idrop", idrop
);
1500 add_intrinsic ("remchar", remchar
);
1501 add_intrinsic ("get_stuff_in_command", get_stuff_in_command
);
1502 add_intrinsic ("do_fancy_stuff", do_fancy_stuff
);
1503 add_intrinsic ("bulletize", bulletize
);
1504 add_intrinsic ("courierize", courierize
);
1505 /* If the following line gives an error, exit() is not declared in the
1506 ../hosts/foo.h file for this host. Fix it there, not here! */
1507 /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1508 add_intrinsic ("exit", chew_exit
);
1509 add_intrinsic ("swap", swap
);
1510 add_intrinsic ("outputdots", outputdots
);
1511 add_intrinsic ("paramstuff", paramstuff
);
1512 add_intrinsic ("maybecatstr", maybecatstr
);
1513 add_intrinsic ("translatecomments", translatecomments
);
1514 add_intrinsic ("kill_bogus_lines", kill_bogus_lines
);
1515 add_intrinsic ("indent", indent
);
1516 add_intrinsic ("internalmode", internalmode
);
1517 add_intrinsic ("print_stack_level", print_stack_level
);
1518 add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines
);
1520 /* Put a nl at the start. */
1521 catchar (&buffer
, '\n');
1523 read_in (&buffer
, stdin
);
1524 remove_noncomments (&buffer
, ptr
);
1525 for (i
= 1; i
< (unsigned int) ac
; i
++)
1527 if (av
[i
][0] == '-')
1529 if (av
[i
][1] == 'f')
1535 f
= fopen (av
[i
+ 1], "r");
1538 fprintf (stderr
, "Can't open the input file %s\n",
1547 else if (av
[i
][1] == 'i')
1549 internal_wanted
= 1;
1551 else if (av
[i
][1] == 'w')
1559 write_buffer (stack
+ 0, stdout
);
1562 fprintf (stderr
, "finishing with current stack level %d\n",