cproto patchlevel 2

Chin Huang cthuang at watdragon.waterloo.edu
Fri Jan 5 18:22:32 AEST 1990


This is an update to cproto, a C function prototype generator.
Since the patches are larger than the original sources, I'm posting 
the entire distribution.  The patchlevel.h file says this is
patchlevel 2.  Patchlevel 1 was never posted.

Changes:

1. Fix: Cproto generated incorrect prototypes for functions that take
   function pointer parameters or return a function pointer.  For example,
   cproto produced an erroneous prototype for this function definition:

	void
	(*signal (sig, func))()
	int sig;
	void (*func)();
	{
	    /* stuff */
	}

2. Fix: When run with the -v option on this input, cproto did not output
   a declaration for variable "b":

	char *a="one"; char *b="two";

3. The lexical analyser now uses LEX.  It should still be compatible with
   FLEX.

4. The options were renamed and new ones were added that change the output
   format of the prototypes generated.


# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by watdragon!cthuang on Thu Jan  4 22:34:54 EST 1990
# Contents:  README Makefile cproto.1 cproto.sh lex.l grammar.y cproto.h
#	patchlevel.h semantics.h symbol.h cproto1.c semantics.c string.c
#	symbol.c
 
echo x - README
sed 's/^@//' > "README" <<'@//E*O*F README//'
This program automatically generates C function prototypes and
variable declarations from C language source code.

Chin Huang
cthuang at watdragon.waterloo.edu
@//E*O*F README//
chmod u=rw,g=r,o=r README
 
echo x - Makefile
sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//'
# $Id: Makefile,v 1.3 90/01/04 22:30:04 cthuang Exp $
#
# Makefile for C prototype generator

LEX = lex
YACC = yacc
CFLAGS = -O $(DEFINES)

# Define -DSYSV if you have UNIX System V
DEFINES =

DIST =		README Makefile cproto.1 cproto.sh $(SOURCES)
SOURCES =	lex.l grammar.y \
		cproto.h patchlevel.h semantics.h symbol.h \
		cproto1.c semantics.c string.c symbol.c
CSOURCES =	cproto1.c semantics.c string.c symbol.c y.tab.c
OBJECTS =	cproto1.o semantics.o string.o symbol.o y.tab.o

all: cproto cproto1

cproto: cproto.sh
	cp cproto.sh cproto

cproto1: $(OBJECTS)
	$(CC) $(CFLAGS) -o $@ $(OBJECTS) -ll

y.tab.o: y.tab.c lex.yy.c

y.tab.c: grammar.y
	$(YACC) grammar.y

lex.yy.c: lex.l
	$(LEX) lex.l

TAGS: $(SOURCES)
	etags -t $(SOURCES)

clean:
	rm -f lex.yy.c y.tab.c $(OBJECTS) cproto cproto1 cproto.shar
	
lint:
	lint -B $(CSOURCES)

print:
	cpr $(SOURCES) | lpr -J'cproto'

shar:
	shar $(DIST) >cproto.shar

ci:
	ci -u $(DIST)

cproto1.o: symbol.h cproto.h
semantics.o: symbol.h cproto.h semantics.h
symbol.o: symbol.h
y.tab.o: symbol.h cproto.h semantics.h
@//E*O*F Makefile//
chmod u=rw,g=r,o=r Makefile
 
echo x - cproto.1
sed 's/^@//' > "cproto.1" <<'@//E*O*F cproto.1//'
@.\" $Header: /u3/cthuang/cproto/RCS/cproto.1,v 1.3 90/01/04 22:30:26 cthuang Exp $
@.\"
@.de EX          \"Begin example
@.ne 5
@.if n .sp 1
@.if t .sp .5
@.nf
@.in +.5i
@..
@.de EE		\"End example
@.fi
@.in -.5i
@.if n .sp 1
@.if t .sp .5
@..
@.TH CPROTO 1 "January 5, 1990"
@.SH NAME
cproto \- generate C function prototypes from C source code
@.SH SYNOPSIS
@.B cproto
[ 
@.I option \fP...\fI
] [
@.I file \fP...\fI
]
@.SH DESCRIPTION
@.B Cproto
reads C source code files and produces to standard output
function prototypes for external functions defined in the file.
The function definitions may be in the old style or new style.
Optionally,
@.B cproto
also outputs declarations for any external variables defined in the file.
If no
@.I file
argument is given,
@.B cproto
takes its input from the standard input.
@.SH OPTIONS
@.TP
@.B \-e
On the output, prepend the keyword
@.B extern
in front of declarations.
@.TP
@.BI \-p n
Set the style of function prototype where
@.I n
is a number from 0 to 3.
For example, consider the function definition
@.EX
main (argc, argv)
int argc;
char *argv[];
{
 ...
}
@.EE
A value of 3 produces the full function prototype:
@.EX
int main(int argc, char *argv[]);
@.EE
For a value of 2, the output has the form:
@.EX
int main(int /*argc*/, char */*argv*/[]);
@.EE
When set to 1, the output is:
@.EX
int main(/*int argc, char *argv[]*/);
@.EE
If the value is 0, then no prototypes are generated.
The default value is 3.
@.TP
@.B \-s
Also output
@.B static
declarations.
@.TP
@.B \-v
Also output declarations for variables defined in the file.
@.TP
@.BI \-ff string
Output this string before each function prototype.
The default value is the null string.
@.TP
@.BI \-fo string
In each parameter list, output this string after the opening parenthesis
and before the first parameter.
The default value is the null string.
@.TP
@.BI \-fp string
Output this string before each subsequent parameter after the first parameter
in the parameter list.
The default value is a space.
@.TP
@.BI \-fc string
Output this string after the last parameter and before the closing
parenthesis in the parameter list.
The default value is the null string.
@.TP
@.BI \-fv string
Output this string before each variable declaration.
The default value is the null string.
For example, setting the options
@.EX
-fo"\\n\\t" -fp"\\n\\t" -fc"\\n\\t"
@.EE
will produce prototypes in the format
@.EX
int main(
        int argc,
        char *argv[]
        );
@.EE
@.TP
@.BI \-D name\[=value\]
This option is passed through to the preprocessor and is used to define 
symbols for use with conditionals such as
@.I #ifdef.
@.TP
@.BI \-U name
This option is passed through to the preprocessor and is used to remove
any definitions of this symbol.
@.TP
@.BI \-I directory
This option is passed through to the preprocessor and is used to specify
a directory to search for files that are referenced with 
@.I #include.
@.SH AUTHOR
Chin Huang (cthuang at watdragon.waterloo.edu)
@.SH BUGS
Parameter types are not promoted.  For example, the correct prototype for
the function definition
@.EX
int foo()
char x;
{
 ...
}
@.EE
is
@.EX
int foo(int x).
@.EE
@.LP
Options that take string arguments only interpret the following
character escape sequences:
@.EX
\\n	newline
\\t	tab
@.EE
@.SH "SEE ALSO"
cc(1),
cpp(1)
@//E*O*F cproto.1//
chmod u=rw,g=r,o=r cproto.1
 
echo x - cproto.sh
sed 's/^@//' > "cproto.sh" <<'@//E*O*F cproto.sh//'
#!/bin/sh
# $Id: cproto.sh,v 1.2 90/01/04 22:33:29 cthuang Exp $
#
# C function prototype generator
# Usage: cproto [options] [files]
#
cpp_opt="-I."
cproto_opt=""
source=""
for opt do
    case "$opt" in
    -D*|-U*|-I*)
	cpp_opt="$cpp_opt $opt"
	;;
    -*)
	cproto_opt="$cproto_opt $opt"
	;;
    *)
	source="$source $opt"
	;;
    esac
done
if [ "$source" ]; then
    for i in $source
    do
	/lib/cpp $cpp_opt $i | cproto1 $cproto_opt
    done
else
    /lib/cpp $cpp_opt | cproto1 $cproto_opt
fi
@//E*O*F cproto.sh//
chmod u=rx,g=r,o=r cproto.sh
 
echo x - lex.l
sed 's/^@//' > "lex.l" <<'@//E*O*F lex.l//'
%{
/* $Id: lex.l,v 1.3 90/01/04 22:30:39 cthuang Exp $
 *
 * C function prototype generator
 * Lexical analyzer specification
 */
%}

WLF		[ \t\n\f]*
LETTER		[A-Za-z_]
DIGIT		[0-9]
ID		{LETTER}({LETTER}|{DIGIT})*
QUOTED		(\"(\\\"|[^"\n])*\"|\'.\'|\\.)

%{
static int curly = 0;		/* number of curly brace nesting levels */
char cur_file[MAX_TEXT_LENGTH];	/* current file name */
int line_num = 1;		/* current line number in file */
%}

%s INIT1 INIT2 CURLY COMMENT
%%

\n			++line_num;

<INITIAL>#[ \t]*[0-9]+[ \t]*\".*$	{
			    sscanf(yytext, "# %d \"%[^\"]\"", &line_num,
			     cur_file);
			    --line_num;
			}

<INITIAL>#[ \t]*[0-9]+.*$	{
			    sscanf(yytext, "# %d ", &line_num);
			    --line_num;
			}

<INITIAL>#.*$		;

<INITIAL>"("		return '(';
<INITIAL>")"		return ')';
<INITIAL>"*"		return '*';
<INITIAL>","		return ',';
<INITIAL>";"		return ';';
<INITIAL>"..."		return ELLIPSIS;

<INITIAL>auto		return AUTO;
<INITIAL>extern		return EXTERN;
<INITIAL>register	return REGISTER;
<INITIAL>static		return STATIC;
<INITIAL>typedef	return TYPEDEF;
<INITIAL>char		return CHAR;
<INITIAL>double		return DOUBLE;
<INITIAL>float		return FLOAT;
<INITIAL>int		return INT;
<INITIAL>void		return VOID;
<INITIAL>long		return LONG;
<INITIAL>short		return SHORT;
<INITIAL>signed		return SIGNED;
<INITIAL>unsigned	return UNSIGNED;
<INITIAL>enum		return ENUM;
<INITIAL>struct		return STRUCT;
<INITIAL>union		return UNION;
<INITIAL>const		return CONST;
<INITIAL>volatile	return VOLATILE;

<INITIAL>\[[^\]]*\]	{
			    strcpy(yylval.text, yytext);
			    return BRACKETS;
			}

<INITIAL>{ID}		{
			    strcpy(yylval.text, yytext);
			    if (is_typedef_name(yytext))
				return TYPEDEF_NAME;
			    else
				return IDENTIFIER;
			}

<INITIAL>"="{WLF}"{"	{
			    int i;

			    curly = 1;
			    BEGIN INIT1;
			    for (i = 0; i < yyleng; ++i)
				if (yytext[i] == '\n') ++line_num;
			}
<INIT1>"{"		++curly;
<INIT1>"}"		{
			    if (--curly == 0) {
				BEGIN INITIAL;
				return INITIALIZER;
			    }
			}
<INIT1>{QUOTED}|.	;

<INITIAL>"="		BEGIN INIT2;
<INIT2>[,;]		{
			    yyless(yyleng-1);
			    BEGIN INITIAL;
			    return INITIALIZER;
			}
<INIT2>{QUOTED}|.	;

<INITIAL>"{"		{ curly = 1; BEGIN CURLY; }
<CURLY>"{"		++curly;
<CURLY>"}"		{
			    if (--curly == 0) {
				BEGIN INITIAL;
				return BRACES;
			    }
			}
<CURLY>{QUOTED}|.	;

<INITIAL>"/*"		BEGIN COMMENT;
<COMMENT>"*/"		BEGIN INITIAL;
<COMMENT>.		;

<INITIAL>[ \t\f]+	;
<INITIAL>.		print_error("bad character '%c'", yytext[0]);
@//E*O*F lex.l//
chmod u=rw,g=r,o=r lex.l
 
echo x - grammar.y
sed 's/^@//' > "grammar.y" <<'@//E*O*F grammar.y//'
/* $Id: grammar.y,v 1.3 90/01/04 22:30:59 cthuang Exp $
 *
 * yacc grammar for C prototype generator
 * This was derived from the grammar given in Appendix A of
 * "The C Programming Language" by Kernighan and Ritchie.
 */

/* identifiers that are not reserved words */
%token IDENTIFIER TYPEDEF_NAME

/* storage class */
%token AUTO EXTERN REGISTER STATIC TYPEDEF

/* type specifiers */
%token CHAR DOUBLE FLOAT INT VOID
%token LONG SHORT SIGNED UNSIGNED
%token ENUM STRUCT UNION

/* type qualifiers */
%token CONST VOLATILE

/* paired braces and everything between them: { ... } */
%token BRACES

/* paired square brackets and everything between them: [ ... ] */
%token BRACKETS

/* three periods */
%token ELLIPSIS

/* equal sign followed by constant expression or stuff between braces */
%token INITIALIZER

%type <decl_spec> declaration_specifiers declaration_specifier
%type <decl_spec> storage_class type_specifier type_qualifier
%type <decl_spec> struct_or_union_specifier enum_specifier
%type <decl_list> init_declarator_list
%type <declarator> init_declarator declarator direct_declarator
%type <declarator> abs_declarator direct_abs_declarator
%type <param_list> parameter_type_list parameter_list
%type <parameter> parameter_declaration
%type <param_list> opt_identifier_list identifier_list
%type <text> struct_or_union
%type <text> pointer type_qualifiers
%type <text> IDENTIFIER TYPEDEF_NAME
%type <text> BRACKETS

%{
#include <stdio.h>
#include "cproto.h"
#include "semantics.h"

/* This variable is set TRUE when we are scanning the parameter declarations
 * part of a function definition.
 */
static boolean func_params = FALSE;

/* This points to the list of parameters for the current function definition. */
static ParameterList *cur_params;

/* temporary string buffer */
static char buf[MAX_TEXT_LENGTH];

/* Table of typedef names */
SymbolTable *typedef_names;
%}
%%

program			: /* empty */
			| translation_unit
			;

translation_unit	: external_declaration
			| translation_unit external_declaration
			;

external_declaration	: declaration
			| function_definition
			| error
			;

declaration		: declaration_specifiers ';'
			| declaration_specifiers init_declarator_list ';'
			{
			    if (func_params) {
				set_param_types(cur_params, &$1, &$2);
			    } else {
				output_declarations(&$1, &$2);
			    }
			    free_decl_spec(&$1);
			    free_decl_list(&$2);
			}
			| TYPEDEF declaration_specifiers declarator_list ';'
			{
			    free_decl_spec(&$2);
			}
			;

declarator_list		: declarator
			{
			    new_symbol(typedef_names, $1.name);
			    free_declarator(&$1);
			}
			| declarator_list ',' declarator
			{
			    new_symbol(typedef_names, $3.name);
			    free_declarator(&$3);
			}
			;

function_definition	: declaration_specifiers declarator
			{
			    if ($2.func_def == FUNC_NONE) {
				yyerror("syntax error");
				YYERROR;
			    }
			    cur_params = &($2.params);
			    func_params = TRUE;
			}
			  opt_declarations BRACES
			{
			    func_params = FALSE;

			    output_prototype(&$1, &$2);
			    free_decl_spec(&$1);
			    free_declarator(&$2);
			}
			| declarator
			{
			    if ($1.func_def == FUNC_NONE) {
				yyerror("syntax error");
				YYERROR;
			    }
			    cur_params = &($1.params);
			    func_params = TRUE;
			}
			  opt_declarations BRACES
			{
			    DeclSpec	decl_spec;

			    func_params = FALSE;

			    new_decl_spec(&decl_spec, "int", DE_EXTERN);
			    output_prototype(&decl_spec, &$1);
			    free_decl_spec(&decl_spec);
			    free_declarator(&$1);
			}
			;

declarations		: declaration
			| declarations declaration
			;

opt_declarations	: declarations
			| /* empty */
			;

declaration_specifiers	: declaration_specifier
			| declaration_specifiers declaration_specifier
			{
			    join_decl_specs(&$$, &$1, &$2);
			}
			;

declaration_specifier	: storage_class
			| type_specifier
			| type_qualifier
			;

storage_class		: AUTO
			{
			    new_decl_spec(&$$, "auto", DE_JUNK);
			}
			| EXTERN
			{
			    new_decl_spec(&$$, "extern", DE_JUNK);
			}
			| REGISTER
			{
			    new_decl_spec(&$$, "register", DE_JUNK);
			}
			| STATIC
			{
			    new_decl_spec(&$$, "static", DE_STATIC);
			}
			;

type_specifier		: CHAR
			{
			    new_decl_spec(&$$, "char", DE_EXTERN);
			}
			| DOUBLE
			{
			    new_decl_spec(&$$, "double", DE_EXTERN);
			}
			| FLOAT
			{
			    new_decl_spec(&$$, "float", DE_EXTERN);
			}
			| INT
			{
			    new_decl_spec(&$$, "int", DE_EXTERN);
			}
			| LONG
			{
			    new_decl_spec(&$$, "long", DE_EXTERN);
			}
			| SHORT
			{
			    new_decl_spec(&$$, "short", DE_EXTERN);
			}
			| SIGNED
			{
			    new_decl_spec(&$$, "signed", DE_EXTERN);
			}
			| UNSIGNED
			{
			    new_decl_spec(&$$, "unsigned", DE_EXTERN);
			}
			| VOID
			{
			    new_decl_spec(&$$, "void", DE_EXTERN);
			}
			| struct_or_union_specifier
			| enum_specifier
			| TYPEDEF_NAME
			{
			    new_decl_spec(&$$, $1, DE_EXTERN);
			}
			;

type_qualifier		: CONST
			{
			    new_decl_spec(&$$, "const", DE_EXTERN);
			}
			| VOLATILE
			{
			    new_decl_spec(&$$, "volatile", DE_EXTERN);
			}
			;

struct_or_union_specifier : struct_or_union IDENTIFIER BRACES
			{
			    sprintf(buf, "%s %s {}", $1, $2);
			    new_decl_spec(&$$, buf, DE_EXTERN);
			}
			| struct_or_union BRACES
			{
			    sprintf(buf, "%s {}", $1);
			    new_decl_spec(&$$, buf, DE_EXTERN);
			}
			| struct_or_union IDENTIFIER
			{
			    sprintf(buf, "%s %s", $1, $2);
			    new_decl_spec(&$$, buf, DE_EXTERN);
			}
			;

struct_or_union		: STRUCT
			{
			    strcpy($$, "struct");
			}
			| UNION
			{
			    strcpy($$, "union");
			}
			;

init_declarator_list	: init_declarator
			{
			    new_decl_list(&$$, &$1);
			}
			| init_declarator_list ',' init_declarator
			{
			    add_decl_list(&$$, &$1, &$3);
			}
			;

init_declarator		: declarator
			| declarator INITIALIZER
			;

enum_specifier		: ENUM IDENTIFIER BRACES
			{
			    sprintf(buf, "enum %s {}", $2);
			    new_decl_spec(&$$, buf, DE_EXTERN);
			}
			| ENUM BRACES
			{
			    new_decl_spec(&$$, "enum {}", DE_EXTERN);
			}
			| ENUM IDENTIFIER
			{
			    sprintf(buf, "enum %s", $2);
			    new_decl_spec(&$$, buf, DE_EXTERN);
			}
			;

declarator		: pointer direct_declarator
			{
			    sprintf(buf, "%s%s", $1, $2.text);
			    $$ = $2;
			    $$.text = strdup(buf);
			    free($2.text);
			}
			| direct_declarator
			;

direct_declarator	: IDENTIFIER
			{
			    new_declarator(&$$, $1, $1);
			}
			| '(' declarator ')'
			{
			    sprintf(buf, "(%s)", $2.text);
			    $$ = $2;
			    $$.text = strdup(buf);
			    free($2.text);
			}
			| direct_declarator BRACKETS
			{
			    sprintf(buf, "%s%s", $1.text, $2);
			    $$ = $1;
			    $$.text = strdup(buf);
			    free($1.text);
			}
			| direct_declarator '(' parameter_type_list ')'
			{
			    sprintf(buf, "%s()", $1.text);
			    $$ = $1;
			    $$.text = strdup(buf);
			    $$.func_def = FUNC_ANSI;
			    $$.params = $3;
			    free($1.text);
			}
			| direct_declarator '(' opt_identifier_list ')'
			{
			    sprintf(buf, "%s()", $1.text);
			    $$ = $1;
			    $$.text = strdup(buf);
			    $$.func_def = FUNC_TRADITIONAL;
			    if ($3.first != NULL) {
				$$.params = $3;
			    }
			    free($1.text);
			}
			;

pointer			: '*' type_qualifiers
			{
			    sprintf($$, "*%s", $2);
			}
			| '*' type_qualifiers pointer
			{
			    sprintf($$, "*%s%s", $2, $3);
			}
			;

type_qualifiers		: /* empty */
			{
			    strcpy($$, "");
			}
			| type_qualifiers type_qualifier
			{
			    sprintf($$, "%s %s ", $1, $2.text);
			    free($2.text);
			}
			;

parameter_type_list	: parameter_list
			| parameter_list ',' ELLIPSIS
			{
			    add_ident_list(&$$, &$1, "...");
			}
			;

parameter_list		: parameter_declaration
			{
			    new_param_list(&$$, &$1);
			}
			| parameter_list ',' parameter_declaration
			{
			    add_param_list(&$$, &$1, &$3);
			}
			;

parameter_declaration	: declaration_specifiers declarator
			{
			    new_parameter(&$$, &$1, &$2);
			}
			| declaration_specifiers abs_declarator
			{
			    new_parameter(&$$, &$1, &$2);
			}
			| declaration_specifiers
			{
			    new_parameter(&$$, &$1, NULL);
			}
			;

opt_identifier_list	: /* empty */
			{
			    new_ident_list(&$$);
			}
			| identifier_list
			;

identifier_list		: IDENTIFIER
			{
			    new_ident_list(&$$);
			    add_ident_list(&$$, &$$, $1);
			}
			| identifier_list ',' IDENTIFIER
			{
			    add_ident_list(&$$, &$1, $3);
			}
			;

abs_declarator		: pointer
			{
			    new_declarator(&$$, $1, "");
			}
			| pointer direct_abs_declarator
			{
			    sprintf(buf, "%s%s", $1, $2.text);
			    $$ = $2;
			    $$.text = strdup(buf);
			    free($2.text);
			}
			| direct_abs_declarator
			;

direct_abs_declarator	: '(' abs_declarator ')'
			{
			    sprintf(buf, "(%s)", $2.text);
			    $$ = $2;
			    $$.text = strdup(buf);
			    free($2.text);
			}
			| direct_abs_declarator BRACKETS
			{
			    sprintf(buf, "%s%s", $1.text, $2);
			    $$ = $1;
			    $$.text = strdup(buf);
			    free($1.text);
			}
			| BRACKETS
			{
			    new_declarator(&$$, $1, "");
			}
			| direct_abs_declarator '(' parameter_type_list ')'
			{
			    sprintf(buf, "%s(%%s)", $1.text);
			    $$ = $1;
			    $$.text = strdup(buf);
			    free($1.text);
			}
			| direct_abs_declarator '(' ')'
			{
			    sprintf(buf, "%s()", $1.text);
			    $$ = $1;
			    $$.text = strdup(buf);
			    free($1.text);
			}
			| '(' parameter_type_list ')'
			{
			    new_declarator(&$$, "()", "");
			}
			| '(' ')'
			{
			    new_declarator(&$$, "()", "");
			}
			;

%%
#include "lex.yy.c"

yyerror (msg)
char *msg;
{
    print_error(msg);
}

void
parse_file ()
{
    typedef_names = create_symbol_table();
    yyparse();
}
@//E*O*F grammar.y//
chmod u=rw,g=r,o=r grammar.y
 
echo x - cproto.h
sed 's/^@//' > "cproto.h" <<'@//E*O*F cproto.h//'
/* $Id: cproto.h,v 1.3 90/01/04 22:31:14 cthuang Exp $
 *
 * Definitions for C language prototype generator
 */
#include "symbol.h"

/* Boolean type */
typedef char boolean;
#define FALSE	0
#define TRUE	1

/* maximum number of characters in a text buffer */
#define MAX_TEXT_LENGTH	512

/* This is a list of function parameters. */
typedef struct _parameter_list {
    struct _parameter	*first;	/* pointer to first parameter in list */
    struct _parameter	*last;  /* pointer to last parameter in list */  
} ParameterList;

/* Declaration specifier flags */
#define DE_EXTERN	0	/* default: external declaration */
#define DE_STATIC	1	/* visible only in current file */
#define DE_JUNK		2	/* we're not interested in this declaration */

/* This structure stores information about a declaration specifier. */
typedef struct _decl_spec {
    unsigned short	flags;	/* flags defined above */
    char		*text;	/* source text */
} DeclSpec;

/* Styles of function definitions
 *
 * FUNC_TRADITIONAL	traditional style function definition
 * FUNC_ANSI		ANSI style
 */
typedef enum { FUNC_NONE, FUNC_TRADITIONAL, FUNC_ANSI } FuncDefType;

/* This structure stores information about a declarator. */
typedef struct _declarator {
    char		*name;		/* name of variable or function */
    char		*text;		/* source text */
    FuncDefType		func_def;	/* style of function definition */
    short		paren_count;	/* parameter parenthesis nesting */
    ParameterList	params;		/* function parameters */
    struct _declarator	*next;		/* next declarator in list */
} Declarator;

/* This is a list of declarators. */
typedef struct _declarator_list {
    Declarator		*first;	/* pointer to first declarator in list */
    Declarator		*last;  /* pointer to last declarator in list */  
} DeclaratorList;

/* This structure stores information about a function parameter. */
typedef struct _parameter {
    DeclSpec		decl_spec;
    Declarator		declarator;
    struct _parameter	*next;		/* next parameter in list */
} Parameter;

/* parser stack entry type */
typedef union {
    char		text[MAX_TEXT_LENGTH];
    DeclSpec		decl_spec;
    Parameter		parameter;
    ParameterList	param_list;
    Declarator		declarator;
    DeclaratorList	decl_list;
} YYSTYPE;

/* Prototype styles */
#define PROTO_NONE		0
#define PROTO_TRADITIONAL	1
#define PROTO_TYPES		2
#define PROTO_FULL		3

/* Program options */
extern boolean extern_out;
extern boolean static_out;
extern boolean variables_out;
extern int proto_style;
extern char *variable_prefix, *function_prefix;
extern char *first_param_prefix, *middle_param_prefix, *last_param_suffix;

/* Global declarations */
extern int line_num;
extern char cur_file[];
extern SymbolTable *typedef_names;
extern void print_error();
extern void parse_file();

extern char *strdup(), *strstr();
extern char *malloc();
@//E*O*F cproto.h//
chmod u=rw,g=r,o=r cproto.h
 
echo x - patchlevel.h
sed 's/^@//' > "patchlevel.h" <<'@//E*O*F patchlevel.h//'
#define PATCHLEVEL 2
@//E*O*F patchlevel.h//
chmod u=rw,g=r,o=r patchlevel.h
 
echo x - semantics.h
sed 's/^@//' > "semantics.h" <<'@//E*O*F semantics.h//'
/* $Id: semantics.h,v 1.3 90/01/04 22:31:32 cthuang Exp $
 *
 * Declarations for semantics action routines
 */

extern boolean is_typedef_name(/*
	char *name
	*/);
extern void new_decl_spec(/*
	DeclSpec *decl_spec,
	char *text,
	unsigned short flags
	*/);
extern void join_decl_specs(/*
	DeclSpec *result,
	DeclSpec *a,
	DeclSpec *b
	*/);
extern void free_decl_spec(/*
	DeclSpec *decl_spec
	*/);
extern void new_parameter(/*
	Parameter *param,
	DeclSpec *decl_spec,
	Declarator *declarator
	*/);
extern void free_parameter(/*
	Parameter *param
	*/);
extern void new_param_list(/*
	ParameterList *param_list,
	Parameter *param
	*/);
extern void add_param_list(/*
	ParameterList *to,
	ParameterList *from,
	Parameter *param
	*/);
extern void free_param_list(/*
	ParameterList *param_list
	*/);
extern void new_ident_list(/*
	ParameterList *param_list
	*/);
extern void add_ident_list(/*
	ParameterList *to,
	ParameterList *from,
	char *name
	*/);
extern void new_declarator(/*
	Declarator *d,
	char *name,
	char *text
	*/);
extern void free_declarator(/*
	Declarator *d
	*/);
extern void new_decl_list(/*
	DeclaratorList *decl_list,
	Declarator *declarator
	*/);
extern void add_decl_list(/*
	DeclaratorList *to,
	DeclaratorList *from,
	Declarator *declarator
	*/);
extern void free_decl_list(/*
	DeclaratorList *decl_list
	*/);
extern void set_param_types(/*
	ParameterList *params,
	DeclSpec *decl_spec,
	DeclaratorList *declarators
	*/);
extern void output_declarations(/*
	DeclSpec *decl_spec,
	DeclaratorList *decl_list
	*/);
extern void output_prototype(/*
	DeclSpec *decl_spec,
	Declarator *declarator
	*/);
@//E*O*F semantics.h//
chmod u=rw,g=r,o=r semantics.h
 
echo x - symbol.h
sed 's/^@//' > "symbol.h" <<'@//E*O*F symbol.h//'
/* $Id: symbol.h,v 1.2 90/01/04 22:31:44 cthuang Exp $
 *
 * Definitions for a symbol table
 */
#ifndef _SYMBOL_H
#define _SYMBOL_H

/* maximum length of symbols */
#define SYM_MAX_LENGTH 64

typedef struct _symbol {
	struct _symbol	*next;			/* next symbol in list */
	char		name[SYM_MAX_LENGTH];	/* name of symbol */
} Symbol;

/* hash table length */
#define SYM_MAX_HASH 256

typedef struct _symbol_table {
	Symbol		*bucket[SYM_MAX_HASH];	/* hash buckets */
} SymbolTable;

extern SymbolTable	*create_symbol_table();	/* Create symbol table */
extern Symbol		*find_symbol();		/* Lookup symbol name */
extern Symbol		*new_symbol();		/* Define new symbol */

#endif
@//E*O*F symbol.h//
chmod u=rw,g=r,o=r symbol.h
 
echo x - cproto1.c
sed 's/^@//' > "cproto1.c" <<'@//E*O*F cproto1.c//'
/* $Id: cproto1.c,v 1.3 90/01/04 22:31:51 cthuang Exp $
 *
 * C prototype generator
 * This filter reads C source code and outputs ANSI C function prototypes.
 */
#ifndef lint
static char *rcsid =
"$Id: cproto1.c,v 1.3 90/01/04 22:31:51 cthuang Exp $";
#endif
#include <stdio.h>
#include <varargs.h>
#include "cproto.h"

/* getopt declarations */
extern int getopt();
extern char *optarg;
extern int optind;

/* Name of the program */
static char *progname = "cproto";

/* Program options */

/* TRUE if "extern" should appear on external declarations. */
boolean extern_out = FALSE;

/* TRUE if static declarations are also output. */
boolean static_out = FALSE;

/* TRUE when variable declarations are printed also. */
boolean variables_out = FALSE;

/* This variable controls the style of function prototype. */
int proto_style = PROTO_FULL;

/* String output before each variable declaration. */
char *variable_prefix = "";

/* String output before each function prototype. */
char *function_prefix = "";

/* String output before the first parameter in a function prototype. */
char *first_param_prefix = "";

/* String output before each subsequent parameter in a function prototype. */
char *middle_param_prefix = " ";

/* String output after the last parameter in a function prototype. */
char *last_param_suffix = "";

/* Output an error message along with the line number where it was found.
 */
void
print_error (va_alist)
va_dcl
{
    va_list	args;
    char	*fmt;

    va_start(args);
    fmt = va_arg(args, char *);
    fprintf(stderr, "\"%s\", line %d: ", cur_file, line_num);
    vfprintf(stderr, fmt, args);
    fputc('\n', stderr);
    va_end(args);
}

/* Replace any character escape sequences in a string with the actual
 * characters and return the resultant string.
 * This function knows only a few escape sequences.
 */
static char *
escape_string (src)
char	*src;
{
    char	*result, *get, *put;

    result = strdup(src);
    put = result;
    get = src;
    while (*get != '\0') {
	if (*get == '\\') {
	    switch (*(++get)) {
	    case 'n':
		*put++ = '\n';
		++get;
		break;
	    case 't':
		*put++ = '\t';
		++get;
		break;
	    default:
		if (*get != '\0')
		    *put++ = *get++;
	    }
	} else {
	    *put++ = *get++;
	}
    }
    *put = *get;
    return result;
}


main (argc, argv)
int argc;
char **argv;
{
    int		c;
    boolean	error_flag;
    char	*format_string;

    error_flag = FALSE;
    while ((c = getopt(argc, argv, "ef:l:m:p:sv")) != EOF) {
	switch (c) {
	case 'e':
	    extern_out = TRUE;
	    break;
	case 'f':
	    format_string = escape_string(optarg);
	    switch (*format_string++) {
	    case 'v':
		variable_prefix = format_string;
		break;
	    case 'f':
		function_prefix = format_string;
		break;
	    case 'o':
		first_param_prefix = format_string;
		break;
	    case 'p':
		middle_param_prefix = format_string;
		break;
	    case 'c':
		last_param_suffix = format_string;
		break;
	    }
	    break;
	case 's':
	    static_out = TRUE;
	    break;
	case 'p':
	    proto_style = atoi(optarg);
	    if (proto_style < 0 || proto_style > PROTO_FULL)
		proto_style = PROTO_FULL;
	    break;
	case 'v':
	    variables_out = TRUE;
	    break;
	case '?':
	default:
	    error_flag = TRUE;
	}
    }

    if (optind == argc-1) {
	if (freopen(argv[optind], "r", stdin) == NULL) {
	    fprintf(stderr, "%s: cannot open file %s\n", progname,
	    	    argv[optind]);
	    exit(1);
	}
	strcpy(cur_file, argv[optind]);
    } else {
	error_flag = (boolean)(optind < argc-1);
    }

    if (error_flag) {
	fprintf(stderr, "usage: %s [ -esv ] [ -p n ] [ file ]\n", progname);
	exit(1);
    }

    parse_file();
}
@//E*O*F cproto1.c//
chmod u=rw,g=r,o=r cproto1.c
 
echo x - semantics.c
sed 's/^@//' > "semantics.c" <<'@//E*O*F semantics.c//'
/*
 * $Id: semantics.c,v 1.3 90/01/04 22:32:00 cthuang Exp $
 *
 * C prototype generator
 * These routines implement the semantic actions executed by the yacc parser.
 */
#include <stdio.h>
#ifdef SYSV
#include <string.h>
#else
#include <strings.h>
#endif /*SYSV*/
#include "cproto.h"
#include "semantics.h"

/* Output a string to standard output. */
#define put_string(s) fputs(s, stdout)

/* Create a new string by joining two strings with a space between them.
 * Return a pointer to the resultant string or NULL if an error occurred.
 */
static char *
concat_string (a, b)
char	*a, *b;
{
    char	*result;

    if ((result = malloc((unsigned)(strlen(a) + strlen(b) + 2))) != NULL) {
	strcpy(result, a);
	strcat(result, " ");
	strcat(result, b);
    }
    return result;
}

/* Return TRUE if the given identifier is really a typedef name.
 * Search the symbol table for the identifier.
 */
boolean
is_typedef_name (name)
char *name;
{
    return (boolean)(find_symbol(typedef_names, name) != NULL);
}

/* Initialize a new declaration specifier part.
 */
void
new_decl_spec (decl_spec, text, flags)
DeclSpec	*decl_spec;
char		*text;
unsigned short	flags;
{
    decl_spec->text = strdup(text);
    decl_spec->flags = flags;
}

/* Append two declaration specifier parts together.
 */
void
join_decl_specs (result, a, b)
DeclSpec	*result, *a, *b;
{
    result->text = concat_string(a->text, b->text);
    result->flags = a->flags | b->flags;
    free(a->text);
    free(b->text);
}

/* Free storage used by a declaration specifier part.
 */
void
free_decl_spec (decl_spec)
DeclSpec	*decl_spec;
{
    free(decl_spec->text);
}

/* Initialize the parameter structure.
 */
void
new_parameter (param, decl_spec, declarator)
Parameter	*param;		/* pointer to structure to be initialized */
DeclSpec	*decl_spec;	/* declaration specifier structure */
Declarator	*declarator;	/* declarator structure */
{
    if (decl_spec == NULL) {
	new_decl_spec(&(param->decl_spec), "", "");
    } else {
	param->decl_spec = *decl_spec;
    }

    if (declarator == NULL) {
	new_declarator(&(param->declarator), "", "");
    } else {
	param->declarator = *declarator;
    }
}

/* Free the storage used by the parameter.
 */
void
free_parameter (param)
Parameter	*param;
{
    free_decl_spec(&(param->decl_spec));
    free_declarator(&(param->declarator));
}

/* Initialize a list of function parameters.
 */
void
new_param_list (param_list, param)
ParameterList	*param_list;
Parameter	*param;
{
    Parameter	*p;

    p = (Parameter *)malloc(sizeof(Parameter));
    *p = *param;
    
    param_list->first = param_list->last = p;
    p->next = NULL;
}

/* Add the function parameter declaration to the list.
 */
void
add_param_list (to, from, param)
ParameterList	*to, *from;
Parameter	*param;
{
    Parameter	*p;

    p = (Parameter *)malloc(sizeof(Parameter));
    *p = *param;

    to->first = from->first;
    from->last->next = p;
    to->last = p;
    p->next = NULL;
}

/* Free storage used by the elements in the function parameter list.
 */
void
free_param_list (param_list)
ParameterList	*param_list;
{
    Parameter	*p, *next;

    p = param_list->first;
    while (p != NULL) {
	next = p->next;
	free_parameter(p);
	free((char *)p);
	p = next;
    }
}

/* Initialize an empty list of function parameter names.
 */
void
new_ident_list (param_list)
ParameterList	*param_list;
{
    param_list->first = param_list->last = NULL;
}

/* Add an item to the list of function parameter declarations but set only
 * the parameter name field.
 */
void
add_ident_list (to, from, name)
ParameterList	*to, *from;
char		*name;
{
    Parameter	*p;
    Declarator	declarator;

    p = (Parameter *)malloc(sizeof(Parameter));
    new_declarator(&declarator, name, name);
    new_parameter(p, NULL, &declarator);

    to->first = from->first;
    if (to->first == NULL) {
	to->first = p;
    } else {
	from->last->next = p;
    }
    to->last = p;
    p->next = NULL;
}

/* Initialize a declarator.
 */
void
new_declarator (d, name, text)
Declarator	*d;
char		*name, *text;
{
    d->name = strdup(name);
    d->text = strdup(text);
    d->func_def = FUNC_NONE;
    d->paren_count = 0;
    d->params.first = d->params.last = NULL;
}

/* Free storage used by a declarator.
 */
void
free_declarator (d)
Declarator	*d;
{
    free(d->name);
    free(d->text);
    free_param_list(&(d->params));
}

/* Initialize a declarator list and add the given declarator to it.
 */
void
new_decl_list (decl_list, declarator)
DeclaratorList	*decl_list;
Declarator	*declarator;
{
    Declarator	*d;

    d = (Declarator *)malloc(sizeof(Declarator));
    *d = *declarator;

    decl_list->first = decl_list->last = d;
    d->next = NULL;
}

/* Add the declarator to the declarator list.
 */
void
add_decl_list (to, from, declarator)
DeclaratorList	*to, *from;
Declarator	*declarator;
{
    Declarator	*d;

    d = (Declarator *)malloc(sizeof(Declarator));
    *d = *declarator;

    to->first = from->first;
    from->last->next = d;
    to->last = d;
    to->last->next = NULL;
}

/* Free storage used by the declarators in the declarator list.
 */
void
free_decl_list (decl_list)
DeclaratorList	*decl_list;
{
    Declarator	*d, *next;

    d = decl_list->first;
    while (d != NULL) {
	next = d->next;
	free_declarator(d);
	free((char *)d);
	d = next;
    }
}

/* Search the list of parameters for a matching parameter name.
 * Return a pointer to the matching parameter or NULL if not found.
 */
static Parameter *
search_parameter_list (params, name)
ParameterList	*params;
char		*name;
{
    Parameter	*p;

    for (p = params->first; p != NULL; p = p->next) {
	if (strcmp(p->declarator.name, name) == 0)
	    return p;
    }
    return (Parameter *)NULL;
}

/* This is the core routine in the algorithm to convert traditional style
 * C function definitions to ANSI C prototypes.  For each name declared
 * in the declarator list, find the parameter with the matching name in the
 * parameter list and set that parameter's declaration specifier.
 */
void
set_param_types (params, decl_spec, declarators)
ParameterList	*params;
DeclSpec	*decl_spec;
DeclaratorList	*declarators;
{
    Declarator	*d;
    Parameter	*p;

    for (d = declarators->first; d != NULL; d = d->next) {
	/* Search the parameter list for a matching name. */
	p = search_parameter_list(params, d->name);
	if (p == NULL) {
	    print_error("declared argument \"%s\" is missing", d->name);
	} else {
	    p->decl_spec.text = strdup(decl_spec->text);
	    p->declarator.text = strdup(d->text);
	}
    }
}

/* Output a declaration specifier for an external declaration.
 */
static void
output_decl_spec (decl_spec)
DeclSpec	*decl_spec;
{
    if (extern_out && (decl_spec->flags & DE_STATIC) == 0) {
	if (strstr(decl_spec->text, "extern") == NULL) {
	    put_string("extern ");
	}
    }
    printf("%s ", decl_spec->text);
}

/* Output a declarator.
 */
static void
output_declarator (d)
Declarator	*d;
{
    static void	output_parameters();
    char	*s;

    if (d->func_def == FUNC_NONE) {
	put_string(d->text);
    } else {
	if ((s = strstr(d->text, "()")) != NULL) {
	    *(++s) = '\0';
	    put_string(d->text);
	    *s = ')';
	    output_parameters(&(d->params));
	    put_string(s);
	}
    }
}

/* Output a function parameter type and variable declaration.
 */
static void
output_parameter (p)
Parameter	*p;
{
    char	*s;

    put_string(p->decl_spec.text);
    if (proto_style == PROTO_TYPES && strlen(p->declarator.name) > 0) {
	s = strstr(p->declarator.text, p->declarator.name);
	*s = '\0';
	printf(" %s/*%s*/%s", p->declarator.text, p->declarator.name,
		s + strlen(p->declarator.name));
	*s = *(p->declarator.name);
    } else {
	if (strlen(p->declarator.text) > 0) {
	    putchar(' ');
	    output_declarator(&(p->declarator));
	}
    }
}

/* Output the list of function parameters.
 */
static void
output_parameters (params)
ParameterList	*params;
{
    Parameter	*p;

    if (proto_style == PROTO_TRADITIONAL)
	put_string("/*");

    p = params->first;
    if (p == NULL ||
        (strcmp(p->decl_spec.text, "void") == 0 &&
	 strlen(p->declarator.text) == 0)) {
	put_string("void");
    } else {
	put_string(first_param_prefix);
	output_parameter(p);
	p = p->next;
	while (p != NULL) {
	    putchar(',');
	    put_string(middle_param_prefix);
	    output_parameter(p);
	    p = p->next;
	}
	put_string(last_param_suffix);
    }

    if (proto_style == PROTO_TRADITIONAL)
	put_string("*/");
}

/* Output variable declarations.
 */
void
output_declarations (decl_spec, decl_list)
DeclSpec	*decl_spec;	/* declaration specifier */
DeclaratorList	*decl_list;	/* list of declared variables */
{
    Declarator	*d;

    if (!variables_out || (decl_spec->flags & DE_JUNK))
	return;
    if (!static_out && (decl_spec->flags & DE_STATIC))
	return;

    for (d = decl_list->first; d != NULL; d = d->next) {
	if (d->func_def == FUNC_NONE) {
	    put_string(variable_prefix);
	    output_decl_spec(decl_spec);
	    output_declarator(d);
	    put_string(";\n");
	}
    }
}

/* Output a function prototype.
 */
void
output_prototype (decl_spec, declarator)
DeclSpec	*decl_spec;
Declarator	*declarator;
{
    Parameter	*p;

    if (proto_style == PROTO_NONE)
	return;
    if (!static_out && (decl_spec->flags & DE_STATIC))
	return;

    /* Check for function parameters for which no type has been specified.
     * This happens when a parameter name appears in the function
     * declaration but does not appear in the parameter declaration part.
     * The default type in this cause is "int".
     */
    for (p = declarator->params.first; p != NULL; p = p->next) {
	if (strlen(p->decl_spec.text) == 0) {
	    free(p->decl_spec.text);
	    p->decl_spec.text = strdup("int");
	}
    }

    put_string(function_prefix);
    output_decl_spec(decl_spec);
    output_declarator(declarator);
    put_string(";\n");
}
@//E*O*F semantics.c//
chmod u=rw,g=r,o=r semantics.c
 
echo x - string.c
sed 's/^@//' > "string.c" <<'@//E*O*F string.c//'
/* $Id: string.c,v 1.2 90/01/04 22:32:12 cthuang Exp $
 *
 * Some string handling routines
 */
#include <stdio.h>
#ifdef SYSV
#include <string.h>
#else
#include <strings.h>
#endif /*SYSV*/

extern char	*malloc();

/* Copy the string into an allocated memory block.
 * Return a pointer to the copy.
 */
char *
strdup (s)
char	*s;
{
    char	*dest;

    if ((dest = malloc((unsigned)(strlen(s)+1))) != NULL)
	strcpy(dest, s);
    return dest;
}

/* Return a pointer to the first occurence of the substring 
 * within the string, or NULL if not found.
 */
char *
strstr (src, key)
char	*src, *key;
{
    char	*s;
    int		keylen;

    keylen = strlen(key);
    s = index(src, *key);
    while (s != NULL) {
	if (strncmp(s, key, keylen) == 0)
	    return s;
	s = index(s+1, *key);
    }
    return NULL;
}
@//E*O*F string.c//
chmod u=rw,g=r,o=r string.c
 
echo x - symbol.c
sed 's/^@//' > "symbol.c" <<'@//E*O*F symbol.c//'
/* $Id: symbol.c,v 1.2 90/01/04 22:32:21 cthuang Exp $
 *
 * Symbol table maintenance. Implements an abstract data type called
 * the symbol table.
 */
#include <stdio.h>
#include <strings.h>
#include "symbol.h"

extern char *malloc();

/* Create a symbol table.
 * Return a pointer to the symbol table or NULL if an error occurs.
 */
SymbolTable *
create_symbol_table ()
{
    SymbolTable *symtab;
    int i;

    if ((symtab = (SymbolTable *)malloc(sizeof(SymbolTable))) != NULL) {
	for (i = 0; i < SYM_MAX_HASH; ++i)
	    symtab->bucket[i] = NULL;
    }
    return symtab;
}


/* This is a simple hash function mapping a symbol name to a hash bucket. */

static int
hash (name)
char *name;
{
    return (name[0] + name[1] + strlen(name)) % SYM_MAX_HASH;
}


/* Search the list of symbols <list> for the symbol <name>.
 * Return a pointer to the symbol or NULL if not found.
 */
static Symbol *
search_symbol_list (list, name)
Symbol *list;
char *name;
{
    Symbol *sym;

    for (sym = list; sym != NULL; sym = sym->next) {
	if (strncmp(sym->name, name, SYM_MAX_LENGTH-1) == 0)
	    return sym;
    }
    return NULL;
}


/* Look for symbol <name> in symbol table <symtab>.
 * Return a pointer to the symbol or NULL if not found.
 */
Symbol *
find_symbol (symtab, name)
SymbolTable *symtab;
char *name;
{
    return search_symbol_list(symtab->bucket[hash(name)], name);
}


/* If the symbol <name> does not already exist in symbol table <symtab>,
 * then add the symbol to the symbol table.
 * Return a pointer to the symbol or NULL on an error.
 */
Symbol *
new_symbol (symtab, name)
SymbolTable *symtab;	/* symbol table */
char *name;		/* symbol name */
{
    Symbol	*sym;
    int		i;

    if ((sym = find_symbol(symtab, name)) == NULL) {
	if ((sym = (Symbol *)malloc(sizeof(Symbol))) != NULL) {
	    strncpy(sym->name, name, SYM_MAX_LENGTH-1);
	    sym->name[SYM_MAX_LENGTH-1] = '\0';

	    i = hash(name);
	    sym->next = symtab->bucket[i];
	    symtab->bucket[i] = sym;
	}
    }
    return sym;
}
@//E*O*F symbol.c//
chmod u=rw,g=r,o= symbol.c
 
exit 0
--
cthuang at watdragon.waterloo.edu
cthuang at watdragon.uwaterloo.ca
cthuang at watdragon.waterloo.cdn
uunet!watmath!watdragon!cthuang



More information about the Comp.sources.bugs mailing list