home *** CD-ROM | disk | FTP | other *** search
Text File | 1988-09-11 | 48.1 KB | 1,927 lines |
- Subject: v13i061: Check for mistakes in C programs
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Nick Crossley <ccicpg!nick@uunet.uu.net>
- Posting-number: Volume 13, Issue 61
- Archive-name: check
-
-
- This program has been posted as a result of a discussion in comp.lang.c
- concerning some possible errors in writing C programs. It is a C syntax
- checker, to be used as an adjunct to lint, not a replacement. It makes
- no attempt to duplicate any warning given by the standard lint, and is not
- at all forgiving about simple syntax errors.
-
- Warnings include things like "if (a = b);" nested comments, and dangling
- else's.
-
- See the README file for more details. If anyone implements the software
- metrics or upgrades the grammar significantly, please send the results
- back to me!
-
- Nick Crossley
- CCI
- email: ..!uunet!ccicpg!nick
-
- #! /bin/sh
- # This is a Shell Archive, containing the files/directories :-
- # Makefile README check.1 check.c check.h lex.l main.c metric.c parse.awk
- # parse.y symbol.c tables.sh test.c tree.c
-
- # To unpack it, execute it with /bin/sh
- # If run with standard input from a terminal, you will be prompted
- # for the name of a directory to hold the unpacked files.
- # Otherwise, it will unpack into the current directory.
-
- if [ -t 0 ]
- then
- while :
- do
- echo 'Directory for output : \c'
- read outdir
-
- if [ X$outdir = X ]
- then outdir=.
- break
- elif [ -d ${outdir} ]
- then break
- elif echo "$outdir does not exist; create it? \c"
- read reply
- [ `expr "$reply" : '[Yy].*'` = 0 ]
- then continue
- elif mkdir $outdir
- then break
- else echo "Cannot create $outdir" 1>&2
- continue
- fi
- done
- cd $outdir
- fi
-
- sed -e 's/^XX//' <<'====End of SHAR Makefile====' >Makefile
- XX# Makefile for C checker
- XX# Has been used on SysV and BSD/SysV mixtures
- XX# I don't guarantee it will work on real BSD
- XX# Set the following macros :-
- XX# CHECK if you want to change the program name
- XX# LIB for the installation directory
- XX# CFLAGS for cc flags
- XX# LDFLAGS for final cc flags
- XX# BLIBS for any other libraries to scan
- XX# LFLAGS for lex flags
- XX# YFLAGS for yacc flags
- XX# LINTF for lint flags
- XX
- XXCHECK = check
- XXLIB = bin
- XXCFLAGS = -O
- XXLDFLAGS =
- XXBLIBS =
- XXLFLAGS =
- XXYFLAGS = -vd
- XXLINTF =
- XX
- XXOBJ = main.o lex.o parse.o symbol.o tree.o check.o metric.o
- XXSRC = main.c lex.l parse.y symbol.c tree.c check.c metric.c
- XX
- XXbuild : $(CHECK)
- XX
- XXinstall : $(CHECK)
- XX cp $(CHECK) $(LIB)
- XX -touch install
- XX
- XX$(CHECK): $(OBJ)
- XX $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ) $(BLIBS) -lm
- XX
- XX$(OBJ) : y.xxx.h check.h
- XX
- XXtree.o : tables.h
- XX
- XXtables.h: y.xxx.h tables.sh
- XX tables.sh
- XX
- XXy.xxx.h : y.tab.h
- XX -cmp -s y.xxx.h y.tab.h || cp y.tab.h y.xxx.h
- XX
- XXy.tab.h : parse.c
- XX
- XX.y.c :; $(YACC) $(YFLAGS) $<
- XX mv y.tab.c $*.c
- XX parse.awk &
- XX
- XX.y.o :; $(YACC) $(YFLAGS) $<
- XX mv y.tab.c $*.c
- XX parse.awk &
- XX $(CC) $(CFLAGS) -c $*.c
- XX
- XX.l.o :; $(LEX) $(LFLAGS) $<
- XX mv lex.yy.c $*.c
- XX $(CC) $(CFLAGS) -c $*.c
- XX
- XX.c.o :; $(CC) $(CFLAGS) -c $*.c
- XX
- XXlist : $(SRC) Makefile
- XX pr -n -f -h "C Checker" $? | lp
- XX -touch list
- XX
- XXlint : $(OBJ:.o=.c) tables.h
- XX lint $(LINTF) $(OBJ:.o=.c)
- XX
- XXclean :; rm -f *.o y.* yacc* parse.c lex.c tables.h
- XX
- XXclobber : clean
- XX rm -f $(CHECK) list install
- ====End of SHAR Makefile====
- if [ "`wc -c <'Makefile'`" != ' 1426' ]
- then echo 'Unpack for Makefile failed!'
- exit 1
- else echo 'Unpacked Makefile'
- fi
- sed -e 's/^XX//' <<'====End of SHAR README====' >README
- XX C Program Checker
- XX -----------------
- XX
- XXThis program has been posted as a result of a discussion in comp.lang.c
- XXconcerning some possible errors in writing C programs. It is a C syntax
- XXchecker, to be used as an adjunct to lint, not a replacement. It makes
- XXno attempt to duplicate any warning given by the standard lint, and is not
- XXat all forgiving about simple syntax errors. It warns about the following
- XXpossible errors :-
- XX
- XX1. Assignment in conditional context
- XX A warning is issued for any assignment in any conditional context,
- XX where the programmer might have mistyped = when == was intended.
- XX Thus, 'if (a=b)' will give a warning, while 'if ((a=b)!=0)' will not.
- XX (NOTE: I am not saying that people should not write 'if (a=b)' and
- XX similar constructs - I frequently do - but that on SOME occasions
- XX programmers make typing errors which are not picked up by lint or cc,
- XX and are not easily visually seen as errors.)
- XX
- XX2. if with neither then nor else
- XX One of my colleagues once wrote
- XX if (a == b);
- XX {
- XX lots of useful code ...
- XX }
- XX and we spent a whole day tracking down why this was not doing as
- XX we expected before I noticed the extra semicolon. (The condition
- XX was actually more complicated, so the semicolon was not as obvious,
- XX and we spent our time working out why the condition did not appear
- XX to have the right value. We were also working on a machine which
- XX did not supply adb, only sdb, and that did not work!)
- XX
- XX3. I come from an Algol68 background, and I HATE the 'dangling-else'
- XX language ambiguity in C, Pascal, ...! So, not that I have ever
- XX seen it as a problem in practice, the program warns about potentially
- XX ambiguous elses :-
- XX
- XX if (a == b)
- XX if (c == d)
- XX action1 ();
- XX else action2 ();
- XX will generate a warning, while :-
- XX
- XX if (a == b)
- XX {
- XX if (c == d)
- XX action1 ();
- XX else action2 ();
- XX }
- XX will not.
- XX
- XX4. Nested comment
- XX I just added this as a result of further net discussion of errors;
- XX this will give a warning if '/*' is seen inside a comment, so that
- XX errors such as that below are noticed.
- XX a = 1; /* initialise a
- XX b = 2; /* initialise b */
- XX The current line number and that where the outer comment started are
- XX included in the warning message.
- XX
- XX5. Unterminated comment
- XX If end-of-file is reached while in a comment. This is also noticed
- XX by both cpp and cc, but check gives the line number where the comment
- XX started, not just the line number where the error was detected, i.e.,
- XX the last line!
- XX
- XX
- XXThe program uses yacc and lex. The grammar was written by me, and is not a
- XXcomplete C grammar - some obsolete or weird constructs are (deliberately) not
- XXsupported. ('Weird' as defined by me!!) No attempt has been made (yet) to
- XXsupport ANSI C. It is not very fast - profiling shows that most of the time
- XXis spent in the lex-generated analyser, as one might expect.
- XX
- XXThere is some code, mostly commented out, to calculate and print software
- XXmetrics, but this needs changes to the lexing, parsing and symbol handling
- XXwhich I have not yet done. If anyone completes this work, or has any improved
- XXmetrics to suggest, please send it back to me!
- XX
- XXAs an example, the output of 'check *.c' in the check source directory is :-
- XXlex.c: assignment in conditional context at or near line 163
- XXlex.c: assignment in conditional context at or near line 588
- XXlex.c: assignment in conditional context at or near line 616
- XXsymbol.c: assignment in conditional context at or near line 79
- XXtest.c: nested comment, starting at line 20, at or near line 21
- XXtest.c: unterminated comment, starting at line 194, at or near line 202
- XXtest.c: IF with neither THEN nor ELSE at or near line 93
- XXtest.c: potentially mismatched ELSE - use {} at or near line 117
- XXtest.c: assignment in conditional context at or near line 132
- XX
- XXThis program is in no way derived from lint sources, which I have not even
- XXlooked at, and is free of all copyright restrictions.
- XX
- XXWed Jan 20 1988
- XX
- XXNick Crossley
- XXComputer Consoles Inc.
- XX9801 Muirlands Boulevard,
- XXIrvine
- XXCA 92718
- XX(714) 458-7282
- XXemail: ...!uunet!ccicpg!nick
- ====End of SHAR README====
- if [ "`wc -c <'README'`" != ' 4011' ]
- then echo 'Unpack for README failed!'
- exit 1
- else echo 'Unpacked README'
- fi
- sed -e 's/^XX//' <<'====End of SHAR check.1====' >check.1
- XX.TH CHECK 1
- XX.SH NAME
- XXcheck \- a C program checker
- XX.SH SYNOPSIS
- XX.B check
- XX[ option ] ... file ...
- XX.SH DESCRIPTION
- XX.I Check\^
- XXattempts to find possible errors in C programs.
- XXIt does not duplicate or replace
- XX.I lint
- XXbut finds some constructs about which
- XX.I lint
- XXis silent.
- XXAmong the things that are detected are
- XXnested comments,
- XXunterminated comments,
- XXassignments in conditional contexts,
- XXif statements with null then and no else
- XXand
- XXpotentially ambiguous else statements
- XX.PP
- XXFor each such construct a warning is given,
- XXidentifying the source file and line number where it occurs.
- XXIf multiple files are being checked,
- XXthe name of each file is printed as checking starts.
- XX.PP
- XXAll leading '-' options are assumed to be C preprocessor directives,
- XXexcept that an argument '--' ends the options and is otherwise ignored.
- XXAll following arguments are assumed to be C source file names.
- XX.SH SEE ALSO
- XXcpp(1), lint(1).
- XX.SH BUGS
- XX.I Check\^
- XXis not at all forgiving of simple syntax errors,
- XXsuch as missing or extra punctuation.
- XX.PP
- XXThe grammar (deliberately) does not accept all currently legal C programs;
- XXsome obsolescent or weird constructs are not allowed.
- XXNo attempt has yet been made to handle ANSI C.
- ====End of SHAR check.1====
- if [ "`wc -c <'check.1'`" != ' 1193' ]
- then echo 'Unpack for check.1 failed!'
- exit 1
- else echo 'Unpacked check.1'
- fi
- sed -e 's/^XX//' <<'====End of SHAR check.c====' >check.c
- XX/*----------------------------------------------------------------------*/
- XX/* */
- XX/* This module contains the actual checking logic */
- XX/* */
- XX/*----------------------------------------------------------------------*/
- XX
- XX
- XX#include <stdio.h>
- XX#include "check.h"
- XX#include "y.tab.h"
- XX
- XX
- XX/*ARGSUSED*/
- XXvoid checknode (depth, parent, branch, np)
- XXint depth, parent, branch;
- XXNodePtr np;
- XX{
- XX /* This routine is called as an 'action' by treewalk. */
- XX /* It checks for the following things :- */
- XX /* 1) assignment in conditional contexts; */
- XX /* 2) potentially mismatched ELSE clauses; */
- XX /* 3) IFs with no THEN or ELSE. */
- XX
- XX
- XX if (np->type == Asgn_Op)
- XX {
- XX if ((parent == IF && branch == 1) ||
- XX (parent == WHILE && branch == 1) ||
- XX (parent == DO && branch == 2) ||
- XX (parent == FOR && branch == 2) ||
- XX parent == And || parent == Or)
- XX
- XX warn ("assignment in conditional context");
- XX }
- XX
- XX if (np->type == IF && np->f3.ptr == NilNode) /* IF with no ELSE */
- XX {
- XX if (np->f2.ptr == NilNode ||
- XX np->f2.ptr->type == 0 || np->f2.ptr->type == ';')
- XX warn ("IF with neither THEN nor ELSE");
- XX
- XX if (np->f2.ptr->type==IF && np->f2.ptr->f3.ptr!=NilNode)
- XX warn ("potentially mismatched ELSE - use {}");
- XX }
- XX}
- XX
- XX
- XXvoid check_prog ()
- XX{
- XX /* Start off the checking process */
- XX
- XX walk_prog (checknode);
- XX}
- ====End of SHAR check.c====
- if [ "`wc -c <'check.c'`" != ' 1304' ]
- then echo 'Unpack for check.c failed!'
- exit 1
- else echo 'Unpacked check.c'
- fi
- sed -e 's/^XX//' <<'====End of SHAR check.h====' >check.h
- XX/*=========== Header file for C Checker Program ================*/
- XX
- XX#define elif else if
- XX#define TRUE 1
- XX#define FALSE 0
- XX#define Printf (void) printf
- XX#define Fprintf (void) fprintf
- XX#define NilNode ((NodePtr) 0)
- XX#define NilSym ((Symbol *) 0)
- XX
- XX
- XX/*=========== Type Definitions ================*/
- XX
- XXtypedef int Token; /* type of Lex tokens */
- XX
- XXtypedef enum {
- XX Find, /* Find only */
- XX Create /* Find and create if required */
- XX} Action;
- XX
- XXtypedef struct Symbol { /* type of Symbol Table Entry */
- XX char *name;
- XX Token token;
- XX struct Symbol *next;
- XX} Symbol;
- XX
- XXtypedef struct Node { /* type of Parse Tree Node */
- XX short type; /* variant for a node */
- XX short line; /* source line number */
- XX union u {
- XX int ival; /* integer value */
- XX unsigned uval; /* unsigned value */
- XX struct Node *ptr; /* pointer to another node */
- XX } f1, f2, f3, f4; /* variable number of fields */
- XX} Node, *NodePtr; /* Node and pointer to Node */
- XX
- XX
- XX/*=========== Parse Tree Node Types ================*/
- XX
- XX#define Seq 1000 /* a sequence of two nodes */
- XX#define Type 1001 /* a type specifier */
- XX#define Label 1002 /* a labelled statement */
- XX#define Pre_Inc 1003 /* ++ (expression) */
- XX#define Pre_Dec 1004 /* -- (expression) */
- XX#define Post_Inc 1005 /* (expression) ++ */
- XX#define Post_Dec 1006 /* (expression) -- */
- XX#define Indirect 1007 /* a -> b */
- XX#define Addr 1008 /* & id */
- XX#define Uplus 1009 /* + expression */
- XX#define Uminus 1010 /* - expression */
- XX#define Cast 1011 /* (type) expression */
- XX#define Size_Type 1012 /* SIZEOF (type) */
- XX#define Size_Expr 1013 /* SIZEOF (expression) */
- XX#define Error 9999 /* error */
- XX
- XX
- XX/*=========== External Function Definitions ================*/
- XX
- XXextern void lex_init (); /* Lexical Analyser initialise */
- XXextern Token yylex (); /* Lexical Analyser interface */
- XX
- XXextern void sy_init (); /* Initialise symbol table */
- XXextern void sy_tidy (); /* Tidy symbol table */
- XXextern Symbol *findsym (); /* look up identifier in table */
- XXextern char *emalloc (); /* allocate space */
- XX
- XXextern int yyparse (); /* interface to Yacc Parser */
- XX
- XXextern NodePtr new_node (); /* build a parse tree node */
- XXextern void check_prog (); /* check the parse tree */
- XXextern void tidy_prog (); /* delete the parse tree */
- XXextern void walk_prog (); /* walk the parse tree */
- XXextern void treeprint (); /* print the parse tree */
- XX
- XXextern void metrics (); /* produce software metrics */
- XXextern void met_init (); /* initialise metrics */
- XXextern void proc_start (); /* initialise local metrics */
- XX
- XXextern void yyerror (); /* Yacc syntax error report */
- XXextern void warn (); /* generate warning messages */
- XXextern void error (); /* stop with error message */
- XXextern void setline (); /* set line and filename */
- XX
- XX
- XX/*=========== External Data Definitions ================*/
- XX
- XXextern int yychar; /* current lookahead token */
- XXextern char *filename; /* current filename */
- XXextern int yylineno; /* current line number */
- XXextern FILE *yyin; /* current input file */
- XXextern NodePtr Tree; /* Root of Parse Tree */
- ====End of SHAR check.h====
- if [ "`wc -c <'check.h'`" != ' 3136' ]
- then echo 'Unpack for check.h failed!'
- exit 1
- else echo 'Unpacked check.h'
- fi
- sed -e 's/^XX//' <<'====End of SHAR lex.l====' >lex.l
- XX%{
- XX/*----------------------------------------------------------------------*/
- XX/* */
- XX/* LEX generated C lexical analyser */
- XX/* */
- XX/*----------------------------------------------------------------------*/
- XX
- XX#include "check.h"
- XX#include "y.tab.h"
- XX
- XX#define yywrap() (1)
- XX
- XXextern Token ident ();
- XXextern void strings (), comment (); /* forward declarations */
- XX%}
- XX
- XXD [0-9]
- XXNUM ({D}+|({D}+"."{D}*)|("."{D}+))([eE][-+]?{D}+)?[lL]?
- XXHEX 0[xX][0-9a-fA-F]+[lL]?
- XXID [A-Za-z_][A-Za-z0-9_]*
- XXASG ([-+*/%&^|]?"=")|"<<="|">>="
- XX
- XX%%
- XX
- XX^"#".*"\n" { setline (yytext); }
- XX{ID} { return ident(); }
- XX{NUM} { return CONSTANT; }
- XX{HEX} { return CONSTANT; }
- XX{ASG} { return Asgn_Op; }
- XX"\"" { strings ('"'); return CONSTANT; }
- XX"'" { strings ('\''); return CONSTANT; }
- XX"<<" { return Shift; }
- XX">>" { return Shift; }
- XX"&&" { return And; }
- XX"||" { return Or; }
- XX"->" { return Point; }
- XX"<"|"<="|">="|">" { return Rel_Op; }
- XX"=="|"!=" { return Eq_Op; }
- XX"++"|"--" { return IncDec; }
- XX[ \t\n]+ ;
- XX"/*" { comment (); }
- XX. { return yytext[0]; }
- XX
- XX%%
- XX
- XXToken ident ()
- XX{
- XX /* Handle an Identifier or Reserved Word */
- XX
- XX yylval.id = findsym (yytext, IDENTIFIER, Create);
- XX return yylval.id->token;
- XX}
- XX
- XX
- XXvoid cwarn (ln, s)
- XXint ln;
- XXchar *s;
- XX{
- XX /* Give a warning about a comment, including starting line number */
- XX
- XX
- XX char msg [120];
- XX (void) sprintf (msg, "%s, starting at line %d,", s, ln);
- XX warn (msg);
- XX free (msg);
- XX}
- XX
- XX
- XXvoid comment ()
- XX{
- XX /* Swallow the rest of a comment */
- XX
- XX register int c = input ();
- XX register int startline = yylineno;
- XX
- XX while (c)
- XX {
- XX if (c == '*')
- XX {
- XX if ((c = input()) == '/') return;
- XX }
- XX elif (c == '/')
- XX {
- XX if ((c = input()) != '*') continue;
- XX cwarn (startline, "nested comment");
- XX }
- XX else c = input();
- XX }
- XX cwarn (startline, "unterminated comment");
- XX}
- XX
- XX
- XXvoid strings (term)
- XXint term;
- XX{
- XX /* A string terminating with 'term' */
- XX
- XX register int c;
- XX
- XX while (c = input ())
- XX {
- XX if (c == term) break;
- XX elif (c == '\\') (void) input ();
- XX }
- XX}
- XX
- XX
- XXvoid lex_init ()
- XX{
- XX /* Initialise the Lexical Analyser for a new file */
- XX /* lex itself should provide this! */
- XX
- XX yyleng = 0;
- XX yymorfg = 0;
- XX yytchar = 0;
- XX yybgin = yysvec+1;
- XX yylineno = 1;
- XX yysptr = yysbuf;
- XX yyprevious = YYNEWLINE;
- XX}
- ====End of SHAR lex.l====
- if [ "`wc -c <'lex.l'`" != ' 2254' ]
- then echo 'Unpack for lex.l failed!'
- exit 1
- else echo 'Unpacked lex.l'
- fi
- sed -e 's/^XX//' <<'====End of SHAR main.c====' >main.c
- XX/*----------------------------------------------------------------------*/
- XX/* */
- XX/* C Checker Main Entry Point */
- XX/* */
- XX/*----------------------------------------------------------------------*/
- XX
- XX
- XX#include <stdio.h>
- XX#include <ctype.h>
- XX#include "check.h"
- XX#include "y.tab.h"
- XX
- XX#define MAXNAME 120
- XX#define CPP "/lib/cpp -C %s %s"
- XX
- XXextern void perror(), exit();
- XX
- XXint errors = 0; /* count of number of errors */
- XXchar filebuf [MAXNAME]; /* Buffer for file names */
- XXchar *filename; /* Pointer to file name */
- XXchar *progname; /* Name of this program */
- XX
- XX/* Really should recode this to avoid using fixed buffer sizes; */
- XX/* malloc and realloc are not difficult to use! */
- XXchar options [BUFSIZ]; /* Buffer for cpp options */
- XX
- XX
- XXint main (argc, argv)
- XXint argc;
- XXchar *argv[];
- XX{
- XX /* Main Entry Point to C Checker */
- XX /* Check each file as specified by arguments */
- XX
- XX char command [BUFSIZ]; /* for cpp command */
- XX register char *opts = options;
- XX register char *opt_end = & options [BUFSIZ-2];
- XX register int pnames;
- XX register int ptree = FALSE;
- XX extern char *strncat ();
- XX extern FILE *popen ();
- XX
- XX sy_init ();
- XX progname = *argv++;
- XX
- XX /* Extract C PreProcessor options */
- XX
- XX while (--argc && **argv == '-')
- XX {
- XX register char *ap = *argv++;
- XX
- XX if (strcmp ("--", ap) == 0)
- XX {
- XX /* End of Options */
- XX
- XX break;
- XX }
- XX#if YYDEBUG
- XX elif (strcmp ("-yydebug", ap) == 0)
- XX {
- XX /* Turn on Yacc Tracing */
- XX
- XX extern int yydebug;
- XX yydebug = 1;
- XX }
- XX#endif
- XX elif (strcmp ("-TP", ap) == 0)
- XX {
- XX /* Print Parse Tree option (debug) */
- XX
- XX ptree = TRUE;
- XX }
- XX else
- XX {
- XX /* C PreProcessor option */
- XX
- XX while (*ap && (opts < opt_end)) *opts++ = *ap++;
- XX *opts++ = ' ';
- XX }
- XX }
- XX *opts++ = ' ';
- XX *opts++ = '\0';
- XX
- XX pnames = argc - 1;
- XX while (argc--)
- XX {
- XX /* Open a pipe for reading from C PreProcessor */
- XX
- XX filename = *argv++;
- XX (void) sprintf (command, CPP, options, filename);
- XX if (pnames > 0) Printf ("%s:\n", filename);
- XX
- XX if ((yyin = popen (command, "r")) == NULL)
- XX {
- XX perror ("cannot open pipe");
- XX exit (1);
- XX }
- XX else
- XX {
- XX /* Analyse one C source file */
- XX
- XX lex_init ();
- XX met_init ();
- XX if (yyparse ()) warn ("fatal syntax error");
- XX
- XX /* Report on results of analysis */
- XX
- XX if (ptree) treeprint ();
- XX check_prog ();
- XX metrics ((char *) 0);
- XX
- XX /* Tidy up, ready for another source file */
- XX
- XX (void) pclose (yyin);
- XX tidy_prog ();
- XX sy_tidy ();
- XX }
- XX }
- XX
- XX return errors;
- XX}
- XX
- XX
- XXchar *emalloc (n)
- XXunsigned n;
- XX{
- XX /*==== Allocate Memory ====*/
- XX
- XX char *p, *malloc ();
- XX
- XX p = malloc (n);
- XX
- XX if (p == 0) error ("out of memory");
- XX
- XX return p;
- XX}
- XX
- XX
- XXvoid yyerror (s)
- XXchar *s;
- XX{
- XX /* Syntax Error from Yacc */
- XX
- XX errors++;
- XX Fprintf (stderr, "%s: %s at or near line %d, token %d\n",
- XX filename, s, yylineno, yychar);
- XX}
- XX
- XX
- XXvoid warn (s)
- XXchar *s;
- XX{
- XX /* Generate a warning message */
- XX
- XX errors++;
- XX Fprintf (stderr, "%s: %s at or near line %d\n",
- XX filename, s, yylineno);
- XX}
- XX
- XX
- XXvoid error (s)
- XXchar *s;
- XX{
- XX /* Handle fatal errors */
- XX
- XX warn (s);
- XX exit (errors);
- XX}
- XX
- XX
- XXvoid setline (line)
- XXchar *line;
- XX{
- XX /* Handle a #line directive */
- XX
- XX register char *cp = line;
- XX register char *fn = filebuf;
- XX register int lnum = 0;
- XX
- XX if (*cp != '#') error ("invalid call to setline");
- XX
- XX while (*cp && !isdigit(*cp)) cp++;
- XX while (*cp && isdigit (*cp)) lnum = lnum*10 + (*cp++ - '0');
- XX while (*cp && *cp != '"') cp++;
- XX if (lnum) yylineno = lnum;
- XX
- XX if (*cp++ == 0) return;
- XX while (*cp && *cp != '"') *fn++ = *cp++;
- XX if (fn == filename) return;
- XX
- XX *fn = '\0';
- XX filename = filebuf;
- XX}
- ====End of SHAR main.c====
- if [ "`wc -c <'main.c'`" != ' 3532' ]
- then echo 'Unpack for main.c failed!'
- exit 1
- else echo 'Unpacked main.c'
- fi
- sed -e 's/^XX//' <<'====End of SHAR metric.c====' >metric.c
- XX/*----------------------------------------------------------------------*/
- XX/* */
- XX/* This module will do software metrics one day... */
- XX/* */
- XX/*----------------------------------------------------------------------*/
- XX
- XX
- XX#include <stdio.h>
- XX#include "check.h"
- XX#include "y.tab.h"
- XX
- XXtypedef struct Metric {
- XX int sep_nouns;
- XX int sep_verbs;
- XX int tot_nouns;
- XX int tot_verbs;
- XX int stmts;
- XX int comments;
- XX int lines;
- XX int decisions;
- XX int knots;
- XX} Metric;
- XX
- XXMetric total, local;
- XX
- XX
- XXvoid swm (m)
- XXMetric *m;
- XX{
- XX /* This procedure will print the Software Metrics */
- XX
- XX/* Commented out until Lex & Grammar re-written to increment counts ...
- XX extern double log();
- XX
- XX double vocab, length, volume, diff, effort, lang;
- XX double decid, comms, layout;
- XX double mccabe, knots;
- XX
- XX vocab = m->sep_verbs + m->sep_nouns;
- XX length = m->tot_verbs + m->tot_nouns;
- XX volume = length * log(vocab) / log(2.0);
- XX diff = (m->sep_verbs*m->tot_nouns)/(2.0*m->sep_nouns);
- XX effort = volume * diff;
- XX lang = volume / (diff * diff);
- XX
- XX decid = m->decisions / m->stmts;
- XX comms = m->comments / m->stmts;
- XX layout = (m->stmts + m->comments) / m->lines;
- XX
- XX mccabe = m->decisions + 1;
- XX knots = m->knots;
- XX
- XX Printf ("%8.2g %8.2g %8.2g %8.2g %8.2g %8.2g %8.2g\n",
- XX volume, diff, effort, lang,
- XX decid, comms, layout,
- XX mccabe, knots
- XX );
- XX............................................................ */
- XX}
- XX
- XX
- XXvoid metrics (this_proc)
- XXchar *this_proc;
- XX{
- XX /* Report on the Software Metrics for current procedure, or */
- XX /* report on the total for the file if this_proc is null. */
- XX
- XX/* Commented out until Lex re-written to increment counts ...
- XX if (this_proc)
- XX {
- XX Printf ("%12.10s ", this_proc);
- XX swm (&local);
- XX }
- XX else
- XX {
- XX Printf ("%12.10s ", "Total:");
- XX swm (&total);
- XX }
- XX............................................................ */
- XX}
- XX
- XX
- XXvoid proc_start ()
- XX{
- XX /* Initialise the counts for a procedure */
- XX
- XX local.sep_nouns = 1;
- XX local.sep_verbs = 1;
- XX local.tot_nouns = 1;
- XX local.tot_verbs = 1;
- XX local.stmts = 1;
- XX local.comments = 1;
- XX local.lines = 1;
- XX local.decisions = 1;
- XX local.knots = 1;
- XX}
- XX
- XX
- XXvoid met_init ()
- XX{
- XX /* Initialise the counts for a file */
- XX
- XX proc_start ();
- XX
- XX total.sep_nouns = 1;
- XX total.sep_verbs = 1;
- XX total.tot_nouns = 1;
- XX total.tot_verbs = 1;
- XX total.stmts = 1;
- XX total.comments = 1;
- XX total.lines = 1;
- XX total.decisions = 1;
- XX total.knots = 1;
- XX}
- ====End of SHAR metric.c====
- if [ "`wc -c <'metric.c'`" != ' 2326' ]
- then echo 'Unpack for metric.c failed!'
- exit 1
- else echo 'Unpacked metric.c'
- fi
- sed -e 's/^XX//' <<'====End of SHAR parse.awk====' >parse.awk
- XXawk '
- XXBEGIN { state = 0; }
- XX/^state/ { --state; }
- XX/shift\/reduce/ { state = 2; }
- XX/reduce\/reduce/ { state = 2; }
- XX/terminals,/ { state = 2; }
- XX { if (state > 0) printf "%s\n", $0; }
- XX
- XX' y.output >yacclist
- ====End of SHAR parse.awk====
- chmod +x parse.awk
- if [ "`wc -c <'parse.awk'`" != ' 208' ]
- then echo 'Unpack for parse.awk failed!'
- exit 1
- else echo 'Unpacked parse.awk'
- fi
- sed -e 's/^XX//' <<'====End of SHAR parse.y====' >parse.y
- XX/* YACC Grammar for C - not very strict. */
- XX/* No attempt is made to conform to or accept */
- XX/* ANSI C yet. Some obsolete constructs are */
- XX/* not supported (deliberately). */
- XX/* */
- XX/* If your terminal can handle it, view/edit this */
- XX/* file in 120 or 132 column mode, as all the */
- XX/* actions start in column 72. */
- XX/* */
- XX/* Note that TYPEDEF names must be recognised as */
- XX/* such, and return a different token from the */
- XX/* Lexical Analyser. */
- XX/* */
- XX/* The Actions build a Parse Tree. */
- XX
- XX%{
- XX#include <stdio.h>
- XX#include "check.h"
- XX
- XX
- XX /*---------- Macros for Tree Building ----------*/
- XX
- XX
- XX#define Z (NodePtr) 0
- XX#define node0(t) new_node (t, Z, Z, Z, Z);
- XX#define node1(t,a) new_node (t, a, Z, Z, Z);
- XX#define node2(t,a,b) new_node (t, a, b, Z, Z);
- XX#define node3(t,a,b,c) new_node (t, a, b, c, Z);
- XX#define node4(t,a,b,c,d) new_node (t, a, b, c, d);
- XX
- XX%}
- XX
- XX%union { /* Type for Parser Stack */
- XX Symbol *id; /* Name for ID, or string */
- XX int ival; /* integer constants */
- XX unsigned uval; /* octal & hex constants */
- XX NodePtr ptr; /* pointer to Parse Tree Node */
- XX}
- XX
- XX%token <id> IDENTIFIER TYPENAME
- XX
- XX%token <ival> CONSTANT
- XX
- XX%token AUTO BREAK CASE CHAR
- XX CONTINUE DEFAULT DO DOUBLE
- XX ELSE ENUM EXTERN FLOAT
- XX FOR GOTO IF INT
- XX LONG REGISTER RETURN SHORT
- XX SIZEOF STATIC STRUCT SWITCH
- XX TYPEDEF UNION UNSIGNED VOID
- XX WHILE
- XX
- XX Shift And Or Rel_Op
- XX Eq_Op IncDec Asgn_Op Point
- XX
- XX%right Asgn_Op
- XX%right '?' ':'
- XX%left Or
- XX%left And
- XX%left '|'
- XX%left '^'
- XX%left '&'
- XX%left Eq_Op
- XX%left Rel_Op
- XX%left Shift
- XX%left '+' '-'
- XX%left '*' '/' '%'
- XX%left Prefix
- XX%left SizeOf
- XX%left IncDec Point '.'
- XX%left '[' '('
- XX
- XX%type <id> declarator
- XX
- XX%type <ptr> top_level_decls top_level_decl function_decl
- XX type_name compound statements
- XX statement label expr_opt
- XX expr_list expression tag
- XX
- XX%%
- XX
- XX
- XX/*-------------------------- DECLARATIONS -------------------------------*/
- XX
- XX
- XXprogram : top_level_decls { Tree = $1; }
- XX ;
- XX
- XXtop_level_decls : /* empty */ { proc_start(); $$ = node0 (0); }
- XX | top_level_decls top_level_decl { proc_start(); $$ = node2 (Seq, $1, $2); }
- XX ;
- XX
- XXtop_level_decl : function_decl { $$ = $1; }
- XX | declaration { $$ = node0 (0); }
- XX | error '}' { $$ = node0 (Error); }
- XX | error ';' { $$ = node0 (Error); }
- XX ;
- XX
- XXfunction_decl : specifiers declarator declarations compound { $$ = $4; metrics ($2->name); }
- XX | declarator declarations compound { $$ = $3; metrics ($1->name); }
- XX ;
- XX
- XXdeclarations : /* empty */
- XX | declarations declaration
- XX ;
- XX
- XXdeclaration : specifiers init_dclrtrs ';'
- XX | specifiers ';'
- XX ;
- XX
- XXspecifiers : storage
- XX | storage type_spec
- XX | type_spec
- XX ;
- XX
- XXstorage : AUTO
- XX | EXTERN
- XX | REGISTER
- XX | STATIC
- XX ;
- XX
- XXtype_spec : int_spec
- XX | UNSIGNED int_spec
- XX | UNSIGNED
- XX | float_spec
- XX | enum_spec
- XX | struct_spec
- XX | union_spec
- XX | TYPENAME
- XX | VOID
- XX ;
- XX
- XXdeclarator : IDENTIFIER { $$ = $1; }
- XX | '(' declarator ')' { $$ = $2; }
- XX | declarator '(' parameter_list ')' { $$ = $1; }
- XX | declarator '(' ')' { $$ = $1; }
- XX | declarator '[' expr_opt ']' { $$ = $1; }
- XX | '*' declarator %prec Prefix { $$ = $2; }
- XX ;
- XX
- XXparameter_list : IDENTIFIER
- XX | parameter_list ',' IDENTIFIER
- XX ;
- XX
- XXinit_dclrtrs : declarator
- XX | declarator Asgn_Op initialiser
- XX | init_dclrtrs ',' declarator
- XX | init_dclrtrs ',' declarator Asgn_Op initialiser
- XX ;
- XX
- XXinitialiser : expression
- XX | '{' init_list '}'
- XX | '{' init_list ',' '}'
- XX ;
- XX
- XXinit_list : initialiser
- XX | init_list ',' initialiser
- XX ;
- XX
- XXdeclaration : TYPEDEF type_spec type_decls ';'
- XX ;
- XX
- XXtype_decls : declarator { $1->token = TYPENAME; }
- XX | type_decls ',' declarator { $3->token = TYPENAME; }
- XX ;
- XX
- XX
- XX/*---------------------------- TYPES ----------------------------------*/
- XX
- XX
- XXint_spec : CHAR | SHORT | SHORT INT | INT | LONG INT | LONG ;
- XXfloat_spec : FLOAT | LONG FLOAT | DOUBLE ;
- XX
- XXenum_spec : ENUM IDENTIFIER
- XX | ENUM IDENTIFIER '{' enum_fields '}'
- XX | ENUM '{' enum_fields '}'
- XX ;
- XX
- XXstruct_spec : STRUCT IDENTIFIER
- XX | STRUCT IDENTIFIER '{' struct_fields '}'
- XX | STRUCT '{' struct_fields '}'
- XX ;
- XX
- XXunion_spec : UNION IDENTIFIER
- XX | UNION IDENTIFIER '{' struct_fields '}'
- XX | UNION '{' struct_fields '}'
- XX ;
- XX
- XXenum_fields : enum_const
- XX | enum_fields ',' enum_const
- XX ;
- XX
- XXenum_const : IDENTIFIER
- XX | IDENTIFIER Asgn_Op expression
- XX ;
- XX
- XXstruct_fields : type_spec field_list ';'
- XX | struct_fields type_spec field_list ';'
- XX | error ';'
- XX ;
- XX
- XXfield_list : field
- XX | field_list ',' field
- XX ;
- XX
- XXfield : declarator
- XX | declarator ':' expression
- XX | ':' expression
- XX ;
- XX
- XXtype_name : type_spec { $$ = node0 (Type); }
- XX | type_spec abstract { $$ = node0 (Type); }
- XX ;
- XX
- XXabstract : '(' abstract ')'
- XX | '(' ')'
- XX | abstract '(' ')'
- XX | '[' expr_opt ']'
- XX | abstract '[' expr_opt ']'
- XX | '*' %prec Prefix
- XX | '*' abstract %prec Prefix
- XX ;
- XX
- XX
- XX/*-------------------------- STATEMENTS --------------------------------*/
- XX
- XX
- XXcompound : '{' declarations statements '}' { $$ = node1 (Seq, $3); }
- XX | '{' '}' { $$ = node0 (0); }
- XX | error '}' { $$ = node0 (Error); }
- XX ;
- XX
- XXstatements : statement { $$ = $1; }
- XX | statements statement { $$ = node2 (Seq, $1, $2); }
- XX ;
- XX
- XXstatement : expr_list ';' { $$ = $1; }
- XX | label ':' statement { $$ = node2 (Label, $1, $3); }
- XX | compound { $$ = $1; }
- XX | IF '(' expr_list ')' statement { $$ = node3 (IF, $3, $5, Z); }
- XX | IF '(' expr_list ')' statement ELSE statement { $$ = node3 (IF, $3, $5, $7); }
- XX | WHILE '(' expr_list ')' statement { $$ = node2 (WHILE, $3, $5); }
- XX | DO statement WHILE '(' expr_list ')' ';' { $$ = node2 (DO, $2, $5); }
- XX | FOR '(' expr_opt ';' expr_opt ';' expr_opt ')'
- XX statement { $$ = node4 (FOR, $3, $5, $7, $9); }
- XX | SWITCH '(' expr_list ')' statement { $$ = node2 (SWITCH, $3, $5); }
- XX | BREAK ';' { $$ = node0 (BREAK); }
- XX | CONTINUE ';' { $$ = node0 (CONTINUE); }
- XX | RETURN expr_opt ';' { $$ = node1 (RETURN, $2); }
- XX | GOTO tag ';' { $$ = node1 (GOTO, Z); }
- XX | ';' { $$ = node0 (';'); }
- XX | error ';' { $$ = node0 (Error); }
- XX ;
- XX
- XXlabel : tag { $$ = $1; }
- XX | CASE expression { $$ = node1 (CASE, $2); }
- XX | DEFAULT { $$ = node0 (DEFAULT); }
- XX ;
- XX
- XX
- XX/*--------------------------- EXPRESSIONS -------------------------------*/
- XX
- XX
- XXexpr_opt : /* empty */ { $$ = node0 (0); }
- XX | expr_list { $$ = $1; }
- XX ;
- XX
- XXexpr_list : expression { $$ = $1; }
- XX | expr_list ',' expression { $$ = node2 (',', $1, $3); }
- XX ;
- XX
- XXexpression : expression Asgn_Op expression { $$ = node2 (Asgn_Op, $1, $3); }
- XX | expression '?' expr_list ':' expression { $$ = node3 ('?', $1, $3, $5); }
- XX | expression Or expression { $$ = node2 (Or, $1, $3); }
- XX | expression And expression { $$ = node2 (And, $1, $3); }
- XX | expression '|' expression { $$ = node2 ('|', $1, $3); }
- XX | expression '^' expression { $$ = node2 ('^', $1, $3); }
- XX | expression '&' expression { $$ = node2 ('&', $1, $3); }
- XX | expression Eq_Op expression { $$ = node2 (Eq_Op, $1, $3); }
- XX | expression Rel_Op expression { $$ = node2 (Rel_Op, $1, $3); }
- XX | expression Shift expression { $$ = node2 (Shift, $1, $3); }
- XX | expression '+' expression { $$ = node2 ('+', $1, $3); }
- XX | expression '-' expression { $$ = node2 ('-', $1, $3); }
- XX | expression '*' expression { $$ = node2 ('*', $1, $3); }
- XX | expression '/' expression { $$ = node2 ('/', $1, $3); }
- XX | expression '%' expression { $$ = node2 ('%', $1, $3); }
- XX | '*' expression %prec Prefix { $$ = node1 (Indirect, $2); }
- XX | '&' expression %prec Prefix { $$ = node1 (Addr, $2); }
- XX | '+' expression %prec Prefix { $$ = node1 (Uplus, $2); }
- XX | '-' expression %prec Prefix { $$ = node1 (Uminus, $2); }
- XX | '!' expression %prec Prefix { $$ = node1 ('!', $2); }
- XX | '~' expression %prec Prefix { $$ = node1 ('~', $2); }
- XX | '(' type_name ')' expression %prec Prefix { $$ = node2 (Cast, $2, $4); }
- XX | IncDec expression %prec Prefix { $$ = node1 (Pre_Inc, $2); }
- XX | SIZEOF '(' type_name ')' %prec SizeOf { $$ = node1 (Size_Type, $3); }
- XX | SIZEOF expression %prec SizeOf { $$ = node1 (Size_Expr, $2); }
- XX | expression IncDec { $$ = node1 (Post_Inc, $1); }
- XX | expression Point tag { $$ = node2 (Point, $1, $3); }
- XX | expression '.' tag { $$ = node2 ('.', $1, $3); }
- XX | expression '(' ')' { $$ = node2 ('(', $1, Z); }
- XX | expression '(' expr_list ')' { $$ = node2 ('(', $1, $3); }
- XX | expression '[' expr_list ']' { $$ = node2 ('[', $1, $3); }
- XX | '(' expr_list ')' { $$ = $2; }
- XX | tag { $$ = $1; }
- XX | CONSTANT { $$ = node1 (CONSTANT, Z); }
- XX ;
- XX
- XXtag : IDENTIFIER { $$ = node1 (IDENTIFIER, (NodePtr) $1); }
- XX ;
- ====End of SHAR parse.y====
- if [ "`wc -c <'parse.y'`" != ' 8625' ]
- then echo 'Unpack for parse.y failed!'
- exit 1
- else echo 'Unpacked parse.y'
- fi
- sed -e 's/^XX//' <<'====End of SHAR symbol.c====' >symbol.c
- XX/*----------------------------------------------------------------------*/
- XX/* */
- XX/* This module handles a symbol/type hash table */
- XX/* */
- XX/*----------------------------------------------------------------------*/
- XX
- XX
- XX#include <stdio.h>
- XX#ifdef BSD
- XX#include <strings.h>
- XX#define memset(p,c,n) {register int i;for(i=0;i<(n);i++)(p)[i]=(c);}
- XX#else
- XX#include <string.h>
- XX#include <memory.h>
- XX#endif
- XX#include "check.h"
- XX#include "y.tab.h"
- XX
- XX#define HASH_SIZE 1000 /* Allow for 750 names at 75% full */
- XX
- XXunsigned hsize; /* Size of the hash table */
- XXSymbol **htable; /* Pointer to an array of ponters to hash entries */
- XX
- XX#ifdef DEBUG
- XXunsigned *hcount; /* Pointer to an array of hash counts */
- XX#endif
- XX
- XX
- XXunsigned hash (key)
- XXregister char *key;
- XX{
- XX /* Hash a key string */
- XX
- XX register unsigned hval = 0;
- XX
- XX while (*key) hval = (hval << 3) + (hval >> 29) + *key++;
- XX
- XX hval = (hval & 0x7fffffff) % hsize;
- XX return hval;
- XX}
- XX
- XX
- XXvoid mkhash (size)
- XXunsigned size; /* Minimum size for hash table */
- XX{
- XX /* Create a hash table of size rounded up to next power of two-1 */
- XX
- XX register unsigned tsize = size;
- XX
- XX hsize = 1; /* Actual hash table size */
- XX while (tsize)
- XX {
- XX tsize >>= 1;
- XX hsize <<= 1;
- XX }
- XX hsize--;
- XX if (hsize == 0) hsize++; /* Silly, but it will work! */
- XX
- XX htable = (Symbol **) emalloc (hsize * sizeof(Symbol *));
- XX memset ((char *) htable, 0, (int) (hsize * sizeof(Symbol *)));
- XX
- XX#ifdef DEBUG
- XX Printf ("mkhash table size %d\n", hsize);
- XX hcount = (unsigned *) emalloc (hsize * sizeof(unsigned));
- XX memset ((char *) hcount, 0, (int) (hsize * sizeof(unsigned)));
- XX#endif
- XX}
- XX
- XX
- XXvoid rmhash ()
- XX{
- XX /* Destroy hash table and all chained entries */
- XX
- XX register Symbol **pp, *p;
- XX extern void free();
- XX
- XX for (pp = htable; pp < htable + hsize; pp++)
- XX {
- XX while (p = *pp)
- XX {
- XX *pp = p->next;
- XX free (p->name);
- XX free ((char *)p);
- XX }
- XX }
- XX
- XX free((char *) htable);
- XX htable = 0;
- XX}
- XX
- XX
- XXSymbol *findsym (name, token, action)
- XXchar *name; /* name to be inserted or found */
- XXToken token; /* type of symbol */
- XXAction action; /* Create or Find */
- XX{
- XX /* Search for, and create if required, an entry in the hash table */
- XX
- XX register Symbol **pp; /* address of pointer to entry */
- XX register Symbol *p; /* search through linked list */
- XX register unsigned hval; /* hash value from name */
- XX register int res; /* result of strcmp */
- XX
- XX pp = &htable[hval = hash(name)];
- XX p = *pp;
- XX
- XX while (p != NULL)
- XX {
- XX if ((res = strcmp(name, p->name)) == 0)
- XX {
- XX return p;
- XX }
- XX elif (res < 0)
- XX {
- XX /* past point where name would be in sorted chain */
- XX break;
- XX }
- XX pp = &(p->next);
- XX p = *pp;
- XX }
- XX
- XX /* Item is not yet on list */
- XX if (action == Find)
- XX return NilSym;
- XX else
- XX {
- XX#ifdef DEBUG
- XX /* Accumulate hashing statistics */
- XX hcount[hval]++;
- XX#endif
- XX p = (Symbol *) emalloc (sizeof(Symbol));
- XX p->name = strcpy (emalloc ((unsigned) strlen(name)+1), name);
- XX p->token = token;
- XX p->next = *pp;
- XX *pp = p;
- XX return p;
- XX }
- XX}
- XX
- XX
- XXstatic struct Keyword {
- XX char *name;
- XX Token token;
- XX} keywords [] = {
- XX "auto", AUTO,
- XX "break", BREAK,
- XX "case", CASE,
- XX "char", CHAR,
- XX "continue", CONTINUE,
- XX "default", DEFAULT,
- XX "do", DO,
- XX "double", DOUBLE,
- XX "else", ELSE,
- XX "enum", ENUM,
- XX "extern", EXTERN,
- XX "float", FLOAT,
- XX "for", FOR,
- XX "goto", GOTO,
- XX "if", IF,
- XX "int", INT,
- XX "long", LONG,
- XX "register", REGISTER,
- XX "return", RETURN,
- XX "short", SHORT,
- XX "sizeof", SIZEOF,
- XX "static", STATIC,
- XX "struct", STRUCT,
- XX "switch", SWITCH,
- XX "typedef", TYPEDEF,
- XX "union", UNION,
- XX "unsigned", UNSIGNED,
- XX "void", VOID,
- XX "while", WHILE,
- XX 0, 0
- XX};
- XX
- XX
- XXvoid sy_init ()
- XX{
- XX /* Initialise the Symbol Table with the reserved words */
- XX
- XX register struct Keyword *kw;
- XX
- XX mkhash (HASH_SIZE);
- XX for (kw = keywords; kw->name; kw++)
- XX {
- XX (void) findsym (kw->name, kw->token, Create);
- XX }
- XX}
- XX
- XX
- XXvoid sy_tidy ()
- XX{
- XX /* Remove all but reserved words from the Symbol Table */
- XX /* This is achieved by brute force; destroy & recreate! */
- XX
- XX#ifdef DEBUG
- XX /* print hash statistics */
- XX register unsigned i, j, tot = 0, maxc = 0, unused = 0;
- XX for (i=0; i<hsize; i++)
- XX {
- XX /* print hash count if non-zero */
- XX if (j = hcount[i])
- XX {
- XX Printf ("hash %6d : %d\n", i, j);
- XX if (j > maxc) maxc = j;
- XX tot += j;
- XX }
- XX else unused++;
- XX }
- XX Printf ("Total=%d, max chain length=%d, unused=%d\n",tot,maxc,unused);
- XX#endif
- XX rmhash ();
- XX sy_init ();
- XX}
- ====End of SHAR symbol.c====
- if [ "`wc -c <'symbol.c'`" != ' 4271' ]
- then echo 'Unpack for symbol.c failed!'
- exit 1
- else echo 'Unpacked symbol.c'
- fi
- sed -e 's/^XX//' <<'====End of SHAR tables.sh====' >tables.sh
- XX
- XX# Make tables.h from check.h and y.xxx.h
- XX
- XX(
- XXsed <check.h -n -e '/ Parse/,$ s/^#define[ ][ ]*//p'
- XXsed <y.xxx.h -n -e 's/^#[ ]*define[ ][ ]*//p'
- XX) |
- XXawk -e '
- XXBEGIN {
- XX printf "typedef struct NodeName {\n"
- XX printf "\tint val;\n"
- XX printf "\tchar *str;\n"
- XX printf "} NodeName;\n\n"
- XX printf "NodeName\tnodenames[] = {\n"
- XX }
- XX {
- XX printf "\t%d, \"%s\",\n", $2, $1
- XX }
- XXEND {
- XX printf " 0, 0\n};\n"
- XX }' >tables.h
- ====End of SHAR tables.sh====
- chmod +x tables.sh
- if [ "`wc -c <'tables.sh'`" != ' 412' ]
- then echo 'Unpack for tables.sh failed!'
- exit 1
- else echo 'Unpacked tables.sh'
- fi
- sed -e 's/^XX//' <<'====End of SHAR test.c====' >test.c
- XX/*----------------------------------------------------------------------*/
- XX/* */
- XX/* C Checker Main Entry Point */
- XX/* Modified version of 'main.c' to see messages from check. */
- XX/* */
- XX/*----------------------------------------------------------------------*/
- XX
- XX
- XX#include <stdio.h>
- XX#include <ctype.h>
- XX#include "check.h"
- XX#include "y.tab.h"
- XX
- XX#define MAXNAME 120
- XX#define CPP "/lib/cpp -C %s %s"
- XX
- XXextern void perror(), exit();
- XX
- XXint errors = 0; /* count of number of errors */
- XXchar filebuf [MAXNAME]; /* Buffer for file names
- XXchar *filename; /* Pointer to file name */
- XXchar *progname; /* Name of this program */
- XX
- XX/* Really should recode this to avoid using fixed buffer sizes; */
- XX/* malloc and realloc are not difficult to use! */
- XXchar options [BUFSIZ]; /* Buffer for cpp options */
- XX
- XX
- XXint main (argc, argv)
- XXint argc;
- XXchar *argv[];
- XX{
- XX /* Main Entry Point to C Checker */
- XX /* Check each file as specified by arguments */
- XX
- XX char command [BUFSIZ]; /* for cpp command */
- XX register char *opts = options;
- XX register char *opt_end = & options [BUFSIZ-2];
- XX register int pnames;
- XX register int ptree = FALSE;
- XX extern char *strncat ();
- XX extern FILE *popen ();
- XX
- XX sy_init ();
- XX progname = *argv++;
- XX
- XX /* Extract C PreProcessor options */
- XX
- XX while (--argc && **argv == '-')
- XX {
- XX register char *ap = *argv++;
- XX
- XX if (strcmp ("--", ap) == 0)
- XX {
- XX /* End of Options */
- XX
- XX break;
- XX }
- XX#if YYDEBUG
- XX elif (strcmp ("-yydebug", ap) == 0)
- XX {
- XX /* Turn on Yacc Tracing */
- XX
- XX extern int yydebug;
- XX yydebug = 1;
- XX }
- XX#endif
- XX elif (strcmp ("-TP", ap) == 0)
- XX {
- XX /* Print Parse Tree option (debug) */
- XX
- XX ptree = TRUE;
- XX }
- XX else
- XX {
- XX /* C PreProcessor option */
- XX
- XX while (*ap && (opts < opt_end)) *opts++ = *ap++;
- XX *opts++ = ' ';
- XX }
- XX }
- XX *opts++ = ' ';
- XX *opts++ = '\0';
- XX
- XX pnames = argc - 1;
- XX while (argc--)
- XX {
- XX /* Open a pipe for reading from C PreProcessor */
- XX
- XX filename = *argv++;
- XX (void) sprintf (command, CPP, options, filename);
- XX if (pnames > 0 && filename != NULL && othertests());
- XX Printf ("%s:\n", filename);
- XX
- XX if ((yyin = popen (command, "r")) == NULL)
- XX if (yyin == NULL) perror ("cannot open pipe");
- XX else
- XX {
- XX /* Analyse one C source file */
- XX
- XX lex_init ();
- XX met_init ();
- XX if (yyparse ()) warn ("fatal syntax error");
- XX
- XX /* Report on results of analysis */
- XX
- XX if (ptree) treeprint ();
- XX check_prog ();
- XX metrics ((char *) 0);
- XX
- XX /* Tidy up, ready for another source file */
- XX
- XX (void) pclose (yyin);
- XX tidy_prog ();
- XX sy_tidy ();
- XX }
- XX }
- XX
- XX return errors;
- XX}
- XX
- XX
- XXchar *emalloc (n)
- XXunsigned n;
- XX{
- XX /*==== Allocate Memory ====*/
- XX
- XX char *p, *malloc ();
- XX
- XX p = malloc (n);
- XX
- XX if (p = 0) error ("out of memory");
- XX
- XX return p;
- XX}
- XX
- XX
- XXvoid yyerror (s)
- XXchar *s;
- XX{
- XX /* Syntax Error from Yacc */
- XX
- XX errors++;
- XX Fprintf (stderr, "%s: %s at or near line %d, token %d\n",
- XX filename, s, yylineno, yychar);
- XX}
- XX
- XX
- XXvoid warn (s)
- XXchar *s;
- XX{
- XX /* Generate a warning message */
- XX
- XX errors++;
- XX Fprintf (stderr, "%s: %s at or near line %d\n",
- XX filename, s, yylineno);
- XX}
- XX
- XX
- XXvoid error (s)
- XXchar *s;
- XX{
- XX /* Handle fatal errors */
- XX
- XX warn (s);
- XX exit (errors);
- XX}
- XX
- XX
- XXvoid setline (line)
- XXchar *line;
- XX{
- XX /* Handle a #line directive */
- XX
- XX register char *cp = line;
- XX register char *fn = filebuf;
- XX register int lnum = 0;
- XX
- XX if (*cp != '#') error ("invalid call to setline");
- XX
- XX while (*cp && !isdigit(*cp)) cp++;
- XX while (*cp && isdigit (*cp)) lnum = lnum*10 + (*cp++ - '0');
- XX while (*cp && *cp != '"') cp++;
- XX if (lnum) yylineno = lnum;
- XX
- XX if (*cp++ == 0) return;
- XX while (*cp && *cp != '"') *fn++ = *cp++;
- XX if (fn == filename) return;
- XX
- XX *fn = '\0';
- XX filename = filebuf;
- XX}
- XX
- XX/* Unterminated comment here ...
- XX
- XXvoid uncompiled (not_passed)
- XX{
- XX int not_here;
- XX
- XX not_called ();
- XX}
- ====End of SHAR test.c====
- if [ "`wc -c <'test.c'`" != ' 3731' ]
- then echo 'Unpack for test.c failed!'
- exit 1
- else echo 'Unpacked test.c'
- fi
- sed -e 's/^XX//' <<'====End of SHAR tree.c====' >tree.c
- XX/*----------------------------------------------------------------------*/
- XX/* */
- XX/* This module handles Parse Tree building and walking */
- XX/* */
- XX/*----------------------------------------------------------------------*/
- XX
- XX
- XX#include <stdio.h>
- XX#include <ctype.h>
- XX#include "check.h"
- XX#include "y.tab.h"
- XX#include "tables.h"
- XX
- XX#define CHUNK 1024 /* No. of nodes allocated */
- XX
- XXNodePtr Tree; /* holds the base of the Parse Tree, */
- XX /* built by the Yacc-generated Parser. */
- XX
- XXNodePtr next_node, /* the next free node for allocation */
- XX last_node, /* node not available for allocation */
- XX node_list; /* head of list of blocks of nodes */
- XX
- XX
- XXNodePtr new_node (nt, p1, p2, p3, p4)
- XXint nt;
- XXNodePtr p1, p2, p3, p4;
- XX{
- XX /* Build a node for the Parse Tree */
- XX
- XX register NodePtr np;
- XX
- XX if (next_node == last_node)
- XX {
- XX /* Allocate a new batch of nodes */
- XX
- XX next_node = (NodePtr) emalloc (sizeof (Node) * CHUNK);
- XX last_node = next_node + CHUNK;
- XX
- XX next_node -> f1.ptr = node_list;
- XX node_list = next_node++;
- XX }
- XX
- XX np = next_node++;
- XX
- XX np -> type = nt;
- XX np -> line = yylineno;
- XX np -> f1.ptr = p1;
- XX np -> f2.ptr = p2;
- XX np -> f3.ptr = p3;
- XX np -> f4.ptr = p4;
- XX
- XX return np;
- XX}
- XX
- XX
- XXvoid tidy_prog ()
- XX{
- XX /* Delete the parse tree and release its memory space; */
- XX /* Leave just the first block of nodes for the next program */
- XX /* No attempt is made to return the freed space to the system */
- XX /* by using (s)brk, but this could be added if desired. */
- XX /* My own view is that if one program builds a huge tree, */
- XX /* others in the same call to check may also, so let's keep */
- XX /* the space. But in that case, why even return it to malloc? */
- XX /* Because it makes it easier to add the (s)brk, and it might */
- XX /* alleviate heap fragmentation if other modules are also */
- XX /* using malloc, and because it just feels neater to me! */
- XX
- XX register NodePtr np;
- XX extern void free();
- XX
- XX Tree = NilNode;
- XX
- XX for (np = node_list->f1.ptr; np; np = np->f1.ptr) free ((char *) np);
- XX node_list -> f1.ptr = NilNode;
- XX next_node = node_list + 1;
- XX last_node = node_list + CHUNK;
- XX}
- XX
- XX
- XXvoid treewalk (depth, parent, branch, np, action)
- XXint depth, parent, branch;
- XXNodePtr np;
- XXvoid (*action) ();
- XX{
- XX /* Perform required action for this node, and all nodes below it */
- XX
- XX register int here;
- XX
- XX if (np == NilNode) return;
- XX yylineno = np -> line;
- XX
- XX action (depth, parent, branch, np);
- XX
- XX switch (here = np -> type)
- XX {
- XX /* = = = Terminal Nodes = = = */
- XX
- XX case IDENTIFIER:
- XX case CONSTANT:
- XX case DEFAULT:
- XX case BREAK:
- XX case CONTINUE:
- XX case ';':
- XX case Type:
- XX case Error:
- XX case 0: break;
- XX
- XX /* = = = Unary Nodes = = = */
- XX
- XX case GOTO:
- XX case RETURN:
- XX case CASE:
- XX case Indirect:
- XX case Addr:
- XX case Uplus:
- XX case Uminus:
- XX case '!':
- XX case '~':
- XX case Pre_Inc:
- XX case Post_Inc:
- XX case Size_Type:
- XX case Size_Expr:
- XX treewalk (depth+1,here,1,np->f1.ptr,action);
- XX break;
- XX
- XX /* = = = Binary Nodes = = = */
- XX
- XX case Seq:
- XX case Label:
- XX case WHILE:
- XX case DO:
- XX case SWITCH:
- XX case ',':
- XX case Or:
- XX case And:
- XX case '|':
- XX case '^':
- XX case '&':
- XX case Eq_Op:
- XX case Rel_Op:
- XX case Shift:
- XX case '+':
- XX case '-':
- XX case '*':
- XX case '/':
- XX case '%':
- XX case Cast:
- XX case Point:
- XX case '.':
- XX case '(':
- XX case '[':
- XX case Asgn_Op:
- XX treewalk (depth+1,here,1,np->f1.ptr,action);
- XX treewalk (depth+1,here,2,np->f2.ptr,action);
- XX break;
- XX
- XX /* = = = Ternary Nodes = = = */
- XX
- XX case IF:
- XX case '?':
- XX treewalk (depth+1,here,1,np->f1.ptr,action);
- XX treewalk (depth+1,here,2,np->f2.ptr,action);
- XX treewalk (depth+1,here,3,np->f3.ptr,action);
- XX break;
- XX
- XX /* = = = Quaternary Nodes = = = */
- XX
- XX case FOR:
- XX treewalk (depth+1,here,1,np->f1.ptr,action);
- XX treewalk (depth+1,here,2,np->f2.ptr,action);
- XX treewalk (depth+1,here,3,np->f3.ptr,action);
- XX treewalk (depth+1,here,4,np->f4.ptr,action);
- XX break;
- XX
- XX
- XX default: Printf ("node type %d encountered\n", here);
- XX error ("treewalk: parse tree corrupt");
- XX }
- XX}
- XX
- XX
- XXvoid walk_prog (action)
- XXvoid (*action) ();
- XX{
- XX /* Start off the Parse Tree walk */
- XX
- XX treewalk (0, 0, 0, Tree, action);
- XX}
- XX
- XX
- XX/*ARGSUSED*/
- XXvoid printnode (depth, parent, branch, np)
- XXint depth, parent, branch;
- XXNodePtr np;
- XX{
- XX /* Print one node of the tree */
- XX
- XX register int type = np->type;
- XX
- XX while (depth--) Printf (" ");
- XX Printf ("(%d) line %d: ", branch, np->line);
- XX
- XX if (type > 256)
- XX {
- XX register NodeName *q = nodenames;
- XX
- XX while (q->val != 0 && q->val != type) q++;
- XX Printf ("%s\n", q->str);
- XX }
- XX elif (type == 256)
- XX Printf ("ERROR/EOF\n");
- XX elif (isprint(type))
- XX Printf ("%c\n", type);
- XX else Printf ("type %d/0x%02x\n", type, type);
- XX}
- XX
- XX
- XXvoid treeprint ()
- XX{
- XX /* Print the Parse Tree */
- XX
- XX treewalk (0, 0, 0, Tree, printnode);
- XX}
- ====End of SHAR tree.c====
- if [ "`wc -c <'tree.c'`" != ' 4678' ]
- then echo 'Unpack for tree.c failed!'
- exit 1
- else echo 'Unpacked tree.c'
- fi
-
-