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
28 Basically, this is a sort of string forth, maybe we should call it
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
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)
55 copy_past_newline - append input, up to and including newline into TOS
59 remchar - delete last character from TOS
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 {* *} { }
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
71 translatecomments - turn {* and *} into comment delimiters
72 kill_bogus_lines - get rid of extra newlines
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.
98 /* Here is a string type ... */
100 typedef struct buffer
103 unsigned long write_idx
;
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
*);
123 init_string_with_size (buffer
, size
)
127 buffer
->write_idx
= 0;
129 buffer
->ptr
= malloc (size
);
136 init_string_with_size (buffer
, DEF_SIZE
);
147 for (i
= 0; i
< str
->write_idx
&& *p
; i
++)
149 if (*p
== str
->ptr
[i
])
158 write_buffer (buffer
, f
)
162 fwrite (buffer
->ptr
, buffer
->write_idx
, 1, f
);
166 delete_string (buffer
)
177 return buffer
->ptr
+ idx
;
185 if (pos
>= buffer
->write_idx
)
187 return buffer
->ptr
[pos
];
195 if (buffer
->write_idx
== buffer
->size
)
198 buffer
->ptr
= realloc (buffer
->ptr
, buffer
->size
);
201 buffer
->ptr
[buffer
->write_idx
++] = ch
;
205 overwrite_string (dst
, src
)
210 dst
->size
= src
->size
;
211 dst
->write_idx
= src
->write_idx
;
216 catbuf (buffer
, buf
, len
)
221 if (buffer
->write_idx
+ len
>= buffer
->size
)
223 while (buffer
->write_idx
+ len
>= buffer
->size
)
225 buffer
->ptr
= realloc (buffer
->ptr
, buffer
->size
);
227 memcpy (buffer
->ptr
+ buffer
->write_idx
, buf
, len
);
228 buffer
->write_idx
+= len
;
232 cattext (buffer
, string
)
236 catbuf (buffer
, string
, (unsigned int) strlen (string
));
244 catbuf (dst
, src
->ptr
, src
->write_idx
);
248 skip_white_and_stars (src
, idx
)
253 while ((c
= at (src
, idx
)),
254 isspace ((unsigned char) 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'))
264 /***********************************************************************/
266 string_type stack
[STACK
];
269 unsigned int idx
= 0; /* Pos in input buffer */
270 string_type
*ptr
; /* and the buffer */
271 typedef void (*stinst_type
)();
273 stinst_type sstack
[STACK
];
274 stinst_type
*ssp
= &sstack
[0];
276 long *isp
= &istack
[0];
278 typedef int *word_type
;
283 struct dict_struct
*next
;
290 typedef struct dict_struct dict_type
;
292 #define WORD(x) static void x()
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);
367 stinst_type
*oldpc
= pc
;
369 e
= (dict_type
*) (pc
[1]);
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)
406 cattext (tos
, *((char **) 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. */
416 remove_noncomments (src
, 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) == '*')
431 idx
= skip_white_and_stars (src
, idx
);
433 /* Remove leading dot */
434 if (at (src
, idx
) == '.')
437 /* Copy to the end of the line, or till the end of the
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')
448 idx
= skip_white_and_stars (src
, idx
);
450 else if (at (src
, idx
) == '*' && at (src
, idx
+ 1) == '/')
453 cattext (dst
, "\nENDDD\n");
458 catchar (dst
, at (src
, idx
));
471 fprintf (stderr
, "current string stack depth = %d, ", tos
- stack
);
472 fprintf (stderr
, "current integer stack depth = %d\n", isp
- istack
);
480 name PARAMS ((stuff));
493 /* Make sure that it's not already param'd or proto'd. */
494 if (find (tos
, "PARAMS") || find (tos
, "PROTO") || !find (tos
, "("))
500 /* Find the open paren. */
501 for (openp
= 0; at (tos
, openp
) != '(' && at (tos
, openp
); openp
++)
505 /* Step back to the fname. */
507 while (fname
&& isspace ((unsigned char) at (tos
, fname
)))
510 && !isspace ((unsigned char) at (tos
,fname
))
511 && at (tos
,fname
) != '*')
516 for (idx
= 0; idx
< fname
; idx
++) /* Output type */
518 /* Omit a trailing whitespace. */
519 if (idx
+ 1 == fname
&& isspace ((unsigned char) at (tos
, idx
)))
522 catchar (&out
, at (tos
, idx
));
525 cattext (&out
, "\n"); /* Insert a newline between type and fnname */
527 for (idx
= fname
; idx
< openp
; idx
++) /* Output fnname */
529 catchar (&out
, at (tos
, idx
));
532 cattext (&out
, " PARAMS (");
534 while (at (tos
, idx
) && at (tos
, idx
) != ';')
536 catchar (&out
, at (tos
, idx
));
539 cattext (&out
, ");\n\n");
541 overwrite_string (tos
, &out
);
547 and *} into comments */
549 WORD (translatecomments
)
551 unsigned int idx
= 0;
555 while (at (tos
, idx
))
557 if (at (tos
, idx
) == '{' && at (tos
, idx
+ 1) == '*')
559 cattext (&out
, "/*");
562 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
564 cattext (&out
, "*/");
569 catchar (&out
, at (tos
, idx
));
574 overwrite_string (tos
, &out
);
581 /* This is not currently used. */
583 /* turn everything not starting with a . into a comment */
585 WORD (manglecomments
)
587 unsigned int idx
= 0;
591 while (at (tos
, idx
))
593 if (at (tos
, idx
) == '\n' && at (tos
, idx
+ 1) == '*')
595 cattext (&out
, " /*");
598 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
600 cattext (&out
, "*/");
605 catchar (&out
, at (tos
, idx
));
610 overwrite_string (tos
, &out
);
617 /* Mod tos so that only lines with leading dots remain */
621 unsigned int idx
= 0;
625 while (at (tos
, idx
))
627 if (at (tos
, idx
) == '\n' && at (tos
, idx
+ 1) == '.')
632 while ((c
= at (tos
, idx
)) && c
!= '\n')
634 if (c
== '{' && at (tos
, idx
+ 1) == '*')
636 cattext (&out
, "/*");
639 else if (c
== '*' && at (tos
, idx
+ 1) == '}')
641 cattext (&out
, "*/");
650 catchar (&out
, '\n');
658 overwrite_string (tos
, &out
);
662 /* Find lines starting with . and | and put example around them on tos */
666 unsigned int idx
= 0;
671 while (at (tos
, idx
))
673 if (at (tos
, idx
) == '\n'
674 && (at (tos
, idx
+1 ) == '.'
675 || at (tos
, idx
+ 1) == '|'))
677 cattext (&out
, "\n@example\n");
682 while (at (tos
, idx
) && at (tos
, idx
) != '\n')
684 if (at (tos
, idx
) == '{' && at (tos
, idx
+ 1) == '*')
686 cattext (&out
, "/*");
689 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
691 cattext (&out
, "*/");
694 else if (at (tos
, idx
) == '{' && !command
)
696 cattext (&out
, "@{");
699 else if (at (tos
, idx
) == '}' && !command
)
701 cattext (&out
, "@}");
706 if (at (tos
, idx
) == '@')
708 else if (isspace ((unsigned char) at (tos
, idx
))
709 || at (tos
, idx
) == '}')
711 catchar (&out
, at (tos
, idx
));
716 catchar (&out
, '\n');
718 while (at (tos
, idx
) == '\n'
719 && ((at (tos
, idx
+ 1) == '.')
720 || (at (tos
, idx
+ 1) == '|')))
722 cattext (&out
, "@end example");
726 catchar (&out
, at (tos
, idx
));
731 overwrite_string (tos
, &out
);
735 /* Finds any lines starting with "o ", if there are any, then turns
736 on @itemize @bullet, and @items each of them. Then ends with @end
737 itemize, inplace at TOS*/
741 unsigned int idx
= 0;
746 while (at (tos
, idx
))
748 if (at (tos
, idx
) == '@'
749 && at (tos
, idx
+ 1) == '*')
754 else if (at (tos
, idx
) == '\n'
755 && at (tos
, idx
+ 1) == 'o'
756 && isspace ((unsigned char) at (tos
, idx
+ 2)))
760 cattext (&out
, "\n@itemize @bullet\n");
764 cattext (&out
, "\n@item\n");
769 catchar (&out
, at (tos
, idx
));
770 if (on
&& at (tos
, idx
) == '\n'
771 && at (tos
, idx
+ 1) == '\n'
772 && at (tos
, idx
+ 2) != 'o')
774 cattext (&out
, "@end itemize");
783 cattext (&out
, "@end itemize\n");
791 /* Turn <<foo>> into @code{foo} in place at TOS*/
793 WORD (do_fancy_stuff
)
795 unsigned int idx
= 0;
798 while (at (tos
, idx
))
800 if (at (tos
, idx
) == '<'
801 && at (tos
, idx
+ 1) == '<'
802 && !isspace ((unsigned char) at (tos
, idx
+ 2)))
804 /* This qualifies as a << startup. */
806 cattext (&out
, "@code{");
808 && at (tos
, idx
) != '>' )
810 catchar (&out
, at (tos
, idx
));
819 catchar (&out
, at (tos
, idx
));
829 /* A command is all upper case,and alone on a line. */
836 unsigned int len
= 0;
837 while (at (ptr
, idx
))
839 if (isupper ((unsigned char) at (ptr
, idx
))
840 || at (ptr
, idx
) == ' ' || at (ptr
, idx
) == '_')
845 else if (at (ptr
, idx
) == '\n')
858 copy_past_newline (ptr
, idx
, dst
)
865 while (at (ptr
, idx
) && at (ptr
, idx
) != '\n')
867 if (at (ptr
, idx
) == '\t')
869 /* Expand tabs. Neither makeinfo nor TeX can cope well with
873 while (++column
& 7);
877 catchar (dst
, at (ptr
, idx
));
883 catchar (dst
, at (ptr
, idx
));
889 WORD (icopy_past_newline
)
894 idx
= copy_past_newline (ptr
, idx
, tos
);
899 Take the string at the top of the stack, do some prettying. */
901 WORD (kill_bogus_lines
)
911 /* Drop leading nl. */
912 while (at (tos
, idx
) == '\n')
918 /* If the first char is a '.' prepend a newline so that it is
919 recognized properly later. */
920 if (at (tos
, idx
) == '.')
921 catchar (&out
, '\n');
923 /* Find the last char. */
924 while (at (tos
, idx
))
929 /* Find the last non white before the nl. */
932 while (idx
&& isspace ((unsigned char) at (tos
, idx
)))
936 /* Copy buffer upto last char, but blank lines before and after
942 if (at (tos
, c
) == '\n'
943 && at (tos
, c
+ 1) == '\n'
944 && at (tos
, c
+ 2) == '.')
946 /* Ignore two newlines before a dot. */
949 else if (at (tos
, c
) == '.' && sl
)
951 /* remember that this line started with a dot. */
954 else if (at (tos
, c
) == '\n'
955 && at (tos
, c
+ 1) == '\n'
959 /* Ignore two newlines when last line was dot. */
962 catchar (&out
, at (tos
, c
));
963 if (at (tos
, c
) == '\n')
980 catchar (&out
, '\n');
994 while (at (tos
, idx
))
996 switch (at (tos
, idx
))
999 cattext (&out
, "\n");
1001 if (tab
&& at (tos
, idx
))
1003 cattext (&out
, " ");
1010 cattext (&out
, " ");
1012 cattext (&out
, "(");
1017 cattext (&out
, ")");
1023 catchar (&out
, at (tos
, idx
));
1032 delete_string (tos
);
1037 WORD (get_stuff_in_command
)
1043 while (at (ptr
, idx
))
1045 if (iscommand (ptr
, idx
))
1047 idx
= copy_past_newline (ptr
, idx
, tos
);
1067 catstr (tos
, tos
- 1);
1089 catstr (tos
, tos
+ 1);
1090 delete_string (tos
+ 1);
1094 WORD (skip_past_newline
)
1096 while (at (ptr
, idx
)
1097 && at (ptr
, idx
) != '\n')
1105 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];
1390 isp
[0] = *(long *) (isp
[0]);
1419 write_buffer (tos
, stdout
);
1421 write_buffer (tos
, stderr
);
1423 fprintf (stderr
, "print: illegal print destination `%ld'\n", *isp
);
1440 r
= fread (buff
, 1, sizeof (buff
), file
);
1441 catbuf (str
, buff
, r
);
1446 catbuf (str
, buff
, 1);
1452 fprintf (stderr
, "usage: -[d|i|g] <file >file\n");
1456 /* There is no reliable way to declare exit. Sometimes it returns
1457 int, and sometimes it returns void. Sometimes it changes between
1458 OS releases. Trying to get it declared correctly in the hosts file
1459 is a pointless waste of time. */
1476 init_string (&buffer
);
1477 init_string (&pptr
);
1478 init_string (stack
+ 0);
1482 add_intrinsic ("push_text", push_text
);
1483 add_intrinsic ("!", bang
);
1484 add_intrinsic ("@", atsign
);
1485 add_intrinsic ("hello", hello
);
1486 add_intrinsic ("stdout", stdout_
);
1487 add_intrinsic ("stderr", stderr_
);
1488 add_intrinsic ("print", print
);
1489 add_intrinsic ("skip_past_newline", skip_past_newline
);
1490 add_intrinsic ("catstr", icatstr
);
1491 add_intrinsic ("copy_past_newline", icopy_past_newline
);
1492 add_intrinsic ("dup", other_dup
);
1493 add_intrinsic ("drop", drop
);
1494 add_intrinsic ("idrop", idrop
);
1495 add_intrinsic ("remchar", remchar
);
1496 add_intrinsic ("get_stuff_in_command", get_stuff_in_command
);
1497 add_intrinsic ("do_fancy_stuff", do_fancy_stuff
);
1498 add_intrinsic ("bulletize", bulletize
);
1499 add_intrinsic ("courierize", courierize
);
1500 /* If the following line gives an error, exit() is not declared in the
1501 ../hosts/foo.h file for this host. Fix it there, not here! */
1502 /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1503 add_intrinsic ("exit", chew_exit
);
1504 add_intrinsic ("swap", swap
);
1505 add_intrinsic ("outputdots", outputdots
);
1506 add_intrinsic ("paramstuff", paramstuff
);
1507 add_intrinsic ("maybecatstr", maybecatstr
);
1508 add_intrinsic ("translatecomments", translatecomments
);
1509 add_intrinsic ("kill_bogus_lines", kill_bogus_lines
);
1510 add_intrinsic ("indent", indent
);
1511 add_intrinsic ("internalmode", internalmode
);
1512 add_intrinsic ("print_stack_level", print_stack_level
);
1513 add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines
);
1515 /* Put a nl at the start. */
1516 catchar (&buffer
, '\n');
1518 read_in (&buffer
, stdin
);
1519 remove_noncomments (&buffer
, ptr
);
1520 for (i
= 1; i
< (unsigned int) ac
; i
++)
1522 if (av
[i
][0] == '-')
1524 if (av
[i
][1] == 'f')
1530 f
= fopen (av
[i
+ 1], "r");
1533 fprintf (stderr
, "Can't open the input file %s\n",
1542 else if (av
[i
][1] == 'i')
1544 internal_wanted
= 1;
1546 else if (av
[i
][1] == 'w')
1554 write_buffer (stack
+ 0, stdout
);
1557 fprintf (stderr
, "finishing with current stack level %d\n",
This page took 0.06373 seconds and 5 git commands to generate.