2 Copyright (C) 1990-2016 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
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.
99 /* Here is a string type ... */
101 typedef struct buffer
104 unsigned long write_idx
;
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 static void die (char *);
125 init_string_with_size (buffer
, size
)
129 buffer
->write_idx
= 0;
131 buffer
->ptr
= (char *) 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 if (buffer
->write_idx
!= 0
165 && fwrite (buffer
->ptr
, buffer
->write_idx
, 1, f
) != 1)
166 die ("cannot write output");
170 delete_string (buffer
)
181 return buffer
->ptr
+ idx
;
189 if (pos
>= buffer
->write_idx
)
191 return buffer
->ptr
[pos
];
199 if (buffer
->write_idx
== buffer
->size
)
202 buffer
->ptr
= (char *) realloc (buffer
->ptr
, buffer
->size
);
205 buffer
->ptr
[buffer
->write_idx
++] = ch
;
209 overwrite_string (dst
, src
)
214 dst
->size
= src
->size
;
215 dst
->write_idx
= src
->write_idx
;
220 catbuf (buffer
, buf
, len
)
225 if (buffer
->write_idx
+ len
>= buffer
->size
)
227 while (buffer
->write_idx
+ len
>= buffer
->size
)
229 buffer
->ptr
= (char *) realloc (buffer
->ptr
, buffer
->size
);
231 memcpy (buffer
->ptr
+ buffer
->write_idx
, buf
, len
);
232 buffer
->write_idx
+= len
;
236 cattext (buffer
, string
)
240 catbuf (buffer
, string
, (unsigned int) strlen (string
));
248 catbuf (dst
, src
->ptr
, src
->write_idx
);
252 skip_white_and_stars (src
, idx
)
257 while ((c
= at (src
, idx
)),
258 isspace ((unsigned char) c
)
260 /* Don't skip past end-of-comment or star as first
261 character on its line. */
262 && at (src
, idx
+1) != '/'
263 && at (src
, idx
-1) != '\n'))
269 skip_past_newline_1 (ptr
, idx
)
274 && at (ptr
, idx
) != '\n')
276 if (at (ptr
, idx
) == '\n')
281 /***********************************************************************/
283 string_type stack
[STACK
];
286 unsigned int idx
= 0; /* Pos in input buffer */
287 string_type
*ptr
; /* and the buffer */
288 typedef void (*stinst_type
)();
290 stinst_type sstack
[STACK
];
291 stinst_type
*ssp
= &sstack
[0];
293 long *isp
= &istack
[0];
295 typedef int *word_type
;
300 struct dict_struct
*next
;
307 typedef struct dict_struct dict_type
;
313 fprintf (stderr
, "%s\n", msg
);
321 die ("underflow in string stack");
322 if (tos
>= stack
+ STACK
)
323 die ("overflow in string stack");
330 die ("underflow in integer stack");
331 if (isp
>= istack
+ STACK
)
332 die ("overflow in integer stack");
336 static void exec (dict_type
*);
337 static void call (void);
338 static void remchar (void), strip_trailing_newlines (void), push_number (void);
339 static void push_text (void);
340 static void remove_noncomments (string_type
*, string_type
*);
341 static void print_stack_level (void);
342 static void paramstuff (void), translatecomments (void);
343 static void outputdots (void), courierize (void), bulletize (void);
344 static void do_fancy_stuff (void);
345 static int iscommand (string_type
*, unsigned int);
346 static int copy_past_newline (string_type
*, unsigned int, string_type
*);
347 static void icopy_past_newline (void), kill_bogus_lines (void), indent (void);
348 static void get_stuff_in_command (void), swap (void), other_dup (void);
349 static void drop (void), idrop (void);
350 static void icatstr (void), skip_past_newline (void), internalmode (void);
351 static void maybecatstr (void);
352 static char *nextword (char *, char **);
353 dict_type
*lookup_word (char *);
354 static void perform (void);
355 dict_type
*newentry (char *);
356 unsigned int add_to_definition (dict_type
*, stinst_type
);
357 void add_intrinsic (char *, void (*)());
358 void add_var (char *);
359 void compile (char *);
360 static void bang (void);
361 static void atsign (void);
362 static void hello (void);
363 static void stdout_ (void);
364 static void stderr_ (void);
365 static void print (void);
366 static void read_in (string_type
*, FILE *);
367 static void usage (void);
368 static void chew_exit (void);
383 stinst_type
*oldpc
= pc
;
385 e
= (dict_type
*) (pc
[1]);
399 strip_trailing_newlines ()
401 while ((isspace ((unsigned char) at (tos
, tos
->write_idx
- 1))
402 || at (tos
, tos
->write_idx
- 1) == '\n')
403 && tos
->write_idx
> 0)
425 cattext (tos
, *((char **) pc
));
429 /* This function removes everything not inside comments starting on
430 the first char of the line from the string, also when copying
431 comments, removes blank space and leading *'s.
432 Blank lines are turned into one blank line. */
435 remove_noncomments (src
, dst
)
439 unsigned int idx
= 0;
441 while (at (src
, idx
))
443 /* Now see if we have a comment at the start of the line. */
444 if (at (src
, idx
) == '\n'
445 && at (src
, idx
+ 1) == '/'
446 && at (src
, idx
+ 2) == '*')
450 idx
= skip_white_and_stars (src
, idx
);
452 /* Remove leading dot */
453 if (at (src
, idx
) == '.')
456 /* Copy to the end of the line, or till the end of the
458 while (at (src
, idx
))
460 if (at (src
, idx
) == '\n')
462 /* end of line, echo and scrape of leading blanks */
463 if (at (src
, idx
+ 1) == '\n')
467 idx
= skip_white_and_stars (src
, idx
);
469 else if (at (src
, idx
) == '*' && at (src
, idx
+ 1) == '/')
472 cattext (dst
, "\nENDDD\n");
477 catchar (dst
, at (src
, idx
));
490 fprintf (stderr
, "current string stack depth = %ld, ",
491 (long) (tos
- stack
));
492 fprintf (stderr
, "current integer stack depth = %ld\n",
493 (long) (isp
- istack
));
501 name PARAMS ((stuff));
517 /* Make sure that it's not already param'd or proto'd. */
519 || find (tos
, "PARAMS") || find (tos
, "PROTO") || !find (tos
, "("))
525 /* Find the open paren. */
526 for (openp
= 0; at (tos
, openp
) != '(' && at (tos
, openp
); openp
++)
530 /* Step back to the fname. */
532 while (fname
&& isspace ((unsigned char) at (tos
, fname
)))
535 && !isspace ((unsigned char) at (tos
,fname
))
536 && at (tos
,fname
) != '*')
541 /* Output type, omitting trailing whitespace character(s), if
543 for (len
= fname
; 0 < len
; len
--)
545 if (!isspace ((unsigned char) at (tos
, len
- 1)))
548 for (idx
= 0; idx
< len
; idx
++)
549 catchar (&out
, at (tos
, idx
));
551 cattext (&out
, "\n"); /* Insert a newline between type and fnname */
553 /* Output function name, omitting trailing whitespace
554 character(s), if any. */
555 for (len
= openp
; 0 < len
; len
--)
557 if (!isspace ((unsigned char) at (tos
, len
- 1)))
560 for (idx
= fname
; idx
< len
; idx
++)
561 catchar (&out
, at (tos
, idx
));
563 cattext (&out
, " PARAMS (");
565 for (idx
= openp
; at (tos
, idx
) && at (tos
, idx
) != ';'; idx
++)
566 catchar (&out
, at (tos
, idx
));
568 cattext (&out
, ");\n\n");
570 overwrite_string (tos
, &out
);
576 and *} into comments */
581 unsigned int idx
= 0;
585 while (at (tos
, idx
))
587 if (at (tos
, idx
) == '{' && at (tos
, idx
+ 1) == '*')
589 cattext (&out
, "/*");
592 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
594 cattext (&out
, "*/");
599 catchar (&out
, at (tos
, idx
));
604 overwrite_string (tos
, &out
);
609 /* Mod tos so that only lines with leading dots remain */
613 unsigned int idx
= 0;
617 while (at (tos
, idx
))
619 /* Every iteration begins at the start of a line. */
620 if (at (tos
, idx
) == '.')
626 while ((c
= at (tos
, idx
)) && c
!= '\n')
628 if (c
== '{' && at (tos
, idx
+ 1) == '*')
630 cattext (&out
, "/*");
633 else if (c
== '*' && at (tos
, idx
+ 1) == '}')
635 cattext (&out
, "*/");
646 catchar (&out
, '\n');
650 idx
= skip_past_newline_1 (tos
, idx
);
654 overwrite_string (tos
, &out
);
658 /* Find lines starting with . and | and put example around them on tos */
663 unsigned int idx
= 0;
668 while (at (tos
, idx
))
670 if (at (tos
, idx
) == '\n'
671 && (at (tos
, idx
+1 ) == '.'
672 || at (tos
, idx
+ 1) == '|'))
674 cattext (&out
, "\n@example\n");
679 while (at (tos
, idx
) && at (tos
, idx
) != '\n')
683 /* We are inside {} parameters of some command;
684 Just pass through until matching brace. */
685 if (at (tos
, idx
) == '{')
687 else if (at (tos
, idx
) == '}')
690 else if (command
!= 0)
692 if (at (tos
, idx
) == '{')
694 else if (!islower ((unsigned char) at (tos
, idx
)))
697 else if (at (tos
, idx
) == '@'
698 && islower ((unsigned char) at (tos
, idx
+ 1)))
702 else if (at (tos
, idx
) == '{' && at (tos
, idx
+ 1) == '*')
704 cattext (&out
, "/*");
708 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
710 cattext (&out
, "*/");
714 else if (at (tos
, idx
) == '{'
715 || at (tos
, idx
) == '}')
720 catchar (&out
, at (tos
, idx
));
723 catchar (&out
, '\n');
725 while (at (tos
, idx
) == '\n'
726 && ((at (tos
, idx
+ 1) == '.')
727 || (at (tos
, idx
+ 1) == '|')))
729 cattext (&out
, "@end example");
733 catchar (&out
, at (tos
, idx
));
738 overwrite_string (tos
, &out
);
742 /* Finds any lines starting with "o ", if there are any, then turns
743 on @itemize @bullet, and @items each of them. Then ends with @end
744 itemize, inplace at TOS*/
749 unsigned int idx
= 0;
754 while (at (tos
, idx
))
756 if (at (tos
, idx
) == '@'
757 && at (tos
, idx
+ 1) == '*')
762 else if (at (tos
, idx
) == '\n'
763 && at (tos
, idx
+ 1) == 'o'
764 && isspace ((unsigned char) at (tos
, idx
+ 2)))
768 cattext (&out
, "\n@itemize @bullet\n");
772 cattext (&out
, "\n@item\n");
777 catchar (&out
, at (tos
, idx
));
778 if (on
&& at (tos
, idx
) == '\n'
779 && at (tos
, idx
+ 1) == '\n'
780 && at (tos
, idx
+ 2) != 'o')
782 cattext (&out
, "@end itemize");
791 cattext (&out
, "@end itemize\n");
799 /* Turn <<foo>> into @code{foo} in place at TOS*/
804 unsigned int idx
= 0;
807 while (at (tos
, idx
))
809 if (at (tos
, idx
) == '<'
810 && at (tos
, idx
+ 1) == '<'
811 && !isspace ((unsigned char) at (tos
, idx
+ 2)))
813 /* This qualifies as a << startup. */
815 cattext (&out
, "@code{");
817 && at (tos
, idx
) != '>' )
819 catchar (&out
, at (tos
, idx
));
828 catchar (&out
, at (tos
, idx
));
838 /* A command is all upper case,and alone on a line. */
845 unsigned int len
= 0;
846 while (at (ptr
, idx
))
848 if (isupper ((unsigned char) at (ptr
, idx
))
849 || at (ptr
, idx
) == ' ' || at (ptr
, idx
) == '_')
854 else if (at (ptr
, idx
) == '\n')
867 copy_past_newline (ptr
, idx
, dst
)
874 while (at (ptr
, idx
) && at (ptr
, idx
) != '\n')
876 if (at (ptr
, idx
) == '\t')
878 /* Expand tabs. Neither makeinfo nor TeX can cope well with
882 while (++column
& 7);
886 catchar (dst
, at (ptr
, idx
));
892 catchar (dst
, at (ptr
, idx
));
899 icopy_past_newline ()
904 idx
= copy_past_newline (ptr
, idx
, tos
);
909 Take the string at the top of the stack, do some prettying. */
922 /* Drop leading nl. */
923 while (at (tos
, idx
) == '\n')
929 /* If the first char is a '.' prepend a newline so that it is
930 recognized properly later. */
931 if (at (tos
, idx
) == '.')
932 catchar (&out
, '\n');
934 /* Find the last char. */
935 while (at (tos
, idx
))
940 /* Find the last non white before the nl. */
943 while (idx
&& isspace ((unsigned char) at (tos
, idx
)))
947 /* Copy buffer upto last char, but blank lines before and after
953 if (at (tos
, c
) == '\n'
954 && at (tos
, c
+ 1) == '\n'
955 && at (tos
, c
+ 2) == '.')
957 /* Ignore two newlines before a dot. */
960 else if (at (tos
, c
) == '.' && sl
)
962 /* remember that this line started with a dot. */
965 else if (at (tos
, c
) == '\n'
966 && at (tos
, c
+ 1) == '\n'
970 /* Ignore two newlines when last line was dot. */
973 catchar (&out
, at (tos
, c
));
974 if (at (tos
, c
) == '\n')
991 catchar (&out
, '\n');
1006 while (at (tos
, idx
))
1008 switch (at (tos
, idx
))
1011 cattext (&out
, "\n");
1013 if (tab
&& at (tos
, idx
))
1015 cattext (&out
, " ");
1022 cattext (&out
, " ");
1024 cattext (&out
, "(");
1029 cattext (&out
, ")");
1035 catchar (&out
, at (tos
, idx
));
1044 delete_string (tos
);
1050 get_stuff_in_command ()
1056 while (at (ptr
, idx
))
1058 if (iscommand (ptr
, idx
))
1060 idx
= copy_past_newline (ptr
, idx
, tos
);
1082 catstr (tos
, tos
- 1);
1107 catstr (tos
, tos
+ 1);
1108 delete_string (tos
+ 1);
1113 skip_past_newline ()
1115 idx
= skip_past_newline_1 (ptr
, idx
);
1122 internal_mode
= *(isp
);
1131 if (internal_wanted
== internal_mode
)
1133 catstr (tos
- 1, tos
);
1135 delete_string (tos
);
1142 nextword (string
, word
)
1153 while (isspace ((unsigned char) *string
) || *string
== '-')
1157 while (*string
&& *string
!= '\n')
1169 word_start
= string
;
1176 if (*string
== '\\')
1182 while (*string
!= '"');
1186 while (!isspace ((unsigned char) *string
))
1194 *word
= (char *) malloc (length
+ 1);
1199 for (idx
= 0; idx
< length
; idx
++)
1201 if (src
[idx
] == '\\')
1202 switch (src
[idx
+ 1])
1210 *dst
++ = src
[idx
+ 1];
1234 dict_type
*ptr
= root
;
1237 if (strcmp (ptr
->word
, word
) == 0)
1242 fprintf (stderr
, "Can't find %s\n", word
);
1251 while (at (ptr
, idx
))
1253 /* It's worth looking through the command list. */
1254 if (iscommand (ptr
, idx
))
1259 (void) nextword (addr (ptr
, idx
), &next
);
1261 word
= lookup_word (next
);
1270 fprintf (stderr
, "warning, %s is not recognised\n", next
);
1271 skip_past_newline ();
1276 skip_past_newline ();
1284 dict_type
*new_d
= (dict_type
*) malloc (sizeof (dict_type
));
1288 new_d
->code
= (stinst_type
*) malloc (sizeof (stinst_type
));
1289 new_d
->code_length
= 1;
1290 new_d
->code_end
= 0;
1295 add_to_definition (entry
, word
)
1299 if (entry
->code_end
== entry
->code_length
)
1301 entry
->code_length
+= 2;
1303 (stinst_type
*) realloc ((char *) (entry
->code
),
1304 entry
->code_length
* sizeof (word_type
));
1306 entry
->code
[entry
->code_end
] = word
;
1308 return entry
->code_end
++;
1312 add_intrinsic (name
, func
)
1316 dict_type
*new_d
= newentry (name
);
1317 add_to_definition (new_d
, func
);
1318 add_to_definition (new_d
, 0);
1325 dict_type
*new_d
= newentry (name
);
1326 add_to_definition (new_d
, push_number
);
1327 add_to_definition (new_d
, (stinst_type
) (&(new_d
->var
)));
1328 add_to_definition (new_d
, 0);
1335 /* Add words to the dictionary. */
1337 string
= nextword (string
, &word
);
1338 while (string
&& *string
&& word
[0])
1340 if (strcmp (word
, "var") == 0)
1342 string
= nextword (string
, &word
);
1345 string
= nextword (string
, &word
);
1347 else if (word
[0] == ':')
1350 /* Compile a word and add to dictionary. */
1351 string
= nextword (string
, &word
);
1353 ptr
= newentry (word
);
1354 string
= nextword (string
, &word
);
1355 while (word
[0] != ';')
1360 /* got a string, embed magic push string
1362 add_to_definition (ptr
, push_text
);
1363 add_to_definition (ptr
, (stinst_type
) (word
+ 1));
1375 /* Got a number, embedd the magic push number
1377 add_to_definition (ptr
, push_number
);
1378 add_to_definition (ptr
, (stinst_type
) atol (word
));
1381 add_to_definition (ptr
, call
);
1382 add_to_definition (ptr
, (stinst_type
) lookup_word (word
));
1385 string
= nextword (string
, &word
);
1387 add_to_definition (ptr
, 0);
1388 string
= nextword (string
, &word
);
1392 fprintf (stderr
, "syntax error at %s\n", string
- 1);
1400 *(long *) ((isp
[0])) = isp
[-1];
1409 isp
[0] = *(long *) (isp
[0]);
1442 write_buffer (tos
, stdout
);
1444 write_buffer (tos
, stderr
);
1446 fprintf (stderr
, "print: illegal print destination `%ld'\n", *isp
);
1463 r
= fread (buff
, 1, sizeof (buff
), file
);
1464 catbuf (str
, buff
, r
);
1469 catbuf (str
, buff
, 1);
1475 fprintf (stderr
, "usage: -[d|i|g] <file >file\n");
1479 /* There is no reliable way to declare exit. Sometimes it returns
1480 int, and sometimes it returns void. Sometimes it changes between
1481 OS releases. Trying to get it declared correctly in the hosts file
1482 is a pointless waste of time. */
1499 init_string (&buffer
);
1500 init_string (&pptr
);
1501 init_string (stack
+ 0);
1505 add_intrinsic ("push_text", push_text
);
1506 add_intrinsic ("!", bang
);
1507 add_intrinsic ("@", atsign
);
1508 add_intrinsic ("hello", hello
);
1509 add_intrinsic ("stdout", stdout_
);
1510 add_intrinsic ("stderr", stderr_
);
1511 add_intrinsic ("print", print
);
1512 add_intrinsic ("skip_past_newline", skip_past_newline
);
1513 add_intrinsic ("catstr", icatstr
);
1514 add_intrinsic ("copy_past_newline", icopy_past_newline
);
1515 add_intrinsic ("dup", other_dup
);
1516 add_intrinsic ("drop", drop
);
1517 add_intrinsic ("idrop", idrop
);
1518 add_intrinsic ("remchar", remchar
);
1519 add_intrinsic ("get_stuff_in_command", get_stuff_in_command
);
1520 add_intrinsic ("do_fancy_stuff", do_fancy_stuff
);
1521 add_intrinsic ("bulletize", bulletize
);
1522 add_intrinsic ("courierize", courierize
);
1523 /* If the following line gives an error, exit() is not declared in the
1524 ../hosts/foo.h file for this host. Fix it there, not here! */
1525 /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1526 add_intrinsic ("exit", chew_exit
);
1527 add_intrinsic ("swap", swap
);
1528 add_intrinsic ("outputdots", outputdots
);
1529 add_intrinsic ("paramstuff", paramstuff
);
1530 add_intrinsic ("maybecatstr", maybecatstr
);
1531 add_intrinsic ("translatecomments", translatecomments
);
1532 add_intrinsic ("kill_bogus_lines", kill_bogus_lines
);
1533 add_intrinsic ("indent", indent
);
1534 add_intrinsic ("internalmode", internalmode
);
1535 add_intrinsic ("print_stack_level", print_stack_level
);
1536 add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines
);
1538 /* Put a nl at the start. */
1539 catchar (&buffer
, '\n');
1541 read_in (&buffer
, stdin
);
1542 remove_noncomments (&buffer
, ptr
);
1543 for (i
= 1; i
< (unsigned int) ac
; i
++)
1545 if (av
[i
][0] == '-')
1547 if (av
[i
][1] == 'f')
1553 f
= fopen (av
[i
+ 1], "r");
1556 fprintf (stderr
, "Can't open the input file %s\n",
1565 else if (av
[i
][1] == 'i')
1567 internal_wanted
= 1;
1569 else if (av
[i
][1] == 'w')
1577 write_buffer (stack
+ 0, stdout
);
1580 fprintf (stderr
, "finishing with current stack level %ld\n",
1581 (long) (tos
- stack
));
This page took 0.103404 seconds and 4 git commands to generate.