X-Git-Url: https://git.saurik.com/bison.git/blobdiff_plain/7400308fa383056ee5d5a78380a7c97b40325a70..e89a22bfab22e4d2ee73be49dcb66b51f8d0e892:/lib/ansi2knr.c diff --git a/lib/ansi2knr.c b/lib/ansi2knr.c index 196ba08e..2ff9d619 100644 --- a/lib/ansi2knr.c +++ b/lib/ansi2knr.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1989, 1997, 1998 Aladdin Enterprises. All rights reserved. */ +/* Copyright (C) 1989, 2000 Aladdin Enterprises. All rights reserved. */ /*$Id$*/ /* Convert ANSI C function definitions to K&R ("traditional C") syntax */ @@ -37,27 +37,62 @@ program under the GPL. * There are no error messages. * * ansi2knr recognizes function definitions by seeing a non-keyword - * identifier at the left margin, followed by a left parenthesis, - * with a right parenthesis as the last character on the line, - * and with a left brace as the first token on the following line - * (ignoring possible intervening comments), except that a line + * identifier at the left margin, followed by a left parenthesis, with a + * right parenthesis as the last character on the line, and with a left + * brace as the first token on the following line (ignoring possible + * intervening comments and/or preprocessor directives), except that a line * consisting of only * identifier1(identifier2) * will not be considered a function definition unless identifier2 is - * the word "void". ansi2knr will recognize a multi-line header provided - * that no intervening line ends with a left or right brace or a semicolon. - * These algorithms ignore whitespace and comments, except that - * the function name must be the first thing on the line. - * The following constructs will confuse it: + * the word "void", and a line consisting of + * identifier1(identifier2, <>) + * will not be considered a function definition. + * ansi2knr will recognize a multi-line header provided that no intervening + * line ends with a left or right brace or a semicolon. These algorithms + * ignore whitespace, comments, and preprocessor directives, except that + * the function name must be the first thing on the line. The following + * constructs will confuse it: * - Any other construct that starts at the left margin and * follows the above syntax (such as a macro or function call). - * - Some macros that tinker with the syntax of the function header. + * - Some macros that tinker with the syntax of function headers. */ /* * The original and principal author of ansi2knr is L. Peter Deutsch * . Other authors are noted in the change history * that follows (in reverse chronological order): + + lpd 2000-04-12 backs out Eggert's changes because of bugs: + - concatlits didn't declare the type of its bufend argument; + - concatlits didn't't recognize when it was inside a comment; + - scanstring could scan backward past the beginning of the string; when + - the check for \ + newline in scanstring was unnecessary. + + 2000-03-05 Paul Eggert + + Add support for concatenated string literals. + * ansi2knr.c (concatlits): New decl. + (main): Invoke concatlits to concatenate string literals. + (scanstring): Handle backslash-newline correctly. Work with + character constants. Fix bug when scanning backwards through + backslash-quote. Check for unterminated strings. + (convert1): Parse character constants, too. + (appendline, concatlits): New functions. + * ansi2knr.1: Document this. + + lpd 1999-08-17 added code to allow preprocessor directives + wherever comments are allowed + lpd 1999-04-12 added minor fixes from Pavel Roskin + for clean compilation with + gcc -W -Wall + lpd 1999-03-22 added hack to recognize lines consisting of + identifier1(identifier2, xxx) as *not* being procedures + lpd 1999-02-03 made indentation of preprocessor commands consistent + lpd 1999-01-28 fixed two bugs: a '/' in an argument list caused an + endless loop; quoted strings within an argument list + confused the parser + lpd 1999-01-24 added a check for write errors on the output, + suggested by Jim Meyering lpd 1998-11-09 added further hack to recognize identifier(void) as being a procedure lpd 1998-10-23 added hack to recognize lines consisting of @@ -153,19 +188,24 @@ program under the GPL. #endif +/* Define NULL (for *very* old compilers). */ +#ifndef NULL +# define NULL (0) +#endif + /* * The ctype macros don't always handle 8-bit characters correctly. * Compensate for this here. */ #ifdef isascii -# undef HAVE_ISASCII /* just in case */ -# define HAVE_ISASCII 1 +# undef HAVE_ISASCII /* just in case */ +# define HAVE_ISASCII 1 #else #endif #if STDC_HEADERS || !HAVE_ISASCII -# define is_ascii(c) 1 +# define is_ascii(c) 1 #else -# define is_ascii(c) isascii(c) +# define is_ascii(c) isascii(c) #endif #define is_space(c) (is_ascii(c) && isspace(c)) @@ -177,7 +217,10 @@ program under the GPL. #define isidfirstchar(ch) (is_alpha(ch) || (ch) == '_') /* Forward references */ +char *ppdirforward(); +char *ppdirbackward(); char *skipspace(); +char *scanstring(); int writeblanks(); int test1(); int convert1(); @@ -190,6 +233,8 @@ main(argc, argv) { FILE *in = stdin; FILE *out = stdout; char *filename = 0; + char *program_name = argv[0]; + char *output_name = 0; #define bufsize 5000 /* arbitrary size */ char *buf; char *line; @@ -205,6 +250,7 @@ main(argc, argv) * check for this switch for backward compatibility. */ int convert_varargs = 1; + int output_error; while ( argc > 1 && argv[1][0] == '-' ) { if ( !strcmp(argv[1], "--varargs") ) { @@ -219,7 +265,8 @@ main(argc, argv) argv += 2; continue; } - fprintf(stderr, "Unrecognized switch: %s\n", argv[1]); + fprintf(stderr, "%s: Unrecognized switch: %s\n", program_name, + argv[1]); fprintf(stderr, usage); exit(1); } @@ -229,16 +276,19 @@ main(argc, argv) fprintf(stderr, usage); exit(0); case 3: - out = fopen(argv[2], "w"); + output_name = argv[2]; + out = fopen(output_name, "w"); if ( out == NULL ) { - fprintf(stderr, "Cannot open output file %s\n", argv[2]); + fprintf(stderr, "%s: Cannot open output file %s\n", + program_name, output_name); exit(1); } /* falls through */ case 2: in = fopen(argv[1], "r"); if ( in == NULL ) { - fprintf(stderr, "Cannot open input file %s\n", argv[1]); + fprintf(stderr, "%s: Cannot open input file %s\n", + program_name, argv[1]); exit(1); } if ( filename == 0 ) @@ -250,6 +300,11 @@ main(argc, argv) if ( filename ) fprintf(out, "#line 1 \"%s\"\n", filename); buf = malloc(bufsize); + if ( buf == NULL ) + { + fprintf(stderr, "Unable to allocate read buffer!\n"); + exit(1); + } line = buf; while ( fgets(line, (unsigned)(buf + bufsize - line), in) != NULL ) { @@ -266,7 +321,7 @@ f: if ( line >= buf + (bufsize - 1) ) /* overflow check */ goto wl; if ( fgets(line, (unsigned)(buf + bufsize - line), in) == NULL ) goto wl; - switch ( *skipspace(more, 1) ) + switch ( *skipspace(ppdirforward(more), 1) ) { case '{': /* Definitely a function header. */ @@ -300,32 +355,91 @@ wl: fputs(buf, out); if ( line != buf ) fputs(buf, out); free(buf); - if ( out != stdout ) - fclose(out); + if ( output_name ) { + output_error = ferror(out); + output_error |= fclose(out); + } else { /* out == stdout */ + fflush(out); + output_error = ferror(out); + } + if ( output_error ) { + fprintf(stderr, "%s: error writing to %s\n", program_name, + (output_name ? output_name : "stdout")); + exit(1); + } if ( in != stdin ) fclose(in); return 0; } -/* Skip over space and comments, in either direction. */ +/* + * Skip forward or backward over one or more preprocessor directives. + */ +char * +ppdirforward(p) + char *p; +{ + for (; *p == '#'; ++p) { + for (; *p != '\r' && *p != '\n'; ++p) + if (*p == 0) + return p; + if (*p == '\r' && p[1] == '\n') + ++p; + } + return p; +} +char * +ppdirbackward(p, limit) + char *p; + char *limit; +{ + char *np = p; + + for (;; p = --np) { + if (*np == '\n' && np[-1] == '\r') + --np; + for (; np > limit && np[-1] != '\r' && np[-1] != '\n'; --np) + if (np[-1] == 0) + return np; + if (*np != '#') + return p; + } +} + +/* + * Skip over whitespace, comments, and preprocessor directives, + * in either direction. + */ char * skipspace(p, dir) - register char *p; - register int dir; /* 1 for forward, -1 for backward */ -{ for ( ; ; ) - { while ( is_space(*p) ) - p += dir; - if ( !(*p == '/' && p[dir] == '*') ) - break; - p += dir; p += dir; - while ( !(*p == '*' && p[dir] == '/') ) - { if ( *p == 0 ) - return p; /* multi-line comment?? */ - p += dir; - } - p += dir; p += dir; - } - return p; + char *p; + int dir; /* 1 for forward, -1 for backward */ +{ + for ( ; ; ) { + while ( is_space(*p) ) + p += dir; + if ( !(*p == '/' && p[dir] == '*') ) + break; + p += dir; p += dir; + while ( !(*p == '*' && p[dir] == '/') ) { + if ( *p == 0 ) + return p; /* multi-line comment?? */ + p += dir; + } + p += dir; p += dir; + } + return p; +} + +/* Scan over a quoted string, in either direction. */ +char * +scanstring(p, dir) + char *p; + int dir; +{ + for (p += dir; ; p += dir) + if (*p == '"' && p[-dir] != '\\') + return p + dir; } /* @@ -359,14 +473,14 @@ writeblanks(start, end) int test1(buf) char *buf; -{ register char *p = buf; +{ char *p = buf; char *bend; char *endfn; int contin; if ( !isidfirstchar(*p) ) return 0; /* no name at left margin */ - bend = skipspace(buf + strlen(buf) - 1, -1); + bend = skipspace(ppdirbackward(buf + strlen(buf) - 1, buf), -1); switch ( *bend ) { case ';': contin = 0 /*2*/; break; @@ -396,7 +510,7 @@ test1(buf) }; char **key = words; char *kp; - int len = endfn - buf; + unsigned len = endfn - buf; while ( (kp = *key) != 0 ) { if ( strlen(kp) == len && !strncmp(kp, buf, len) ) @@ -409,14 +523,16 @@ test1(buf) int len; /* * Check for identifier1(identifier2) and not - * identifier1(void). + * identifier1(void), or identifier1(identifier2, xxxx). */ while ( isidchar(*p) ) p++; len = p - id; p = skipspace(p, 1); - if ( *p == ')' && (len != 4 || strncmp(id, "void", 4)) ) + if (*p == ',' || + (*p == ')' && (len != 4 || strncmp(id, "void", 4))) + ) return 0; /* not a function */ } /* @@ -443,7 +559,7 @@ convert1(buf, out, header, convert_varargs) int header; /* Boolean */ int convert_varargs; /* Boolean */ { char *endfn; - register char *p; + char *p; /* * The breaks table contains pointers to the beginning and end * of each argument. @@ -461,7 +577,7 @@ convert1(buf, out, header, convert_varargs) ; top: p = endfn; breaks = (char **)malloc(sizeof(char *) * num_breaks * 2); - if ( breaks == 0 ) + if ( breaks == NULL ) { /* Couldn't allocate break table, give up */ fprintf(stderr, "Unable to allocate break table!\n"); fputs(buf, out); @@ -473,7 +589,7 @@ top: p = endfn; do { int level = 0; char *lp = NULL; - char *rp; + char *rp = NULL; char *end = NULL; if ( bp >= btop ) @@ -500,14 +616,18 @@ top: p = endfn; else rp = p; break; case '/': - p = skipspace(p, 1) - 1; + if (p[1] == '*') + p = skipspace(p, 1) - 1; break; + case '"': + p = scanstring(p, 1) - 1; + break; default: ; } } /* Erase any embedded prototype parameters. */ - if ( lp ) + if ( lp && rp ) writeblanks(lp + 1, rp); p--; /* back up over terminator */ /* Find the name being declared. */ @@ -523,9 +643,19 @@ top: p = endfn; while ( level ) switch ( *--p ) { - case ']': case ')': level++; break; - case '[': case '(': level--; break; - case '/': p = skipspace(p, -1) + 1; break; + case ']': case ')': + level++; + break; + case '[': case '(': + level--; + break; + case '/': + if (p > buf && p[-1] == '*') + p = skipspace(p, -1) + 1; + break; + case '"': + p = scanstring(p, -1) + 1; + break; default: ; } }