diff options
author | bothner <bothner@138bc75d-0d04-0410-961f-82ee72b054a4> | 1993-07-26 00:11:20 +0000 |
---|---|---|
committer | bothner <bothner@138bc75d-0d04-0410-961f-82ee72b054a4> | 1993-07-26 00:11:20 +0000 |
commit | 41f8c0bb2babab1eddb059f6fb78b8f0da65a822 (patch) | |
tree | d62b715f580e46dc24f6184c8c26da60ec50313d | |
parent | a0f2061cf6523e9ac06fdee65cda04727146904f (diff) | |
download | gcc-41f8c0bb2babab1eddb059f6fb78b8f0da65a822.tar.gz |
Initial revision
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@4986 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/fix-header.c | 674 | ||||
-rw-r--r-- | gcc/gen-protos.c | 141 | ||||
-rw-r--r-- | gcc/scan-decls.c | 170 | ||||
-rw-r--r-- | gcc/scan.c | 274 | ||||
-rw-r--r-- | gcc/scan.h | 75 |
5 files changed, 1334 insertions, 0 deletions
diff --git a/gcc/fix-header.c b/gcc/fix-header.c new file mode 100644 index 00000000000..4d3dfefb549 --- /dev/null +++ b/gcc/fix-header.c @@ -0,0 +1,674 @@ +/* patch-header.c - Make C header file suitable for C++. + Copyright (C) 1993 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, 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 of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This program massages a system include file (such as stdio.h), + into a form more conformant with ANSI/POSIX, and more suitable for C++: + + * extern "C" { ... } braces are added (inside #ifndef __cplusplus), + if they seem to be needed. These prevcnt C++ compilers from name + mangling the functions inside the braces. + + * If an old-style incomplete function declaration is seen (without + an argument list), and it is a "standard" function listed in + the file sys-protos.h (and with a non-empty argument list), then + the declaration is converted to a complete prototype by replacing + the empty parameter list with the argument lust from sys-protos.h. + + * The program can be given a list of (names of) required standard + functions (such as fclose for stdio.h). If a reqquired function + is not seen in the input, then a prototype for it will be + written to the output. + + * If all of the non-comment code of the original file is protected + against multiple inclusion: + #ifndef FOO + #define FOO + <body of include file> + #endif + then extra matter added to the include file is placed inside the <body>. + + * If the input file is OK (nothing needs to be done); + the output file is not written (nor removed if it exists). + + There are also some special actions that are done for certain + well-known standard include files: + + * If argv[1] is "sys/stat.h", the Posix.1 macros + S_ISBLK, S_ISCHR, S_ISDIR, S_ISFIFO, S_ISLNK, S_ISREG are added if + they were missing, and the corresponding "traditional" S_IFxxx + macros were defined. + + * If argv[1] is "errno.h", errno is declared if it was missing. + + * TODO: The input file should be read complete into memory, because: + a) it needs to be scanned twice anyway, and + b) it would be nice to allow update in place. + + Usage: + patch-header FOO.H INFILE.H OUTFILE.H REQUIRED_FUNCS <SCAN-FILE + where: + * FOO.H is the relative file name of the include file, + as it would be #include'd by a C file. (E.g. stdio.h) + * INFILE.H is a full pathname for the input file (e.g. /usr/include/stdio.h) + * OUTFILE.H is the full pathname for where to write the output file, + if anything needs to be done. (e.g. ./include/stdio.h) + * SCAN-FILE is the output of the scan-decls program. + * REQUIRED_FUNCS is a list of required function (e.g. fclose for stdio.h). + + Written by Per Bothner <bothner@cygnus.com>, July 1993. */ + +#include <stdio.h> +#include <ctype.h> +#include "obstack.h" +#include "scan.h" + +extern char *strcpy(); +sstring buf; +int verbose = 0; +int partial_count = 0; +int missing_extern_C_count = 0; +int missing_extra_stuff = 0; + +#include "xsys-protos.h" + +/* Certain standard files get extra treatment */ + +enum special_file +{ + no_special, + errno_special, + sys_stat_special +}; + +enum special_file special_file_handling = no_special; + +/* The following are only used when handling sys/stat.h */ +/* They are set if the corresponding macro has been seen. */ +int seen_S_IFBLK = 0, seen_S_ISBLK = 0; +int seen_S_IFCHR = 0, seen_S_ISCHR = 0; +int seen_S_IFDIR = 0, seen_S_ISDIR = 0; +int seen_S_IFIFO = 0, seen_S_ISFIFO = 0; +int seen_S_IFLNK = 0, seen_S_ISLNK = 0; +int seen_S_IFREG = 0, seen_S_ISREG = 0; + +/* The following are only used when handling errno.h */ +int seen_errno = 0; + +/* Wrapper around free, to avoid prototype clashes. */ + +void xfree (ptr) + char *ptr; +{ + free(ptr); +} + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free xfree +struct obstack scan_file_obstack; + +/* NOTE: If you edit this, also edit gen-protos.c !! */ +struct fn_decl * +lookup_std_proto (name) + char *name; +{ + int i = hash(name) % HASH_SIZE; + int i0 = i; + for (;;) + { + struct fn_decl *fn; + if (hash_tab[i] == 0) + return NULL; + fn = &std_protos[hash_tab[i]]; + if (strcmp (fn->fname, name) == 0) + return fn; + i = (i+1) % HASH_SIZE; + if (i == i0) + abort(); + } +} + +char *inc_filename; +int inc_filename_length; +char *progname = "patch-header"; +FILE *outf; +sstring buf; +sstring line; + +int lbrac_line, rbrac_line; + +char **required_functions; +int required_unseen_count; + +int +write_lbrac () +{ + fprintf (outf, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); + + if (partial_count) + { + fprintf (outf, "#ifndef _PARAMS\n"); + fprintf (outf, "#if defined(__STDC__) || defined(__cplusplus)\n"); + fprintf (outf, "#define _PARAMS(ARGS) ARGS\n"); + fprintf (outf, "#else\n"); + fprintf (outf, "#define _PARAMS(ARGS) ()\n"); + fprintf (outf, "#endif\n#endif /* _PARAMS */\n"); + } +} + +struct partial_proto +{ + struct partial_proto *next; + char *fname; /* name of function */ + char *rtype; /* return type */ + struct fn_decl *fn; + int line_seen; +}; + +struct partial_proto *partial_proto_list = NULL; + +struct partial_proto required_dummy_proto; +#define REQUIRED(FN) ((FN)->partial == &required_dummy_proto) +#define SET_REQUIRED(FN) ((FN)->partial = &required_dummy_proto) +#define CLEAR_REQUIRED(FN) ((FN)->partial = 0) + +void +read_scan_file (scan_file) + FILE *scan_file; +{ + char **rptr; + int i; + obstack_init(&scan_file_obstack); + + for (;;) + { + struct partial_proto *partial; + struct fn_decl *fn; + int ch; + char *ptr, *fname, *extern_C, *rtype, *args, *file_seen, *line_seen; + line.ptr = line.base; + ch = read_upto (scan_file, &line, '\n'); + if (ch == EOF) + break; + + fname = line.base; + for (ptr = fname; *ptr != ';'; ) ptr++; + *ptr = 0; + extern_C = ptr + 1; + for (ptr = extern_C; *ptr != ';'; ) ptr++; + *ptr = 0; + + if (*extern_C == 'X') + { + switch (special_file_handling) + { + case errno_special: + if (strcmp (fname, "errno") == 0) seen_errno++; + break; + } + continue; + } + + if (*extern_C == 'M') + { + /* The original include file defines fname as a macro. */ + fn = lookup_std_proto (fname); + + /* Since fname is a macro, don't require a prototype for it. */ + if (fn && REQUIRED (fn)) + { + CLEAR_REQUIRED(fn); + required_unseen_count--; + } + + switch (special_file_handling) + { + case errno_special: + if (strcmp (fname, "errno") == 0) seen_errno++; + break; + case sys_stat_special: + if (fname[0] == 'S' && fname[1] == '_') + { + if (strcmp (fname, "S_IFBLK") == 0) seen_S_IFBLK++; + else if (strcmp (fname, "S_ISBLK") == 0) seen_S_ISBLK++; + else if (strcmp (fname, "S_IFCHR") == 0) seen_S_IFCHR++; + else if (strcmp (fname, "S_ISCHR") == 0) seen_S_ISCHR++; + else if (strcmp (fname, "S_IFDIR") == 0) seen_S_IFDIR++; + else if (strcmp (fname, "S_ISDIR") == 0) seen_S_ISDIR++; + else if (strcmp (fname, "S_IFIFO") == 0) seen_S_IFIFO++; + else if (strcmp (fname, "S_ISFIFO") == 0) seen_S_ISFIFO++; + else if (strcmp (fname, "S_IFLNK") == 0) seen_S_IFLNK++; + else if (strcmp (fname, "S_ISLNK") == 0) seen_S_ISLNK++; + else if (strcmp (fname, "S_IFREG") == 0) seen_S_IFREG++; + else if (strcmp (fname, "S_ISREG") == 0) seen_S_ISREG++; + } + break; + } + continue; + } + + rtype = ptr + 1; + for (ptr = rtype; *ptr != ';'; ) ptr++; + *ptr = 0; + args = ptr + 1; + for (ptr = args; *ptr != ';'; ) ptr++; + *ptr = 0; + file_seen = ptr + 1; + for (ptr = file_seen; *ptr != ';'; ) ptr++; + *ptr = 0; + line_seen = ptr + 1; + for (ptr = line_seen; *ptr != ';'; ) ptr++; + *ptr = 0; + + if (extern_C[0] == 'f') + missing_extern_C_count++; + + fn = lookup_std_proto (fname); + + /* Remove the function from the list of required function. */ + if (fn && REQUIRED (fn)) + { + CLEAR_REQUIRED(fn); + required_unseen_count--; + } + + /* If we have a full prototype, we're done. */ + if (args[0] != '\0') + continue; + + /* If the partial prototype was included from some other file, + we don't need to patch it up (in this run). */ + i = strlen (file_seen); + if (i < inc_filename_length + || strcmp (inc_filename, file_seen + (i - inc_filename_length)) != 0) + continue; + + if (fn == NULL) + continue; + if (fn->fname[0] == '\0' || strcmp(fn->fname, "void") == 0) + continue; + + /* We only have a partial function declaration, + so remember that we have to add a complete prototype. */ + partial_count++; + partial = (struct partial_proto*) + obstack_alloc (&scan_file_obstack, sizeof(struct partial_proto)); + partial->fname + = obstack_copy0 (&scan_file_obstack, fname, strlen (fname)); + partial->rtype + = obstack_copy0 (&scan_file_obstack, rtype, strlen (rtype)); + partial->line_seen = atoi(line_seen); + partial->fn = fn; + fn->partial = partial; + partial->next = partial_proto_list; + partial_proto_list = partial; + if (verbose) + { + fprintf (stderr, "(%s: %s non-prototype function declaration.)\n", + inc_filename, fname); + } + } + + if (missing_extern_C_count + required_unseen_count + partial_count + + missing_extra_stuff == 0) + { + if (verbose) + fprintf (stderr, "%s: OK, nothing needs to be done.\n", inc_filename); + exit (0); + } + if (required_unseen_count) + fprintf (stderr, "%s: %d missing function declarations.\n", + inc_filename, required_unseen_count); + if (partial_count) + fprintf (stderr, "%s: %d non-prototype function declarations.\n", + inc_filename, partial_count); + if (missing_extern_C_count) + fprintf (stderr, "%s: %d declarations not protected by extern \"C\".\n", + inc_filename, missing_extern_C_count); +} + +write_rbrac () +{ + struct fn_decl *fn; + char **rptr; + register struct partial_proto *partial; + + if (required_unseen_count) + fprintf (outf, "#if defined(__STDC__) || defined(__cplusplus)\n"); + + /* Now we print out prototypes for those functions that we haven't seen. */ + for (rptr = required_functions; *rptr; rptr++) + { + fn = lookup_std_proto (*rptr); + if (fn == NULL || !REQUIRED (fn)) + continue; + fprintf (outf, "extern %s %s (%s);\n", + fn->rtype, fn->fname, fn->params); + } + if (required_unseen_count) + fprintf (outf, + "#endif /* defined(__STDC__) || defined(__cplusplus) */\n"); + + switch (special_file_handling) + { + case errno_special: + if (!seen_errno) + fprintf (outf, "extern int errno;\n"); + break; + case sys_stat_special: + if (!seen_S_ISBLK && seen_S_IFBLK) + fprintf (outf, + "#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)\n"); + if (!seen_S_ISCHR && seen_S_IFCHR) + fprintf (outf, + "#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)\n"); + if (!seen_S_ISDIR && seen_S_IFDIR) + fprintf (outf, + "#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)\n"); + if (!seen_S_ISFIFO && seen_S_IFIFO) + fprintf (outf, + "#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)\n"); + if (!seen_S_ISLNK && seen_S_IFLNK) + fprintf (outf, + "#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)\n"); + if (!seen_S_ISREG && seen_S_IFREG) + fprintf (outf, + "#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)\n"); + break; + } + + + fprintf (outf, "#ifdef __cplusplus\n}\n#endif\n"); +} + +char * +strdup (str) + char *str; +{ + return strcpy((char*)malloc (strlen (str) + 1), str); +} + +/* Returns 1 iff the file is properly protected from multiple inclusion: + #ifndef PROTECT_NAME + #define PROTECT_NAME + #endif + + */ + +int +check_protection (inf, ifndef_line, endif_line) + FILE *inf; + int *ifndef_line, *endif_line; +{ + int c; + int if_nesting = 1; /* Level of nesting of #if's */ + char *protect_name = NULL; /* Identifier following initial #ifndef */ + int define_seen = 0; + + /* Skip initial white space (including comments). */ + for (;; lineno++) + { + c = skip_spaces (inf, ' '); + if (c == EOF) + return 0; + if (c != '\n') + break; + } + if (c != '#') + return 0; + c = scan_ident (inf, &buf, skip_spaces (inf, ' ')); + if (SSTRING_LENGTH(&buf) == 0 || strcmp (buf.base, "ifndef") != 0) + return 0; + + /* So far so good: We've seen an initial #ifndef. */ + *ifndef_line = lineno; + c = scan_ident (inf, &buf, skip_spaces (inf, c)); + if (SSTRING_LENGTH(&buf) == 0 || c == EOF) + return 0; + protect_name = strdup (buf.base); + + ungetc (c, inf); + c = read_upto (inf, &buf, '\n'); + if (c == EOF) + return 0; + lineno++; + + for (;;) + { + c = skip_spaces(inf, ' '); + if (c == EOF) + return 0; + if (c == '\n') + { + lineno++; + continue; + } + if (c != '#') + goto skip_to_eol; + c = scan_ident (inf, &buf, skip_spaces (inf, ' ')); + if (SSTRING_LENGTH(&buf) == 0) + ; + else if (!strcmp (buf.base, "ifndef") + || !strcmp (buf.base, "ifdef") || !strcmp (buf.base, "if")) + { + if_nesting++; + } + else if (!strcmp (buf.base, "endif")) + { + if_nesting--; + if (if_nesting == 0) + break; + } + else if (!strcmp (buf.base, "else")) + { + if (if_nesting == 1) + return 0; + } + else if (!strcmp (buf.base, "define")) + { + if (if_nesting != 1) + goto skip_to_eol; + c = skip_spaces (inf, c); + c = scan_ident (inf, &buf, c); + if (buf.base[0] > 0 && strcmp(buf.base, protect_name) == 0) + define_seen = 1; + } + skip_to_eol: + for (;;) + { + if (c == '\n' || c == EOF) + break; + c = getc (inf); + } + if (c == EOF) + return 0; + lineno++; + } + + if (!define_seen) + return 0; + *endif_line = lineno; + /* Skip final white space (including comments). */ + for (;;) + { + c = skip_spaces (inf, ' '); + if (c == EOF) + break; + if (c != '\n') + return 0; + } + + return 1; +} + +int +main(argc, argv) + int argc; + char **argv; +{ + FILE *inf; + int c; + int i, done; + char *cptr, *cptr0, **pptr; + int ifndef_line; + int endif_line;; + + + if (argv[0] && argv[0][0]) + progname = argv[0]; + + if (argc < 4) + { + fprintf (stderr, "%s: Usage: foo.h infile.h outfile.h req_funcs <scan-file-name\n", + progname); + exit (-1); + } + + inc_filename = argv[1]; + inc_filename_length = strlen (inc_filename); + if (strcmp (inc_filename, "sys/stat.h") == 0) + special_file_handling = sys_stat_special; + else if (strcmp (inc_filename, "errno.h") == 0) + special_file_handling = errno_special, missing_extra_stuff++; + + /* Calculate an upper bound of the number of function names in argv[4] */ + for (i = 1, cptr = argv[4]; *cptr; cptr++) + if (*cptr == ' ') i++; + /* Find the list of prototypes required for this include file. */ + required_functions = (char**)xmalloc((i+1) * sizeof(char*)); + for (cptr = argv[4], cptr0 = cptr, pptr = required_functions, done = 0; + !done; cptr++) + { + done = *cptr == '\0'; + if (*cptr == ' ' || done) + { + *cptr = '\0'; + if (cptr > cptr0) + { + struct fn_decl *fn = lookup_std_proto(cptr0); + *pptr++ = cptr0; + if (fn == NULL) + fprintf (stderr, "Internal error: No prototype for %s\n", + cptr0); + else + SET_REQUIRED(fn); + } + cptr0 = cptr + 1; + } + } + required_unseen_count = pptr - required_functions; + *pptr = 0; + + read_scan_file (stdin); + + inf = fopen (argv[2], "r"); + if (inf == NULL) + { + fprintf (stderr, "%s: Cannot open '%s' for reading -", + progname, argv[2]); + perror (NULL); + exit (-1); + } + + outf = fopen (argv[3], "w"); + if (outf == NULL) + { + fprintf (stderr, "%s: Cannot open '%s' for writing -", + progname, argv[3]); + perror (NULL); + exit (-1); + } + + if (check_protection (inf, &ifndef_line, &endif_line)) + { +#if 0 + fprintf(stderr, "#ifndef %s on line %d; #endif on line %d\n", + protect_name, ifndef_line, endif_line); +#endif + lbrac_line = ifndef_line+1; + rbrac_line = endif_line; + } + else + { + lbrac_line = 1; + rbrac_line = -1; + } + + fseek(inf, 0, 0); + lineno = 1; + + for (;;) + { + if (lineno == lbrac_line) + write_lbrac (); + if (lineno == rbrac_line) + write_rbrac (); + for (;;) + { + struct fn_decl *fn; + c = getc (inf); + if (c == EOF) + break; + if (isalpha (c) || c == '_') + { + struct partial_proto *partial; + ungetc (c, inf); + if (get_token (inf, &buf) != IDENTIFIER_TOKEN) + abort (); + fputs (buf.base, outf); + fn = lookup_std_proto (buf.base); + /* We only want to edit the declaration matching the one + seen by scan-decls, as there can be multiple + declarations, selected by #ifdef __STDC__ or whatever. */ + if (fn && fn->partial && fn->partial->line_seen == lineno) + { + c = skip_spaces (inf, ' '); + if (c == EOF) + break; + if (c == '(') + { + c = skip_spaces (inf, ' '); + if (c == ')') + { + fprintf (outf, " _PARAMS((%s))", fn->params); + } + else + { + putc ('(', outf); + ungetc (c, inf); + } + } + else + putc (c, outf); + } + } + else + putc (c, outf); + if (c == '\n') + break; + } + if (c == EOF) + break; + lineno++; + } + if (rbrac_line < 0) + write_rbrac (); + + fclose (inf); + fclose (outf); + + return 0; +} diff --git a/gcc/gen-protos.c b/gcc/gen-protos.c new file mode 100644 index 00000000000..ace6d1267d8 --- /dev/null +++ b/gcc/gen-protos.c @@ -0,0 +1,141 @@ +/* gen-protos.c - massages a list of prototypes, for use by fixproto. + Copyright (C) 1993 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, 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 of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include "scan.h" + +#define HASH_SIZE 2503 /* a prime */ + +int hash_tab[HASH_SIZE]; + +sstring linebuf; + +int +main (argc, argv) + int argc; + char** argv; +{ + FILE *inf = stdin; + FILE *outf = stdout; + int next_index = 0; + int i, i0; + + fprintf (outf, "struct fn_decl std_protos[] = {\n"); + + for (;;) + { + int c = skip_spaces (inf, ' '); + int param_nesting = 1; + char *param_start, *param_end, *decl_start, + *name_start, *name_end; + register char *ptr; + if (c == EOF) + break; + linebuf.ptr = linebuf.base; + ungetc (c, inf); + c = read_upto (inf, &linebuf, '\n'); + if (linebuf.base[0] == '#') /* skip cpp command */ + continue; + if (linebuf.base[0] == '\0') /* skip empty line */ + continue; + + ptr = linebuf.ptr - 1; + while (*ptr == ' ' || *ptr == '\t') ptr--; + if (*ptr-- != ';') + { + fprintf (stderr, "Funny input line: %s\n", linebuf.base); + continue; + } + while (*ptr == ' ' || *ptr == '\t') ptr--; + if (*ptr != ')') + { + fprintf (stderr, "Funny input line: %s\n", linebuf.base); + continue; + } + param_end = ptr; + for (;;) + { + int c = *--ptr; + if (c == '(' && --param_nesting == 0) + break; + else if (c == ')') + param_nesting++; + } + param_start = ptr+1; + + ptr--; + while (*ptr == ' ' || *ptr == '\t') ptr--; + + if (!isalnum (*ptr)) + { + fprintf (stderr, "%s: Can't handle this complex prototype: %s\n", + argv[0], linebuf.base); + continue; + } + name_end = ptr+1; + + while (isalnum (*ptr) || *ptr == '_') --ptr; + name_start = ptr+1; + while (*ptr == ' ' || *ptr == '\t') ptr--; + ptr[1] = 0; + *name_end = 0; + *param_end = 0; + *name_end = 0; + + decl_start = linebuf.base; + if (strncmp (decl_start, "typedef ", 8) == 0) + continue; + if (strncmp (decl_start, "extern ", 7) == 0) + decl_start += 7; + + + /* NOTE: If you edit this, + also edit lookup_std_proto in patch-header.c !! */ + i = hash(name_start) % HASH_SIZE; + i0 = i; + if (hash_tab[i] != 0) + { + for (;;) + { + i = (i+1) % HASH_SIZE; + if (i == i0) + abort(); + if (hash_tab[i] == 0) + break; + } + } + hash_tab[i] = next_index; + + fprintf (outf, " {\"%s\", \"%s\", \"%s\" }, /* ix: %d, i0: %d */\n", + name_start, decl_start, param_start, i, i0); + + next_index++; + + if (c == EOF) + break; + } + fprintf (outf, "{0, 0, 0}\n};\n"); + + + fprintf (outf, "#define HASH_SIZE %d\n", HASH_SIZE); + fprintf (outf, "short hash_tab[HASH_SIZE] = {\n"); + for (i = 0; i < HASH_SIZE; i++) + fprintf (outf, " %d,\n", hash_tab[i]); + fprintf (outf, "};\n"); + + return 0; +} diff --git a/gcc/scan-decls.c b/gcc/scan-decls.c new file mode 100644 index 00000000000..4e2f1943005 --- /dev/null +++ b/gcc/scan-decls.c @@ -0,0 +1,170 @@ +/* scan-decls.c - Extracts declarations from cpp output. + Copyright (C) 1993 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, 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 of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This filter scans a C source file (actually, the output of cpp). + It looks for function declaration. For each declaration, it prints: + + NAME;C;RTYPE;ARGS;FILENAME;LINENO; + + NAME is the function's name. + C is "F" if the declaration is nested inside 'extern "C"' braces; + otherwise "f". + RTYPE is the function's return type. + ARGS is the function's argument list. + FILENAME and LINENO is where the declarations was seen + (taking #-directives into account). + + Also: + + NAME;M; + indicates that the macro NAME was seen (when invoked from fixproto). + NAME;X;TYPE; + indicates that 'extern TYPE NAME;' was seen. + + Written by Per Bothner <bothner@cygnus.com>, July 1993. + */ + +#include <stdio.h> +#include <ctype.h> +#include "scan.h" + +sstring buf; +sstring rtype; + +int brace_nesting = 0; + +/* The first extern_C_braces_length elements of extern_C_braces + indicate the (brace nesting levels of) left braces that were + prefixed by extern "C". */ +int extern_C_braces_length = 0; +char extern_C_braces[20]; +#define in_extern_C_brace (extern_C_braces_length>0) + +/* True if the function declaration currently being scanned is + prefixed by extern "C". */ +int current_extern_C = 0; + +int +main () +{ + FILE *fp = stdin; + int c; + int saw_extern; + + new_statement: + c = get_token (fp, &buf); + handle_statement: + current_extern_C = 0; + saw_extern = 0; + if (c == '}') + { + /* pop an 'extern "C"' nesting level, if appropriate */ + if (extern_C_braces_length + && extern_C_braces[extern_C_braces_length - 1] == brace_nesting) + extern_C_braces_length--; + brace_nesting--; + goto new_statement; + } + if (c == '{') + { + brace_nesting++; + goto new_statement; + } + if (c == EOF) + return 0; + if (c == ';') + goto new_statement; + if (c != IDENTIFIER_TOKEN) + goto new_statement; + rtype.ptr = rtype.base; + if (SSTRING_LENGTH (&buf) > 16 + && strncmp (buf.base, "__DEFINED_MACRO_", 16) == 0) + { + fprintf (stdout, "%s;M;\n", buf.base+16); + goto new_statement; + } + if (strcmp (buf.base, "extern") == 0) + { + saw_extern = 1; + c = get_token (fp, &buf); + if (c == STRING_TOKEN && strcmp (buf.base, "C") == 0) + { + current_extern_C = 1; + c = get_token (fp, &buf); + if (c == '{') + { + brace_nesting++; + extern_C_braces[extern_C_braces_length++] = brace_nesting; + goto new_statement; + } + c = get_token (fp, &buf); + } + } + for (;;) + { + int followingc = getc (fp); /* char following token in buf */ + if (c == IDENTIFIER_TOKEN) + { + int nextc = skip_spaces (fp, followingc); + if (nextc == '(') + { + int nesting = 1; + + MAKE_SSTRING_SPACE(&rtype, 1); + *rtype.ptr = 0; + + fprintf (stdout, "%s;%s;%s;", + buf.base, + in_extern_C_brace || current_extern_C ? "F" : "f", + rtype.base); + c = skip_spaces (fp, ' '); + for (;;) + { + if (c == '(') + nesting++; + else if (c == ')') + if (--nesting == 0) + break; + if (c == EOF) + break; + if (c == '\n') + c = ' '; + putc (c, stdout); + c = getc (fp); + } + fprintf (stdout, ";%s;%d;\n", + source_filename.base, source_lineno); + goto new_statement; + } + else if (nextc == ';' && saw_extern) + { + fprintf (stdout, "%s;X;%s;\n", buf.base, rtype.base); + goto handle_statement; + } + else + ungetc (nextc, fp); + } + else if (followingc != EOF) + ungetc (followingc, fp); + if (c == ';' || c == '{' || c == '}' || c == EOF) + goto handle_statement; + sstring_append (&rtype, &buf); + if (followingc == ' ' || followingc == '\t' || followingc == '\n') + SSTRING_PUT(&rtype, ' '); + c = get_token (fp, &buf); + } +} diff --git a/gcc/scan.c b/gcc/scan.c new file mode 100644 index 00000000000..a4980ea76f5 --- /dev/null +++ b/gcc/scan.c @@ -0,0 +1,274 @@ +/* scan.c - Utility functions for scan-decls and patch-header programs. + Copyright (C) 1993 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, 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 of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "scan.h" +#include <ctype.h> + +int lineno = 1; +int source_lineno = 1; +sstring source_filename; + +void +make_sstring_space (str, count) + sstring *str; + int count; +{ + int cur_pos = str->ptr - str->base; + int cur_size = str->limit - str->base; + int new_size = cur_pos + count + 100; + + if (new_size <= cur_size) + return; + + if (str->base == NULL) + str->base = xmalloc (new_size); + else + str->base = xrealloc (str->base, new_size); + str->ptr = str->base + cur_size; + str->limit = str->base + new_size; +} + +void +sstring_append (dst, src) + sstring *dst; + sstring *src; +{ + register char *d, *s; + register count = SSTRING_LENGTH(src); + MAKE_SSTRING_SPACE(dst, count + 1); + d = dst->ptr; + s = src->base; + while (--count >= 0) *d++ = *s++; + dst->ptr = d; + *d = 0; +} + +memory_full () +{ + abort(); +} + +char * +xmalloc (size) + unsigned size; +{ + register char *ptr = (char *) malloc (size); + if (ptr != 0) return (ptr); + memory_full (); + /*NOTREACHED*/ + return 0; +} + + +char * +xrealloc (old, size) + char *old; + unsigned size; +{ + register char *ptr = (char *) realloc (old, size); + if (ptr != 0) return (ptr); + memory_full (); + /*NOTREACHED*/ + return 0; +} + +int +scan_ident (fp, s, c) + register FILE *fp; + register sstring *s; + int c; +{ + s->ptr = s->base; + if (isalpha(c) || c == '_') + { + for (;;) + { + SSTRING_PUT(s, c); + c = getc (fp); + if (c == EOF || !(isalnum(c) || c == '_')) + break; + } + } + MAKE_SSTRING_SPACE(s, 1); + *s->ptr = 0; + return c; +} + +int scan_string (fp, s, init) + register FILE *fp; + register sstring *s; +{ + int c; + for (;;) + { + c = getc (fp); + if (c == EOF || c == '\n') + break; + if (c == init) + { + c = getc (fp); + break; + } + if (c == '\\') + { + c = getc (fp); + if (c == EOF) + break; + if (c == '\n') + continue; + } + SSTRING_PUT(s, c); + } + MAKE_SSTRING_SPACE(s, 1); + *s->ptr = 0; + return c; +} + +/* Skip horizontal white spaces (spaces, tabs, and C-style comments). */ + +int skip_spaces (fp, c) + register FILE *fp; + int c; +{ + for (;;) + { + if (c == ' ' || c == '\t') + c = getc (fp); + else if (c == '/') + { + c = getc (fp); + if (c != '*') + { + ungetc (c, fp); + return '/'; + } + c = getc (fp); + for (;;) + { + if (c == EOF) + return EOF; + else if (c != '*') + { + if (c == '\n') + source_lineno++, lineno++; + c = getc (fp); + } + else if ((c = getc (fp)) == '/') + return getc (fp); + } + } + else + break; + } + return c; +} + +int +read_upto (fp, str, delim) + FILE *fp; + sstring *str; + int delim; +{ + int ch; + for (;;) + { + ch = getc (fp); + if (ch == EOF || ch == delim) + break; + SSTRING_PUT(str, ch); + } + MAKE_SSTRING_SPACE(str, 1); + *str->ptr = 0; + return ch; +} + +int +get_token (fp, s) + register FILE *fp; + register sstring *s; +{ + int c; + s->ptr = s->base; + retry: + c = ' '; + again: + c = skip_spaces (fp, c); + if (c == '\n') + { + source_lineno++; + lineno++; + goto retry; + } + if (c == '#') + { + c = get_token (fp, s); + if (c == INT_TOKEN) + { + source_lineno = atoi (s->base); + get_token (fp, &source_filename); + } + for (;;) + { + c = getc (fp); + if (c == EOF) + return EOF; + if (c == '\n') + goto retry; + } + } + if (c == EOF) + return EOF; + if (isdigit (c)) + { + do + { + SSTRING_PUT(s, c); + c = getc (fp); + } while (c != EOF && isdigit(c)); + ungetc (c, fp); + c = INT_TOKEN; + goto done; + } + if (isalpha (c) || c == '_') + { + c = scan_ident (fp, s, c); + ungetc (c, fp); + return IDENTIFIER_TOKEN; + } + if (c == '\'' || c == '"') + { + int quote = c; + c = scan_string (fp, s, c); + ungetc (c, fp); + return c == '\'' ? CHAR_TOKEN : STRING_TOKEN; + } + SSTRING_PUT(s, c); + done: + MAKE_SSTRING_SPACE(s, 1); + *s->ptr = 0; + return c; +} + +unsigned long +hash (str) + char *str; +{ + int h = 0; + /* Replace this with something faster/better! FIXME! */ + while (*str) h = (h << 3) + *str++; + return h & 0x7FFFFFFF; +} diff --git a/gcc/scan.h b/gcc/scan.h new file mode 100644 index 00000000000..7106eb0bf79 --- /dev/null +++ b/gcc/scan.h @@ -0,0 +1,75 @@ +/* scan.h - Utility declarations for scan-decls and patch-header programs. + Copyright (C) 1993 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, 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 of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> + +typedef struct sstring +{ + char *base; + char *ptr; + char *limit; +} sstring; + +#define INIT_SSTRING(STR) ((STR)->base = 0, (STR)->ptr = 0, (STR)->limit = 0) +#define FREE_SSTRING(STR) do { if ((STR)->base) free (STR)->base; } while(0) +#define SSTRING_PUT(STR, C) do {\ + if ((STR)->limit <= (STR)->ptr) make_sstring_space (STR, 1); \ + *(STR)->ptr++ = (C); } while (0) +#define SSTRING_LENGTH(STR) ((STR)->ptr - (STR)->base) +#define MAKE_SSTRING_SPACE(STR, COUNT) \ + if ((STR)->limit - (STR)->ptr < (COUNT)) make_sstring_space (STR, COUNT); + +#ifndef _PARAMS +#if defined(__STDC__) || defined(__cplusplus) +#define _PARAMS(args) args +#else +#define _PARAMS(args) () +#endif +#endif + +struct partial_proto; +struct fn_decl +{ + char *fname; + char *rtype; + char *params; + struct partial_proto *partial; +}; + +extern int lineno; +extern void sstring_append _PARAMS((sstring*, sstring*)); +extern void make_sstring_space _PARAMS((sstring*, int)); +extern int skip_spaces _PARAMS((FILE*, int)); +extern int scan_ident _PARAMS((FILE *, sstring *, int)); +extern int scan_string _PARAMS((FILE*, sstring *, int)); +extern int read_upto _PARAMS((FILE*, sstring*, int)); +extern char *xmalloc _PARAMS((unsigned)); +extern char *xrealloc _PARAMS((char *, unsigned)); +extern unsigned long hash _PARAMS((char*)); + +/* get_token is a simple C lexer. */ +#define IDENTIFIER_TOKEN 300 +#define CHAR_TOKEN 301 +#define STRING_TOKEN 302 +#define INT_TOKEN 303 +extern int get_token _PARAMS ((FILE*, sstring*)); + +/* Current file and line numer, taking #-directives into account */ +extern int source_lineno; +extern sstring source_filename; +/* Current physical line number */ +extern int lineno; |