home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume13
/
check
< prev
next >
Wrap
Text File
|
1988-01-31
|
49KB
|
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