📄 chew.c
字号:
/* chew Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Contributed by steve chamberlain @cygnusThis file is part of BFD, the Binary File Descriptor library.This program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2 of the License, or(at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* Yet another way of extracting documentation from source. No, I haven't finished it yet, but I hope you people like it better than the old way sac Basically, this is a sort of string forth, maybe we should call it struth? You define new words thus: : <newword> <oldwords> ;*//* Primitives provided by the program: Two stacks are provided, a string stack and an integer stack. Internal state variables: internal_wanted - indicates whether `-i' was passed internal_mode - user-settable Commands: push_text ! - pop top of integer stack for address, pop next for value; store @ - treat value on integer stack as the address of an integer; push that integer on the integer stack after popping the "address" hello - print "hello\n" to stdout stdout - put stdout marker on TOS stderr - put stderr marker on TOS print - print TOS-1 on TOS (eg: "hello\n" stdout print) skip_past_newline catstr - fn icatstr copy_past_newline - append input, up to and including newline into TOS dup - fn other_dup drop - discard TOS idrop - ditto remchar - delete last character from TOS get_stuff_in_command do_fancy_stuff - translate <<foo>> to @code{foo} in TOS bulletize - if "o" lines found, prepend @itemize @bullet to TOS and @item to each "o" line; append @end itemize courierize - put @example around . and | lines, translate {* *} { } exit - fn chew_exit swap outputdots - strip out lines without leading dots paramstuff - convert full declaration into "PARAMS" form if not already maybecatstr - do catstr if internal_mode == internal_wanted, discard value in any case translatecomments - turn {* and *} into comment delimiters kill_bogus_lines - get rid of extra newlines indent internalmode - pop from integer stack, set `internalmode' to that value print_stack_level - print current stack depth to stderr strip_trailing_newlines - go ahead, guess... [quoted string] - push string onto string stack [word starting with digit] - push atol(str) onto integer stack A command must be all upper-case, and alone on a line. Foo. */#include "ansidecl.h"#include "sysdep.h"#include <assert.h>#include <stdio.h>#include <ctype.h>#define DEF_SIZE 5000#define STACK 50int internal_wanted;int internal_mode;int warning;/* Here is a string type ... */typedef struct buffer{ char *ptr; unsigned long write_idx; unsigned long size;} string_type;#ifdef __STDC__static void init_string_with_size (string_type *, unsigned int);static void init_string (string_type *);static int find (string_type *, char *);static void write_buffer (string_type *, FILE *);static void delete_string (string_type *);static char *addr (string_type *, unsigned int);static char at (string_type *, unsigned int);static void catchar (string_type *, int);static void overwrite_string (string_type *, string_type *);static void catbuf (string_type *, char *, unsigned int);static void cattext (string_type *, char *);static void catstr (string_type *, string_type *);#endifstatic voidinit_string_with_size (buffer, size) string_type *buffer; unsigned int size;{ buffer->write_idx = 0; buffer->size = size; buffer->ptr = malloc (size);}static voidinit_string (buffer) string_type *buffer;{ init_string_with_size (buffer, DEF_SIZE);}static intfind (str, what) string_type *str; char *what;{ unsigned int i; char *p; p = what; for (i = 0; i < str->write_idx && *p; i++) { if (*p == str->ptr[i]) p++; else p = what; } return (*p == 0);}static voidwrite_buffer (buffer, f) string_type *buffer; FILE *f;{ fwrite (buffer->ptr, buffer->write_idx, 1, f);}static voiddelete_string (buffer) string_type *buffer;{ free (buffer->ptr);}static char *addr (buffer, idx) string_type *buffer; unsigned int idx;{ return buffer->ptr + idx;}static charat (buffer, pos) string_type *buffer; unsigned int pos;{ if (pos >= buffer->write_idx) return 0; return buffer->ptr[pos];}static voidcatchar (buffer, ch) string_type *buffer; int ch;{ if (buffer->write_idx == buffer->size) { buffer->size *= 2; buffer->ptr = realloc (buffer->ptr, buffer->size); } buffer->ptr[buffer->write_idx++] = ch;}static voidoverwrite_string (dst, src) string_type *dst; string_type *src;{ free (dst->ptr); dst->size = src->size; dst->write_idx = src->write_idx; dst->ptr = src->ptr;}static voidcatbuf (buffer, buf, len) string_type *buffer; char *buf; unsigned int len;{ if (buffer->write_idx + len >= buffer->size) { while (buffer->write_idx + len >= buffer->size) buffer->size *= 2; buffer->ptr = realloc (buffer->ptr, buffer->size); } memcpy (buffer->ptr + buffer->write_idx, buf, len); buffer->write_idx += len;}static voidcattext (buffer, string) string_type *buffer; char *string;{ catbuf (buffer, string, (unsigned int) strlen (string));}static voidcatstr (dst, src) string_type *dst; string_type *src;{ catbuf (dst, src->ptr, src->write_idx);}static unsigned intskip_white_and_stars (src, idx) string_type *src; unsigned int idx;{ char c; while ((c = at (src, idx)), isspace ((unsigned char) c) || (c == '*' /* Don't skip past end-of-comment or star as first character on its line. */ && at (src, idx +1) != '/' && at (src, idx -1) != '\n')) idx++; return idx;}/***********************************************************************/string_type stack[STACK];string_type *tos;unsigned int idx = 0; /* Pos in input buffer */string_type *ptr; /* and the buffer */typedef void (*stinst_type)();stinst_type *pc;stinst_type sstack[STACK];stinst_type *ssp = &sstack[0];long istack[STACK];long *isp = &istack[0];typedef int *word_type;struct dict_struct{ char *word; struct dict_struct *next; stinst_type *code; int code_length; int code_end; int var;};typedef struct dict_struct dict_type;static voiddie (msg) char *msg;{ fprintf (stderr, "%s\n", msg); exit (1);}static voidcheck_range (){ if (tos < stack) die ("underflow in string stack"); if (tos >= stack + STACK) die ("overflow in string stack");}static voidicheck_range (){ if (isp < istack) die ("underflow in integer stack"); if (isp >= istack + STACK) die ("overflow in integer stack");}#ifdef __STDC__static void exec (dict_type *);static void call (void);static void remchar (void), strip_trailing_newlines (void), push_number (void);static void push_text (void);static void remove_noncomments (string_type *, string_type *);static void print_stack_level (void);static void paramstuff (void), translatecomments (void);static void outputdots (void), courierize (void), bulletize (void);static void do_fancy_stuff (void);static int iscommand (string_type *, unsigned int);static int copy_past_newline (string_type *, unsigned int, string_type *);static void icopy_past_newline (void), kill_bogus_lines (void), indent (void);static void get_stuff_in_command (void), swap (void), other_dup (void);static void drop (void), idrop (void);static void icatstr (void), skip_past_newline (void), internalmode (void);static void maybecatstr (void);static char *nextword (char *, char **);dict_type *lookup_word (char *);static void perform (void);dict_type *newentry (char *);unsigned int add_to_definition (dict_type *, stinst_type);void add_intrinsic (char *, void (*)());void add_var (char *);void compile (char *);static void bang (void);static void atsign (void);static void hello (void);static void stdout_ (void);static void stderr_ (void);static void print (void);static void read_in (string_type *, FILE *);static void usage (void);static void chew_exit (void);#endifstatic voidexec (word) dict_type *word;{ pc = word->code; while (*pc) (*pc) ();}static voidcall (){ stinst_type *oldpc = pc; dict_type *e; e = (dict_type *) (pc[1]); exec (e); pc = oldpc + 2;}static voidremchar (){ if (tos->write_idx) tos->write_idx--; pc++;}static voidstrip_trailing_newlines (){ while ((isspace ((unsigned char) at (tos, tos->write_idx - 1)) || at (tos, tos->write_idx - 1) == '\n') && tos->write_idx > 0) tos->write_idx--; pc++;}static voidpush_number (){ isp++; icheck_range (); pc++; *isp = (long) (*pc); pc++;}static voidpush_text (){ tos++; check_range (); init_string (tos); pc++; cattext (tos, *((char **) pc)); pc++;}/* This function removes everything not inside comments starting on the first char of the line from the string, also when copying comments, removes blank space and leading *'s. Blank lines are turned into one blank line. */static voidremove_noncomments (src, dst) string_type *src; string_type *dst;{ unsigned int idx = 0; while (at (src, idx)) { /* Now see if we have a comment at the start of the line. */ if (at (src, idx) == '\n' && at (src, idx + 1) == '/' && at (src, idx + 2) == '*') { idx += 3; idx = skip_white_and_stars (src, idx); /* Remove leading dot */ if (at (src, idx) == '.') idx++; /* Copy to the end of the line, or till the end of the comment. */ while (at (src, idx)) { if (at (src, idx) == '\n') { /* end of line, echo and scrape of leading blanks */ if (at (src, idx + 1) == '\n') catchar (dst, '\n'); catchar (dst, '\n'); idx++; idx = skip_white_and_stars (src, idx); } else if (at (src, idx) == '*' && at (src, idx + 1) == '/') { idx += 2; cattext (dst, "\nENDDD\n"); break; } else { catchar (dst, at (src, idx)); idx++; } } } else idx++; }}static voidprint_stack_level (){ fprintf (stderr, "current string stack depth = %d, ", tos - stack); fprintf (stderr, "current integer stack depth = %d\n", isp - istack); pc++;}/* turn: foobar name(stuff); into: foobar name PARAMS ((stuff)); and a blank line. */static voidparamstuff (){ unsigned int openp; unsigned int fname; unsigned int idx; unsigned int len; string_type out; init_string (&out);#define NO_PARAMS 1 /* Make sure that it's not already param'd or proto'd. */ if (NO_PARAMS || find (tos, "PARAMS") || find (tos, "PROTO") || !find (tos, "(")) { catstr (&out, tos); } else { /* Find the open paren. */ for (openp = 0; at (tos, openp) != '(' && at (tos, openp); openp++) ; fname = openp; /* Step back to the fname. */ fname--; while (fname && isspace ((unsigned char) at (tos, fname))) fname--; while (fname && !isspace ((unsigned char) at (tos,fname)) && at (tos,fname) != '*') fname--; fname++; /* Output type, omitting trailing whitespace character(s), if any. */ for (len = fname; 0 < len; len--) { if (!isspace ((unsigned char) at (tos, len - 1))) break; } for (idx = 0; idx < len; idx++) catchar (&out, at (tos, idx)); cattext (&out, "\n"); /* Insert a newline between type and fnname */ /* Output function name, omitting trailing whitespace character(s), if any. */ for (len = openp; 0 < len; len--) { if (!isspace ((unsigned char) at (tos, len - 1))) break; } for (idx = fname; idx < len; idx++) catchar (&out, at (tos, idx)); cattext (&out, " PARAMS ("); for (idx = openp; at (tos, idx) && at (tos, idx) != ';'; idx++) catchar (&out, at (tos, idx)); cattext (&out, ");\n\n"); } overwrite_string (tos, &out); pc++;}/* turn {* and *} into comments */static voidtranslatecomments (){ unsigned int idx = 0; string_type out; init_string (&out); while (at (tos, idx)) { if (at (tos, idx) == '{' && at (tos, idx + 1) == '*') { cattext (&out, "/*"); idx += 2; } else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}') { cattext (&out, "*/"); idx += 2; } else { catchar (&out, at (tos, idx)); idx++; } } overwrite_string (tos, &out); pc++;}#if 0/* This is not currently used. *//* turn everything not starting with a . into a comment */static voidmanglecomments (){ unsigned int idx = 0; string_type out; init_string (&out); while (at (tos, idx)) { if (at (tos, idx) == '\n' && at (tos, idx + 1) == '*') { cattext (&out, " /*"); idx += 2; } else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}') { cattext (&out, "*/"); idx += 2; } else { catchar (&out, at (tos, idx)); idx++; } } overwrite_string (tos, &out); pc++;}#endif/* Mod tos so that only lines with leading dots remain */static voidoutputdots (){ unsigned int idx = 0; string_type out; init_string (&out); while (at (tos, idx)) { if (at (tos, idx) == '\n' && at (tos, idx + 1) == '.') { char c; idx += 2; while ((c = at (tos, idx)) && c != '\n') { if (c == '{' && at (tos, idx + 1) == '*') { cattext (&out, "/*"); idx += 2; } else if (c == '*' && at (tos, idx + 1) == '}') { cattext (&out, "*/"); idx += 2; } else { catchar (&out, c); idx++; } } catchar (&out, '\n'); } else { idx++; } } overwrite_string (tos, &out); pc++;}/* Find lines starting with . and | and put example around them on tos */static voidcourierize (){ string_type out; unsigned int idx = 0; int command = 0; init_string (&out); while (at (tos, idx)) { if (at (tos, idx) == '\n' && (at (tos, idx +1 ) == '.' || at (tos, idx + 1) == '|')) { cattext (&out, "\n@example\n"); do { idx += 2; while (at (tos, idx) && at (tos, idx) != '\n') { if (command > 1) { /* We are inside {} parameters of some command; Just pass through until matching brace. */ if (at (tos, idx) == '{') ++command; else if (at (tos, idx) == '}') --command; } else if (command != 0) { if (at (tos, idx) == '{') ++command; else if (!islower ((unsigned char) at (tos, idx))) --command; } else if (at (tos, idx) == '@' && islower ((unsigned char) at (tos, idx + 1))) { ++command; } else if (at (tos, idx) == '{' && at (tos, idx + 1) == '*') { cattext (&out, "/*"); idx += 2; continue; } else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}') { cattext (&out, "*/"); idx += 2; continue; } else if (at (tos, idx) == '{' || at (tos, idx) == '}') { catchar (&out, '@'); } catchar (&out, at (tos, idx)); idx++; } catchar (&out, '\n'); } while (at (tos, idx) == '\n' && ((at (tos, idx + 1) == '.') || (at (tos, idx + 1) == '|'))) ; cattext (&out, "@end example"); } else { catchar (&out, at (tos, idx)); idx++; } } overwrite_string (tos, &out); pc++;}/* Finds any lines starting with "o ", if there are any, then turns on @itemize @bullet, and @items each of them. Then ends with @end itemize, inplace at TOS*/static voidbulletize (){ unsigned int idx = 0; int on = 0; string_type out; init_string (&out); while (at (tos, idx)) { if (at (tos, idx) == '@' && at (tos, idx + 1) == '*') { cattext (&out, "*"); idx += 2; } else if (at (tos, idx) == '\n' && at (tos, idx + 1) == 'o' && isspace ((unsigned char) at (tos, idx + 2))) { if (!on) { cattext (&out, "\n@itemize @bullet\n"); on = 1; } cattext (&out, "\n@item\n"); idx += 3; } else { catchar (&out, at (tos, idx)); if (on && at (tos, idx) == '\n' && at (tos, idx + 1) == '\n' && at (tos, idx + 2) != 'o') { cattext (&out, "@end itemize"); on = 0; } idx++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -