2
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 2000, 2001,
3
2002, 2003, 2005, 2007, 2009, 2012
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 3 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,
22
MA 02110-1301, USA. */
24
/* Yet another way of extracting documentation from source.
25
No, I haven't finished it yet, but I hope you people like it better
30
Basically, this is a sort of string forth, maybe we should call it
33
You define new words thus:
34
: <newword> <oldwords> ;
38
/* Primitives provided by the program:
40
Two stacks are provided, a string stack and an integer stack.
42
Internal state variables:
43
internal_wanted - indicates whether `-i' was passed
44
internal_mode - user-settable
48
! - pop top of integer stack for address, pop next for value; store
49
@ - treat value on integer stack as the address of an integer; push
50
that integer on the integer stack after popping the "address"
51
hello - print "hello\n" to stdout
52
stdout - put stdout marker on TOS
53
stderr - put stderr marker on TOS
54
print - print TOS-1 on TOS (eg: "hello\n" stdout print)
57
copy_past_newline - append input, up to and including newline into TOS
61
remchar - delete last character from TOS
63
do_fancy_stuff - translate <<foo>> to @code{foo} in TOS
64
bulletize - if "o" lines found, prepend @itemize @bullet to TOS
65
and @item to each "o" line; append @end itemize
66
courierize - put @example around . and | lines, translate {* *} { }
69
outputdots - strip out lines without leading dots
70
paramstuff - convert full declaration into "PARAMS" form if not already
71
maybecatstr - do catstr if internal_mode == internal_wanted, discard
73
translatecomments - turn {* and *} into comment delimiters
74
kill_bogus_lines - get rid of extra newlines
76
internalmode - pop from integer stack, set `internalmode' to that value
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
A command must be all upper-case, and alone on a line.
101
/* Here is a string type ... */
103
typedef struct buffer
106
unsigned long write_idx;
111
static void init_string_with_size (string_type *, unsigned int);
112
static void init_string (string_type *);
113
static int find (string_type *, char *);
114
static void write_buffer (string_type *, FILE *);
115
static void delete_string (string_type *);
116
static char *addr (string_type *, unsigned int);
117
static char at (string_type *, unsigned int);
118
static void catchar (string_type *, int);
119
static void overwrite_string (string_type *, string_type *);
120
static void catbuf (string_type *, char *, unsigned int);
121
static void cattext (string_type *, char *);
122
static void catstr (string_type *, string_type *);
123
static void die (char *);
127
init_string_with_size (buffer, size)
131
buffer->write_idx = 0;
133
buffer->ptr = (char *) malloc (size);
140
init_string_with_size (buffer, DEF_SIZE);
151
for (i = 0; i < str->write_idx && *p; i++)
153
if (*p == str->ptr[i])
162
write_buffer (buffer, f)
166
if (buffer->write_idx != 0
167
&& fwrite (buffer->ptr, buffer->write_idx, 1, f) != 1)
168
die ("cannot write output");
172
delete_string (buffer)
183
return buffer->ptr + idx;
191
if (pos >= buffer->write_idx)
193
return buffer->ptr[pos];
201
if (buffer->write_idx == buffer->size)
204
buffer->ptr = (char *) realloc (buffer->ptr, buffer->size);
207
buffer->ptr[buffer->write_idx++] = ch;
211
overwrite_string (dst, src)
216
dst->size = src->size;
217
dst->write_idx = src->write_idx;
222
catbuf (buffer, buf, len)
227
if (buffer->write_idx + len >= buffer->size)
229
while (buffer->write_idx + len >= buffer->size)
231
buffer->ptr = (char *) realloc (buffer->ptr, buffer->size);
233
memcpy (buffer->ptr + buffer->write_idx, buf, len);
234
buffer->write_idx += len;
238
cattext (buffer, string)
242
catbuf (buffer, string, (unsigned int) strlen (string));
250
catbuf (dst, src->ptr, src->write_idx);
254
skip_white_and_stars (src, idx)
259
while ((c = at (src, idx)),
260
isspace ((unsigned char) c)
262
/* Don't skip past end-of-comment or star as first
263
character on its line. */
264
&& at (src, idx +1) != '/'
265
&& at (src, idx -1) != '\n'))
270
/***********************************************************************/
272
string_type stack[STACK];
275
unsigned int idx = 0; /* Pos in input buffer */
276
string_type *ptr; /* and the buffer */
277
typedef void (*stinst_type)();
279
stinst_type sstack[STACK];
280
stinst_type *ssp = &sstack[0];
282
long *isp = &istack[0];
284
typedef int *word_type;
289
struct dict_struct *next;
296
typedef struct dict_struct dict_type;
302
fprintf (stderr, "%s\n", msg);
310
die ("underflow in string stack");
311
if (tos >= stack + STACK)
312
die ("overflow in string stack");
319
die ("underflow in integer stack");
320
if (isp >= istack + STACK)
321
die ("overflow in integer stack");
325
static void exec (dict_type *);
326
static void call (void);
327
static void remchar (void), strip_trailing_newlines (void), push_number (void);
328
static void push_text (void);
329
static void remove_noncomments (string_type *, string_type *);
330
static void print_stack_level (void);
331
static void paramstuff (void), translatecomments (void);
332
static void outputdots (void), courierize (void), bulletize (void);
333
static void do_fancy_stuff (void);
334
static int iscommand (string_type *, unsigned int);
335
static int copy_past_newline (string_type *, unsigned int, string_type *);
336
static void icopy_past_newline (void), kill_bogus_lines (void), indent (void);
337
static void get_stuff_in_command (void), swap (void), other_dup (void);
338
static void drop (void), idrop (void);
339
static void icatstr (void), skip_past_newline (void), internalmode (void);
340
static void maybecatstr (void);
341
static char *nextword (char *, char **);
342
dict_type *lookup_word (char *);
343
static void perform (void);
344
dict_type *newentry (char *);
345
unsigned int add_to_definition (dict_type *, stinst_type);
346
void add_intrinsic (char *, void (*)());
347
void add_var (char *);
348
void compile (char *);
349
static void bang (void);
350
static void atsign (void);
351
static void hello (void);
352
static void stdout_ (void);
353
static void stderr_ (void);
354
static void print (void);
355
static void read_in (string_type *, FILE *);
356
static void usage (void);
357
static void chew_exit (void);
372
stinst_type *oldpc = pc;
374
e = (dict_type *) (pc[1]);
388
strip_trailing_newlines ()
390
while ((isspace ((unsigned char) at (tos, tos->write_idx - 1))
391
|| at (tos, tos->write_idx - 1) == '\n')
392
&& tos->write_idx > 0)
414
cattext (tos, *((char **) pc));
418
/* This function removes everything not inside comments starting on
419
the first char of the line from the string, also when copying
420
comments, removes blank space and leading *'s.
421
Blank lines are turned into one blank line. */
424
remove_noncomments (src, dst)
428
unsigned int idx = 0;
430
while (at (src, idx))
432
/* Now see if we have a comment at the start of the line. */
433
if (at (src, idx) == '\n'
434
&& at (src, idx + 1) == '/'
435
&& at (src, idx + 2) == '*')
439
idx = skip_white_and_stars (src, idx);
441
/* Remove leading dot */
442
if (at (src, idx) == '.')
445
/* Copy to the end of the line, or till the end of the
447
while (at (src, idx))
449
if (at (src, idx) == '\n')
451
/* end of line, echo and scrape of leading blanks */
452
if (at (src, idx + 1) == '\n')
456
idx = skip_white_and_stars (src, idx);
458
else if (at (src, idx) == '*' && at (src, idx + 1) == '/')
461
cattext (dst, "\nENDDD\n");
466
catchar (dst, at (src, idx));
479
fprintf (stderr, "current string stack depth = %ld, ", tos - stack);
480
fprintf (stderr, "current integer stack depth = %ld\n", isp - istack);
488
name PARAMS ((stuff));
504
/* Make sure that it's not already param'd or proto'd. */
506
|| find (tos, "PARAMS") || find (tos, "PROTO") || !find (tos, "("))
512
/* Find the open paren. */
513
for (openp = 0; at (tos, openp) != '(' && at (tos, openp); openp++)
517
/* Step back to the fname. */
519
while (fname && isspace ((unsigned char) at (tos, fname)))
522
&& !isspace ((unsigned char) at (tos,fname))
523
&& at (tos,fname) != '*')
528
/* Output type, omitting trailing whitespace character(s), if
530
for (len = fname; 0 < len; len--)
532
if (!isspace ((unsigned char) at (tos, len - 1)))
535
for (idx = 0; idx < len; idx++)
536
catchar (&out, at (tos, idx));
538
cattext (&out, "\n"); /* Insert a newline between type and fnname */
540
/* Output function name, omitting trailing whitespace
541
character(s), if any. */
542
for (len = openp; 0 < len; len--)
544
if (!isspace ((unsigned char) at (tos, len - 1)))
547
for (idx = fname; idx < len; idx++)
548
catchar (&out, at (tos, idx));
550
cattext (&out, " PARAMS (");
552
for (idx = openp; at (tos, idx) && at (tos, idx) != ';'; idx++)
553
catchar (&out, at (tos, idx));
555
cattext (&out, ");\n\n");
557
overwrite_string (tos, &out);
563
and *} into comments */
568
unsigned int idx = 0;
572
while (at (tos, idx))
574
if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
576
cattext (&out, "/*");
579
else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
581
cattext (&out, "*/");
586
catchar (&out, at (tos, idx));
591
overwrite_string (tos, &out);
596
/* Mod tos so that only lines with leading dots remain */
600
unsigned int idx = 0;
604
while (at (tos, idx))
606
if (at (tos, idx) == '\n' && at (tos, idx + 1) == '.')
611
while ((c = at (tos, idx)) && c != '\n')
613
if (c == '{' && at (tos, idx + 1) == '*')
615
cattext (&out, "/*");
618
else if (c == '*' && at (tos, idx + 1) == '}')
620
cattext (&out, "*/");
629
catchar (&out, '\n');
637
overwrite_string (tos, &out);
641
/* Find lines starting with . and | and put example around them on tos */
646
unsigned int idx = 0;
651
while (at (tos, idx))
653
if (at (tos, idx) == '\n'
654
&& (at (tos, idx +1 ) == '.'
655
|| at (tos, idx + 1) == '|'))
657
cattext (&out, "\n@example\n");
662
while (at (tos, idx) && at (tos, idx) != '\n')
666
/* We are inside {} parameters of some command;
667
Just pass through until matching brace. */
668
if (at (tos, idx) == '{')
670
else if (at (tos, idx) == '}')
673
else if (command != 0)
675
if (at (tos, idx) == '{')
677
else if (!islower ((unsigned char) at (tos, idx)))
680
else if (at (tos, idx) == '@'
681
&& islower ((unsigned char) at (tos, idx + 1)))
685
else if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
687
cattext (&out, "/*");
691
else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
693
cattext (&out, "*/");
697
else if (at (tos, idx) == '{'
698
|| at (tos, idx) == '}')
703
catchar (&out, at (tos, idx));
706
catchar (&out, '\n');
708
while (at (tos, idx) == '\n'
709
&& ((at (tos, idx + 1) == '.')
710
|| (at (tos, idx + 1) == '|')))
712
cattext (&out, "@end example");
716
catchar (&out, at (tos, idx));
721
overwrite_string (tos, &out);
725
/* Finds any lines starting with "o ", if there are any, then turns
726
on @itemize @bullet, and @items each of them. Then ends with @end
727
itemize, inplace at TOS*/
732
unsigned int idx = 0;
737
while (at (tos, idx))
739
if (at (tos, idx) == '@'
740
&& at (tos, idx + 1) == '*')
745
else if (at (tos, idx) == '\n'
746
&& at (tos, idx + 1) == 'o'
747
&& isspace ((unsigned char) at (tos, idx + 2)))
751
cattext (&out, "\n@itemize @bullet\n");
755
cattext (&out, "\n@item\n");
760
catchar (&out, at (tos, idx));
761
if (on && at (tos, idx) == '\n'
762
&& at (tos, idx + 1) == '\n'
763
&& at (tos, idx + 2) != 'o')
765
cattext (&out, "@end itemize");
774
cattext (&out, "@end itemize\n");
782
/* Turn <<foo>> into @code{foo} in place at TOS*/
787
unsigned int idx = 0;
790
while (at (tos, idx))
792
if (at (tos, idx) == '<'
793
&& at (tos, idx + 1) == '<'
794
&& !isspace ((unsigned char) at (tos, idx + 2)))
796
/* This qualifies as a << startup. */
798
cattext (&out, "@code{");
800
&& at (tos, idx) != '>' )
802
catchar (&out, at (tos, idx));
811
catchar (&out, at (tos, idx));
821
/* A command is all upper case,and alone on a line. */
828
unsigned int len = 0;
829
while (at (ptr, idx))
831
if (isupper ((unsigned char) at (ptr, idx))
832
|| at (ptr, idx) == ' ' || at (ptr, idx) == '_')
837
else if (at (ptr, idx) == '\n')
850
copy_past_newline (ptr, idx, dst)
857
while (at (ptr, idx) && at (ptr, idx) != '\n')
859
if (at (ptr, idx) == '\t')
861
/* Expand tabs. Neither makeinfo nor TeX can cope well with
865
while (++column & 7);
869
catchar (dst, at (ptr, idx));
875
catchar (dst, at (ptr, idx));
882
icopy_past_newline ()
887
idx = copy_past_newline (ptr, idx, tos);
892
Take the string at the top of the stack, do some prettying. */
905
/* Drop leading nl. */
906
while (at (tos, idx) == '\n')
912
/* If the first char is a '.' prepend a newline so that it is
913
recognized properly later. */
914
if (at (tos, idx) == '.')
915
catchar (&out, '\n');
917
/* Find the last char. */
918
while (at (tos, idx))
923
/* Find the last non white before the nl. */
926
while (idx && isspace ((unsigned char) at (tos, idx)))
930
/* Copy buffer upto last char, but blank lines before and after
936
if (at (tos, c) == '\n'
937
&& at (tos, c + 1) == '\n'
938
&& at (tos, c + 2) == '.')
940
/* Ignore two newlines before a dot. */
943
else if (at (tos, c) == '.' && sl)
945
/* remember that this line started with a dot. */
948
else if (at (tos, c) == '\n'
949
&& at (tos, c + 1) == '\n'
953
/* Ignore two newlines when last line was dot. */
956
catchar (&out, at (tos, c));
957
if (at (tos, c) == '\n')
974
catchar (&out, '\n');
989
while (at (tos, idx))
991
switch (at (tos, idx))
994
cattext (&out, "\n");
996
if (tab && at (tos, idx))
1005
cattext (&out, " ");
1007
cattext (&out, "(");
1012
cattext (&out, ")");
1018
catchar (&out, at (tos, idx));
1027
delete_string (tos);
1033
get_stuff_in_command ()
1039
while (at (ptr, idx))
1041
if (iscommand (ptr, idx))
1043
idx = copy_past_newline (ptr, idx, tos);
1065
catstr (tos, tos - 1);
1090
catstr (tos, tos + 1);
1091
delete_string (tos + 1);
1096
skip_past_newline ()
1098
while (at (ptr, idx)
1099
&& at (ptr, idx) != '\n')
1108
internal_mode = *(isp);
1117
if (internal_wanted == internal_mode)
1119
catstr (tos - 1, tos);
1121
delete_string (tos);
1128
nextword (string, word)
1139
while (isspace ((unsigned char) *string) || *string == '-')
1143
while (*string && *string != '\n')
1155
word_start = string;
1162
if (*string == '\\')
1168
while (*string != '"');
1172
while (!isspace ((unsigned char) *string))
1180
*word = (char *) malloc (length + 1);
1185
for (idx = 0; idx < length; idx++)
1187
if (src[idx] == '\\')
1188
switch (src[idx + 1])
1196
*dst++ = src[idx + 1];
1220
dict_type *ptr = root;
1223
if (strcmp (ptr->word, word) == 0)
1228
fprintf (stderr, "Can't find %s\n", word);
1237
while (at (ptr, idx))
1239
/* It's worth looking through the command list. */
1240
if (iscommand (ptr, idx))
1245
(void) nextword (addr (ptr, idx), &next);
1247
word = lookup_word (next);
1256
fprintf (stderr, "warning, %s is not recognised\n", next);
1257
skip_past_newline ();
1262
skip_past_newline ();
1270
dict_type *new_d = (dict_type *) malloc (sizeof (dict_type));
1274
new_d->code = (stinst_type *) malloc (sizeof (stinst_type));
1275
new_d->code_length = 1;
1276
new_d->code_end = 0;
1281
add_to_definition (entry, word)
1285
if (entry->code_end == entry->code_length)
1287
entry->code_length += 2;
1289
(stinst_type *) realloc ((char *) (entry->code),
1290
entry->code_length * sizeof (word_type));
1292
entry->code[entry->code_end] = word;
1294
return entry->code_end++;
1298
add_intrinsic (name, func)
1302
dict_type *new_d = newentry (name);
1303
add_to_definition (new_d, func);
1304
add_to_definition (new_d, 0);
1311
dict_type *new_d = newentry (name);
1312
add_to_definition (new_d, push_number);
1313
add_to_definition (new_d, (stinst_type) (&(new_d->var)));
1314
add_to_definition (new_d, 0);
1321
/* Add words to the dictionary. */
1323
string = nextword (string, &word);
1324
while (string && *string && word[0])
1326
if (strcmp (word, "var") == 0)
1328
string = nextword (string, &word);
1331
string = nextword (string, &word);
1333
else if (word[0] == ':')
1336
/* Compile a word and add to dictionary. */
1337
string = nextword (string, &word);
1339
ptr = newentry (word);
1340
string = nextword (string, &word);
1341
while (word[0] != ';')
1346
/* got a string, embed magic push string
1348
add_to_definition (ptr, push_text);
1349
add_to_definition (ptr, (stinst_type) (word + 1));
1361
/* Got a number, embedd the magic push number
1363
add_to_definition (ptr, push_number);
1364
add_to_definition (ptr, (stinst_type) atol (word));
1367
add_to_definition (ptr, call);
1368
add_to_definition (ptr, (stinst_type) lookup_word (word));
1371
string = nextword (string, &word);
1373
add_to_definition (ptr, 0);
1374
string = nextword (string, &word);
1378
fprintf (stderr, "syntax error at %s\n", string - 1);
1386
*(long *) ((isp[0])) = isp[-1];
1395
isp[0] = *(long *) (isp[0]);
1428
write_buffer (tos, stdout);
1430
write_buffer (tos, stderr);
1432
fprintf (stderr, "print: illegal print destination `%ld'\n", *isp);
1449
r = fread (buff, 1, sizeof (buff), file);
1450
catbuf (str, buff, r);
1455
catbuf (str, buff, 1);
1461
fprintf (stderr, "usage: -[d|i|g] <file >file\n");
1465
/* There is no reliable way to declare exit. Sometimes it returns
1466
int, and sometimes it returns void. Sometimes it changes between
1467
OS releases. Trying to get it declared correctly in the hosts file
1468
is a pointless waste of time. */
1485
init_string (&buffer);
1486
init_string (&pptr);
1487
init_string (stack + 0);
1491
add_intrinsic ("push_text", push_text);
1492
add_intrinsic ("!", bang);
1493
add_intrinsic ("@", atsign);
1494
add_intrinsic ("hello", hello);
1495
add_intrinsic ("stdout", stdout_);
1496
add_intrinsic ("stderr", stderr_);
1497
add_intrinsic ("print", print);
1498
add_intrinsic ("skip_past_newline", skip_past_newline);
1499
add_intrinsic ("catstr", icatstr);
1500
add_intrinsic ("copy_past_newline", icopy_past_newline);
1501
add_intrinsic ("dup", other_dup);
1502
add_intrinsic ("drop", drop);
1503
add_intrinsic ("idrop", idrop);
1504
add_intrinsic ("remchar", remchar);
1505
add_intrinsic ("get_stuff_in_command", get_stuff_in_command);
1506
add_intrinsic ("do_fancy_stuff", do_fancy_stuff);
1507
add_intrinsic ("bulletize", bulletize);
1508
add_intrinsic ("courierize", courierize);
1509
/* If the following line gives an error, exit() is not declared in the
1510
../hosts/foo.h file for this host. Fix it there, not here! */
1511
/* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1512
add_intrinsic ("exit", chew_exit);
1513
add_intrinsic ("swap", swap);
1514
add_intrinsic ("outputdots", outputdots);
1515
add_intrinsic ("paramstuff", paramstuff);
1516
add_intrinsic ("maybecatstr", maybecatstr);
1517
add_intrinsic ("translatecomments", translatecomments);
1518
add_intrinsic ("kill_bogus_lines", kill_bogus_lines);
1519
add_intrinsic ("indent", indent);
1520
add_intrinsic ("internalmode", internalmode);
1521
add_intrinsic ("print_stack_level", print_stack_level);
1522
add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines);
1524
/* Put a nl at the start. */
1525
catchar (&buffer, '\n');
1527
read_in (&buffer, stdin);
1528
remove_noncomments (&buffer, ptr);
1529
for (i = 1; i < (unsigned int) ac; i++)
1531
if (av[i][0] == '-')
1533
if (av[i][1] == 'f')
1539
f = fopen (av[i + 1], "r");
1542
fprintf (stderr, "Can't open the input file %s\n",
1551
else if (av[i][1] == 'i')
1553
internal_wanted = 1;
1555
else if (av[i][1] == 'w')
1563
write_buffer (stack + 0, stdout);
1566
fprintf (stderr, "finishing with current stack level %ld\n",