home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume13 / check < prev    next >
Text File  |  1988-01-31  |  49KB  |  1,927 lines

  1. Subject:  v13i061:  Check for mistakes in C programs
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Nick Crossley <ccicpg!nick@uunet.uu.net>
  7. Posting-number: Volume 13, Issue 61
  8. Archive-name: check
  9.  
  10.  
  11. This program has been posted as a result of a discussion in comp.lang.c
  12. concerning some possible errors in writing C programs.  It is a C syntax
  13. checker, to be used as an adjunct to lint, not a replacement.  It makes
  14. no attempt to duplicate any warning given by the standard lint, and is not
  15. at all forgiving about simple syntax errors.
  16.  
  17. Warnings include things like "if (a = b);" nested comments, and dangling
  18. else's.
  19.  
  20. See the README file for more details.  If anyone implements the software
  21. metrics or upgrades the grammar significantly, please send the results
  22. back to me!
  23.  
  24.     Nick Crossley
  25.     CCI
  26.     email:  ..!uunet!ccicpg!nick
  27.  
  28. #! /bin/sh
  29. # This is a Shell Archive, containing the files/directories :-
  30. #    Makefile README check.1 check.c check.h lex.l main.c metric.c parse.awk
  31. #    parse.y symbol.c tables.sh test.c tree.c
  32.  
  33. # To unpack it, execute it with /bin/sh
  34. # If run with standard input from a terminal, you will be prompted
  35. # for the name of a directory to hold the unpacked files.
  36. # Otherwise, it will unpack into the current directory.
  37.  
  38. if    [ -t 0 ]
  39. then
  40.     while    :
  41.     do
  42.         echo 'Directory for output : \c'
  43.         read outdir
  44.  
  45.         if    [ X$outdir = X ]
  46.         then    outdir=.
  47.             break
  48.         elif    [ -d ${outdir} ]
  49.         then    break
  50.         elif    echo "$outdir does not exist; create it? \c"
  51.             read reply
  52.             [ `expr "$reply" : '[Yy].*'` = 0 ]
  53.         then    continue
  54.         elif    mkdir $outdir
  55.         then    break
  56.         else    echo "Cannot create $outdir" 1>&2
  57.             continue
  58.         fi
  59.     done
  60.     cd $outdir
  61. fi
  62.  
  63. sed -e 's/^XX//' <<'====End of SHAR Makefile====' >Makefile
  64. XX#    Makefile for C checker
  65. XX#    Has been used on SysV and BSD/SysV mixtures
  66. XX#    I don't guarantee it will work on real BSD
  67. XX#    Set the following macros :-
  68. XX#        CHECK    if you want to change the program name
  69. XX#        LIB    for the installation directory
  70. XX#        CFLAGS    for cc flags
  71. XX#        LDFLAGS for final cc flags
  72. XX#        BLIBS    for any other libraries to scan
  73. XX#        LFLAGS    for lex flags
  74. XX#        YFLAGS    for yacc flags
  75. XX#        LINTF    for lint flags
  76. XX
  77. XXCHECK    = check
  78. XXLIB    = bin
  79. XXCFLAGS    = -O
  80. XXLDFLAGS    =
  81. XXBLIBS    =
  82. XXLFLAGS    =
  83. XXYFLAGS    = -vd
  84. XXLINTF    =
  85. XX
  86. XXOBJ    = main.o  lex.o  parse.o  symbol.o  tree.o  check.o  metric.o
  87. XXSRC    = main.c  lex.l  parse.y  symbol.c  tree.c  check.c  metric.c
  88. XX
  89. XXbuild    :    $(CHECK)
  90. XX
  91. XXinstall    :    $(CHECK)
  92. XX        cp $(CHECK) $(LIB)
  93. XX        -touch install
  94. XX
  95. XX$(CHECK):    $(OBJ)
  96. XX        $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ) $(BLIBS) -lm
  97. XX
  98. XX$(OBJ)    :    y.xxx.h check.h
  99. XX
  100. XXtree.o    :    tables.h
  101. XX
  102. XXtables.h:    y.xxx.h tables.sh
  103. XX        tables.sh
  104. XX
  105. XXy.xxx.h    :    y.tab.h
  106. XX        -cmp -s y.xxx.h y.tab.h || cp y.tab.h y.xxx.h
  107. XX
  108. XXy.tab.h    :    parse.c
  109. XX
  110. XX.y.c    :;    $(YACC) $(YFLAGS) $<
  111. XX        mv y.tab.c $*.c
  112. XX        parse.awk &
  113. XX
  114. XX.y.o    :;    $(YACC) $(YFLAGS) $<
  115. XX        mv y.tab.c $*.c
  116. XX        parse.awk &
  117. XX        $(CC) $(CFLAGS) -c $*.c
  118. XX
  119. XX.l.o    :;    $(LEX) $(LFLAGS) $<
  120. XX        mv lex.yy.c $*.c
  121. XX        $(CC) $(CFLAGS) -c $*.c
  122. XX
  123. XX.c.o    :;    $(CC) $(CFLAGS) -c $*.c
  124. XX
  125. XXlist    :    $(SRC) Makefile
  126. XX        pr -n -f -h "C Checker" $? | lp
  127. XX        -touch list
  128. XX
  129. XXlint    :    $(OBJ:.o=.c) tables.h
  130. XX        lint $(LINTF) $(OBJ:.o=.c)
  131. XX
  132. XXclean    :;    rm -f *.o y.* yacc* parse.c lex.c tables.h
  133. XX
  134. XXclobber    :    clean
  135. XX        rm -f $(CHECK) list install
  136. ====End of SHAR Makefile====
  137. if    [ "`wc -c <'Makefile'`" != '    1426' ]
  138. then    echo 'Unpack for Makefile failed!'
  139.     exit 1
  140. else    echo 'Unpacked Makefile'
  141. fi
  142. sed -e 's/^XX//' <<'====End of SHAR README====' >README
  143. XX            C Program Checker
  144. XX            -----------------
  145. XX
  146. XXThis program has been posted as a result of a discussion in comp.lang.c
  147. XXconcerning some possible errors in writing C programs.  It is a C syntax
  148. XXchecker, to be used as an adjunct to lint, not a replacement.  It makes
  149. XXno attempt to duplicate any warning given by the standard lint, and is not
  150. XXat all forgiving about simple syntax errors.  It warns about the following
  151. XXpossible errors :-
  152. XX
  153. XX1.    Assignment in conditional context
  154. XX    A warning is issued for any assignment in any conditional context,
  155. XX    where the programmer might have mistyped = when == was intended.
  156. XX    Thus, 'if (a=b)' will give a warning, while 'if ((a=b)!=0)' will not.
  157. XX    (NOTE:  I am not saying that people should not write 'if (a=b)' and
  158. XX    similar constructs - I frequently do - but that on SOME occasions
  159. XX    programmers make typing errors which are not picked up by lint or cc,
  160. XX    and are not easily visually seen as errors.)
  161. XX
  162. XX2.    if with neither then nor else
  163. XX    One of my colleagues once wrote
  164. XX        if    (a == b);
  165. XX        {
  166. XX            lots of useful code ...
  167. XX        }
  168. XX    and we spent a whole day tracking down why this was not doing as
  169. XX    we expected before I noticed the extra semicolon.  (The condition
  170. XX    was actually more complicated, so the semicolon was not as obvious,
  171. XX    and we spent our time working out why the condition did not appear
  172. XX    to have the right value.  We were also working on a machine which
  173. XX    did not supply adb, only sdb, and that did not work!)
  174. XX
  175. XX3.    I come from an Algol68 background, and I HATE the 'dangling-else'
  176. XX    language ambiguity in C, Pascal, ...!  So, not that I have ever
  177. XX    seen it as a problem in practice, the program warns about potentially
  178. XX    ambiguous elses :-
  179. XX
  180. XX        if    (a == b)
  181. XX            if    (c == d)
  182. XX                action1 ();
  183. XX            else    action2 ();
  184. XX    will generate a warning, while :-
  185. XX
  186. XX        if    (a == b)
  187. XX        {
  188. XX            if    (c == d)
  189. XX                action1 ();
  190. XX            else    action2 ();
  191. XX        }
  192. XX    will not.
  193. XX
  194. XX4.    Nested comment
  195. XX    I just added this as a result of further net discussion of errors;
  196. XX    this will give a warning if '/*' is seen inside a comment, so that
  197. XX    errors such as that below are noticed.
  198. XX    a = 1;    /* initialise a
  199. XX    b = 2;  /* initialise b  */
  200. XX    The current line number and that where the outer comment started are
  201. XX    included in the warning message.
  202. XX
  203. XX5.    Unterminated comment
  204. XX    If end-of-file is reached while in a comment.  This is also noticed
  205. XX    by both cpp and cc, but check gives the line number where the comment
  206. XX    started, not just the line number where the error was detected, i.e.,
  207. XX    the last line!
  208. XX
  209. XX
  210. XXThe program uses yacc and lex.  The grammar was written by me, and is not a
  211. XXcomplete C grammar - some obsolete or weird constructs are (deliberately) not
  212. XXsupported.  ('Weird' as defined by me!!)  No attempt has been made (yet) to
  213. XXsupport ANSI C.  It is not very fast - profiling shows that most of the time
  214. XXis spent in the lex-generated analyser, as one might expect.
  215. XX
  216. XXThere is some code, mostly commented out, to calculate and print software
  217. XXmetrics, but this needs changes to the lexing, parsing and symbol handling
  218. XXwhich I have not yet done.  If anyone completes this work, or has any improved
  219. XXmetrics to suggest, please send it back to me!
  220. XX
  221. XXAs an example, the output of 'check *.c' in the check source directory is :-
  222. XXlex.c: assignment in conditional context at or near line 163
  223. XXlex.c: assignment in conditional context at or near line 588
  224. XXlex.c: assignment in conditional context at or near line 616
  225. XXsymbol.c: assignment in conditional context at or near line 79
  226. XXtest.c: nested comment, starting at line 20, at or near line 21
  227. XXtest.c: unterminated comment, starting at line 194, at or near line 202
  228. XXtest.c: IF with neither THEN nor ELSE at or near line 93
  229. XXtest.c: potentially mismatched ELSE - use {} at or near line 117
  230. XXtest.c: assignment in conditional context at or near line 132
  231. XX
  232. XXThis program is in no way derived from lint sources, which I have not even
  233. XXlooked at, and is free of all copyright restrictions.
  234. XX
  235. XXWed Jan 20 1988
  236. XX
  237. XXNick Crossley
  238. XXComputer Consoles Inc.
  239. XX9801 Muirlands Boulevard,
  240. XXIrvine
  241. XXCA 92718
  242. XX(714) 458-7282
  243. XXemail: ...!uunet!ccicpg!nick
  244. ====End of SHAR README====
  245. if    [ "`wc -c <'README'`" != '    4011' ]
  246. then    echo 'Unpack for README failed!'
  247.     exit 1
  248. else    echo 'Unpacked README'
  249. fi
  250. sed -e 's/^XX//' <<'====End of SHAR check.1====' >check.1
  251. XX.TH CHECK 1 
  252. XX.SH NAME
  253. XXcheck \- a C program checker
  254. XX.SH SYNOPSIS
  255. XX.B check
  256. XX[ option ] ... file ...
  257. XX.SH DESCRIPTION
  258. XX.I Check\^
  259. XXattempts to find possible errors in C programs.
  260. XXIt does not duplicate or replace
  261. XX.I lint
  262. XXbut finds some constructs about which
  263. XX.I lint
  264. XXis silent.
  265. XXAmong the things that are detected are
  266. XXnested comments,
  267. XXunterminated comments,
  268. XXassignments in conditional contexts,
  269. XXif statements with null then and no else
  270. XXand
  271. XXpotentially ambiguous else statements
  272. XX.PP
  273. XXFor each such construct a warning is given,
  274. XXidentifying the source file and line number where it occurs.
  275. XXIf multiple files are being checked,
  276. XXthe name of each file is printed as checking starts.
  277. XX.PP
  278. XXAll leading '-' options are assumed to be C preprocessor directives,
  279. XXexcept that an argument '--' ends the options and is otherwise ignored.
  280. XXAll following arguments are assumed to be C source file names.
  281. XX.SH SEE ALSO
  282. XXcpp(1), lint(1).
  283. XX.SH BUGS
  284. XX.I Check\^
  285. XXis not at all forgiving of simple syntax errors,
  286. XXsuch as missing or extra punctuation.
  287. XX.PP
  288. XXThe grammar (deliberately) does not accept all currently legal C programs;
  289. XXsome obsolescent or weird constructs are not allowed.
  290. XXNo attempt has yet been made to handle ANSI C.
  291. ====End of SHAR check.1====
  292. if    [ "`wc -c <'check.1'`" != '    1193' ]
  293. then    echo 'Unpack for check.1 failed!'
  294.     exit 1
  295. else    echo 'Unpacked check.1'
  296. fi
  297. sed -e 's/^XX//' <<'====End of SHAR check.c====' >check.c
  298. XX/*----------------------------------------------------------------------*/
  299. XX/*                                    */
  300. XX/*    This module contains the actual checking logic            */
  301. XX/*                                    */
  302. XX/*----------------------------------------------------------------------*/
  303. XX
  304. XX
  305. XX#include    <stdio.h>
  306. XX#include    "check.h"
  307. XX#include    "y.tab.h"
  308. XX
  309. XX
  310. XX/*ARGSUSED*/
  311. XXvoid checknode (depth, parent, branch, np)
  312. XXint    depth, parent, branch;
  313. XXNodePtr    np;
  314. XX{
  315. XX    /*  This routine is called as an 'action' by treewalk.    */
  316. XX    /*  It checks for the following things :-        */
  317. XX    /*    1) assignment in conditional contexts;        */
  318. XX    /*    2) potentially mismatched ELSE clauses;        */
  319. XX    /*    3) IFs with no THEN or ELSE.            */
  320. XX
  321. XX
  322. XX    if  (np->type == Asgn_Op)
  323. XX    {
  324. XX        if    ((parent == IF && branch == 1) ||
  325. XX            (parent == WHILE && branch == 1) ||
  326. XX            (parent == DO && branch == 2) ||
  327. XX            (parent == FOR && branch == 2) ||
  328. XX            parent == And || parent == Or)
  329. XX
  330. XX            warn ("assignment in conditional context");
  331. XX    }
  332. XX
  333. XX    if    (np->type == IF && np->f3.ptr == NilNode)  /* IF with no ELSE */
  334. XX    {
  335. XX        if    (np->f2.ptr == NilNode ||
  336. XX             np->f2.ptr->type == 0 || np->f2.ptr->type == ';')
  337. XX            warn ("IF with neither THEN nor ELSE");
  338. XX
  339. XX        if    (np->f2.ptr->type==IF && np->f2.ptr->f3.ptr!=NilNode)
  340. XX            warn ("potentially mismatched ELSE - use {}");
  341. XX    }
  342. XX}
  343. XX
  344. XX
  345. XXvoid check_prog ()
  346. XX{
  347. XX    /*  Start off the checking process  */
  348. XX
  349. XX    walk_prog (checknode);
  350. XX}
  351. ====End of SHAR check.c====
  352. if    [ "`wc -c <'check.c'`" != '    1304' ]
  353. then    echo 'Unpack for check.c failed!'
  354.     exit 1
  355. else    echo 'Unpacked check.c'
  356. fi
  357. sed -e 's/^XX//' <<'====End of SHAR check.h====' >check.h
  358. XX/*===========    Header file for C Checker Program    ================*/
  359. XX
  360. XX#define        elif        else if
  361. XX#define        TRUE        1
  362. XX#define        FALSE        0
  363. XX#define        Printf        (void) printf
  364. XX#define        Fprintf        (void) fprintf
  365. XX#define        NilNode        ((NodePtr) 0)
  366. XX#define        NilSym        ((Symbol *) 0)
  367. XX
  368. XX
  369. XX/*===========    Type Definitions            ================*/
  370. XX
  371. XXtypedef int    Token;            /*  type of Lex tokens        */
  372. XX
  373. XXtypedef    enum    {
  374. XX    Find,        /* Find only */
  375. XX    Create        /* Find and create if required */
  376. XX}    Action;
  377. XX
  378. XXtypedef struct    Symbol {        /*  type of Symbol Table Entry    */
  379. XX        char        *name;
  380. XX        Token        token;
  381. XX        struct Symbol    *next;
  382. XX}    Symbol;
  383. XX
  384. XXtypedef    struct    Node {            /*  type of Parse Tree Node    */
  385. XX    short    type;            /*  variant for a node        */
  386. XX    short    line;            /*  source line number        */
  387. XX    union    u {
  388. XX        int        ival;    /*  integer value        */
  389. XX        unsigned    uval;    /*  unsigned value        */
  390. XX        struct Node    *ptr;    /*  pointer to another node    */
  391. XX    }    f1, f2, f3, f4;        /*  variable number of fields    */
  392. XX}    Node, *NodePtr;            /*  Node and pointer to Node    */
  393. XX
  394. XX
  395. XX/*===========    Parse Tree Node Types            ================*/
  396. XX
  397. XX#define        Seq        1000    /*  a sequence of two nodes    */
  398. XX#define        Type        1001    /*  a type specifier        */
  399. XX#define        Label        1002    /*  a labelled statement    */
  400. XX#define        Pre_Inc        1003    /*  ++ (expression)        */
  401. XX#define        Pre_Dec        1004    /*  -- (expression)        */
  402. XX#define        Post_Inc    1005    /*  (expression) ++        */
  403. XX#define        Post_Dec    1006    /*  (expression) --        */
  404. XX#define        Indirect    1007    /*  a -> b            */
  405. XX#define        Addr        1008    /*  & id            */
  406. XX#define        Uplus        1009    /*  + expression        */
  407. XX#define        Uminus        1010    /*  - expression        */
  408. XX#define        Cast        1011    /*  (type) expression        */
  409. XX#define        Size_Type    1012    /*  SIZEOF (type)        */
  410. XX#define        Size_Expr    1013    /*  SIZEOF (expression)        */
  411. XX#define        Error        9999    /*  error            */
  412. XX
  413. XX
  414. XX/*===========    External Function Definitions        ================*/
  415. XX
  416. XXextern    void    lex_init ();        /*  Lexical Analyser initialise    */
  417. XXextern    Token    yylex ();        /*  Lexical Analyser interface    */
  418. XX
  419. XXextern    void    sy_init ();        /*  Initialise symbol table    */
  420. XXextern    void    sy_tidy ();        /*  Tidy symbol table        */
  421. XXextern    Symbol    *findsym ();        /*  look up identifier in table    */
  422. XXextern    char    *emalloc ();        /*  allocate space        */
  423. XX
  424. XXextern    int    yyparse ();        /*  interface to Yacc Parser    */
  425. XX
  426. XXextern    NodePtr    new_node ();        /*  build a parse tree node    */
  427. XXextern    void    check_prog ();        /*  check the parse tree    */
  428. XXextern    void    tidy_prog ();        /*  delete the parse tree    */
  429. XXextern    void    walk_prog ();        /*  walk the parse tree        */
  430. XXextern    void    treeprint ();        /*  print the parse tree    */
  431. XX
  432. XXextern    void    metrics ();        /*  produce software metrics    */
  433. XXextern    void    met_init ();        /*  initialise metrics        */
  434. XXextern    void    proc_start ();        /*  initialise local metrics    */
  435. XX
  436. XXextern    void    yyerror ();        /*  Yacc syntax error report    */
  437. XXextern    void    warn ();        /*  generate warning messages    */
  438. XXextern    void    error ();        /*  stop with error message    */
  439. XXextern    void    setline ();        /*  set line and filename    */
  440. XX
  441. XX
  442. XX/*===========    External Data Definitions        ================*/
  443. XX
  444. XXextern    int    yychar;            /*  current lookahead token    */
  445. XXextern    char    *filename;        /*  current filename        */
  446. XXextern    int    yylineno;        /*  current line number        */
  447. XXextern    FILE    *yyin;            /*  current input file        */
  448. XXextern    NodePtr    Tree;            /*  Root of Parse Tree        */
  449. ====End of SHAR check.h====
  450. if    [ "`wc -c <'check.h'`" != '    3136' ]
  451. then    echo 'Unpack for check.h failed!'
  452.     exit 1
  453. else    echo 'Unpacked check.h'
  454. fi
  455. sed -e 's/^XX//' <<'====End of SHAR lex.l====' >lex.l
  456. XX%{
  457. XX/*----------------------------------------------------------------------*/
  458. XX/*                                    */
  459. XX/*        LEX generated C lexical analyser            */
  460. XX/*                                    */
  461. XX/*----------------------------------------------------------------------*/
  462. XX
  463. XX#include    "check.h"
  464. XX#include    "y.tab.h"
  465. XX
  466. XX#define        yywrap()    (1)
  467. XX
  468. XXextern    Token    ident ();
  469. XXextern    void    strings (), comment ();    /*  forward declarations  */
  470. XX%}
  471. XX
  472. XXD            [0-9]
  473. XXNUM            ({D}+|({D}+"."{D}*)|("."{D}+))([eE][-+]?{D}+)?[lL]?
  474. XXHEX            0[xX][0-9a-fA-F]+[lL]?
  475. XXID            [A-Za-z_][A-Za-z0-9_]*
  476. XXASG            ([-+*/%&^|]?"=")|"<<="|">>="
  477. XX
  478. XX%%
  479. XX
  480. XX^"#".*"\n"        { setline (yytext); }
  481. XX{ID}            { return ident(); }
  482. XX{NUM}            { return CONSTANT; }
  483. XX{HEX}            { return CONSTANT; }
  484. XX{ASG}            { return Asgn_Op; }
  485. XX"\""            { strings ('"');  return CONSTANT; }
  486. XX"'"            { strings ('\'');  return CONSTANT; }
  487. XX"<<"            { return Shift; }
  488. XX">>"            { return Shift; }
  489. XX"&&"            { return And; }
  490. XX"||"            { return Or; }
  491. XX"->"            { return Point; }
  492. XX"<"|"<="|">="|">"    { return Rel_Op; }
  493. XX"=="|"!="        { return Eq_Op; }
  494. XX"++"|"--"        { return IncDec; }
  495. XX[ \t\n]+        ;
  496. XX"/*"            { comment (); }
  497. XX.            { return yytext[0]; }
  498. XX
  499. XX%%
  500. XX
  501. XXToken ident ()
  502. XX{
  503. XX    /*  Handle an Identifier or Reserved Word  */
  504. XX
  505. XX    yylval.id = findsym (yytext, IDENTIFIER, Create);
  506. XX    return yylval.id->token;
  507. XX}
  508. XX
  509. XX
  510. XXvoid cwarn (ln, s)
  511. XXint    ln;
  512. XXchar    *s;
  513. XX{
  514. XX    /*  Give a warning about a comment, including starting line number  */
  515. XX
  516. XX
  517. XX    char    msg [120];
  518. XX    (void) sprintf (msg, "%s, starting at line %d,", s, ln);
  519. XX    warn (msg);
  520. XX    free (msg);
  521. XX}
  522. XX
  523. XX
  524. XXvoid comment ()
  525. XX{
  526. XX    /*  Swallow the rest of a comment  */
  527. XX
  528. XX    register int    c = input ();
  529. XX    register int    startline = yylineno;
  530. XX
  531. XX    while    (c)
  532. XX    {
  533. XX        if    (c == '*')
  534. XX        {
  535. XX            if  ((c = input()) == '/')  return;
  536. XX        }
  537. XX        elif    (c == '/')
  538. XX        {
  539. XX            if  ((c = input()) != '*')  continue;
  540. XX            cwarn (startline, "nested comment");
  541. XX        }
  542. XX        else    c = input();
  543. XX    }
  544. XX    cwarn (startline, "unterminated comment");
  545. XX}
  546. XX
  547. XX
  548. XXvoid strings (term)
  549. XXint    term;
  550. XX{
  551. XX    /*  A string terminating with 'term'  */
  552. XX
  553. XX    register int c;
  554. XX
  555. XX    while    (c = input ())
  556. XX    {
  557. XX        if    (c == term)    break;
  558. XX        elif    (c == '\\')    (void) input ();
  559. XX    }
  560. XX}
  561. XX
  562. XX
  563. XXvoid lex_init ()
  564. XX{
  565. XX    /*  Initialise the Lexical Analyser for a new file  */
  566. XX    /*  lex itself should provide this!                 */
  567. XX
  568. XX    yyleng        =  0;
  569. XX    yymorfg        =  0;
  570. XX    yytchar        =  0;
  571. XX    yybgin        =  yysvec+1;
  572. XX    yylineno    =  1;
  573. XX    yysptr        =  yysbuf;
  574. XX    yyprevious    =  YYNEWLINE;
  575. XX}
  576. ====End of SHAR lex.l====
  577. if    [ "`wc -c <'lex.l'`" != '    2254' ]
  578. then    echo 'Unpack for lex.l failed!'
  579.     exit 1
  580. else    echo 'Unpacked lex.l'
  581. fi
  582. sed -e 's/^XX//' <<'====End of SHAR main.c====' >main.c
  583. XX/*----------------------------------------------------------------------*/
  584. XX/*                                    */
  585. XX/*        C Checker Main Entry Point                */
  586. XX/*                                    */
  587. XX/*----------------------------------------------------------------------*/
  588. XX
  589. XX
  590. XX#include    <stdio.h>
  591. XX#include    <ctype.h>
  592. XX#include    "check.h"
  593. XX#include    "y.tab.h"
  594. XX
  595. XX#define        MAXNAME        120
  596. XX#define        CPP        "/lib/cpp -C %s %s"
  597. XX
  598. XXextern void    perror(), exit();
  599. XX
  600. XXint    errors = 0;            /*  count of number of errors    */
  601. XXchar    filebuf [MAXNAME];        /*  Buffer for file names    */
  602. XXchar    *filename;            /*  Pointer to file name    */
  603. XXchar    *progname;            /*  Name of this program    */
  604. XX
  605. XX/*  Really should recode this to avoid using fixed buffer sizes;  */
  606. XX/*  malloc and realloc are not difficult to use!                  */
  607. XXchar    options [BUFSIZ];        /*  Buffer for cpp options    */
  608. XX
  609. XX
  610. XXint main (argc, argv)
  611. XXint    argc;
  612. XXchar    *argv[];
  613. XX{
  614. XX    /*    Main Entry Point to C Checker        */
  615. XX    /*  Check each file as specified by arguments    */
  616. XX
  617. XX    char        command [BUFSIZ];    /*  for cpp command  */
  618. XX    register char    *opts = options;
  619. XX    register char    *opt_end = & options [BUFSIZ-2];
  620. XX    register int    pnames;
  621. XX    register int    ptree = FALSE;
  622. XX    extern char    *strncat ();
  623. XX    extern FILE    *popen ();
  624. XX
  625. XX    sy_init ();
  626. XX    progname = *argv++;
  627. XX
  628. XX    /*  Extract C PreProcessor options  */
  629. XX
  630. XX    while    (--argc && **argv == '-')
  631. XX    {
  632. XX        register char *ap = *argv++;
  633. XX
  634. XX        if    (strcmp ("--", ap) == 0)
  635. XX        {
  636. XX            /*  End of Options  */
  637. XX
  638. XX            break;
  639. XX        }
  640. XX#if    YYDEBUG
  641. XX        elif    (strcmp ("-yydebug", ap) == 0)
  642. XX        {
  643. XX            /*  Turn on Yacc Tracing  */
  644. XX
  645. XX            extern int yydebug;
  646. XX            yydebug = 1;
  647. XX        }
  648. XX#endif
  649. XX        elif    (strcmp ("-TP", ap) == 0)
  650. XX        {
  651. XX            /*  Print Parse Tree option (debug)  */
  652. XX
  653. XX            ptree = TRUE;
  654. XX        }
  655. XX        else
  656. XX        {
  657. XX            /*  C PreProcessor option  */
  658. XX
  659. XX            while    (*ap && (opts < opt_end)) *opts++ = *ap++;
  660. XX            *opts++ = ' ';
  661. XX        }
  662. XX    }
  663. XX    *opts++ = ' ';
  664. XX    *opts++ = '\0';
  665. XX
  666. XX    pnames = argc - 1;
  667. XX    while    (argc--)
  668. XX    {
  669. XX        /*  Open a pipe for reading from C PreProcessor  */
  670. XX
  671. XX        filename = *argv++;
  672. XX        (void) sprintf (command, CPP, options, filename);
  673. XX        if  (pnames > 0)  Printf ("%s:\n", filename);
  674. XX
  675. XX        if    ((yyin = popen (command, "r")) == NULL)
  676. XX        {
  677. XX            perror ("cannot open pipe");
  678. XX            exit (1);
  679. XX        }
  680. XX        else
  681. XX        {
  682. XX            /*  Analyse one C source file  */
  683. XX
  684. XX            lex_init ();
  685. XX            met_init ();
  686. XX            if  (yyparse ())  warn ("fatal syntax error");
  687. XX
  688. XX            /*  Report on results of analysis  */
  689. XX
  690. XX            if  (ptree)  treeprint ();
  691. XX            check_prog ();
  692. XX            metrics ((char *) 0);
  693. XX
  694. XX            /*  Tidy up, ready for another source file  */
  695. XX
  696. XX            (void) pclose (yyin);
  697. XX            tidy_prog ();
  698. XX            sy_tidy ();
  699. XX        }
  700. XX    }
  701. XX
  702. XX    return errors;
  703. XX}
  704. XX
  705. XX
  706. XXchar *emalloc (n)
  707. XXunsigned n;
  708. XX{
  709. XX    /*====  Allocate Memory  ====*/
  710. XX
  711. XX    char    *p, *malloc ();
  712. XX
  713. XX    p = malloc (n);
  714. XX
  715. XX    if (p == 0)  error ("out of memory");
  716. XX
  717. XX    return p;
  718. XX}
  719. XX
  720. XX
  721. XXvoid yyerror (s)
  722. XXchar    *s;
  723. XX{
  724. XX    /*  Syntax Error from Yacc  */
  725. XX
  726. XX    errors++;
  727. XX    Fprintf (stderr, "%s: %s at or near line %d, token %d\n",
  728. XX        filename, s, yylineno, yychar);
  729. XX}
  730. XX
  731. XX
  732. XXvoid warn (s)
  733. XXchar    *s;
  734. XX{
  735. XX    /*  Generate a warning message  */
  736. XX
  737. XX    errors++;
  738. XX    Fprintf (stderr, "%s: %s at or near line %d\n",
  739. XX        filename, s, yylineno);
  740. XX}
  741. XX
  742. XX
  743. XXvoid error (s)
  744. XXchar    *s;
  745. XX{
  746. XX    /*  Handle fatal errors  */
  747. XX
  748. XX    warn (s);
  749. XX    exit (errors);
  750. XX}
  751. XX
  752. XX
  753. XXvoid setline (line)
  754. XXchar    *line;
  755. XX{
  756. XX    /*  Handle a #line directive  */
  757. XX
  758. XX    register char    *cp  = line;
  759. XX    register char    *fn  = filebuf;
  760. XX    register int    lnum = 0;
  761. XX
  762. XX    if    (*cp != '#')        error ("invalid call to setline");
  763. XX
  764. XX    while    (*cp && !isdigit(*cp))    cp++;
  765. XX    while    (*cp && isdigit (*cp))    lnum = lnum*10 + (*cp++ - '0');
  766. XX    while    (*cp && *cp != '"')    cp++;
  767. XX    if    (lnum)            yylineno = lnum;
  768. XX
  769. XX    if    (*cp++ == 0)        return;
  770. XX    while    (*cp && *cp != '"')    *fn++ = *cp++;
  771. XX    if    (fn == filename)    return;
  772. XX
  773. XX    *fn     = '\0';
  774. XX    filename = filebuf;
  775. XX}
  776. ====End of SHAR main.c====
  777. if    [ "`wc -c <'main.c'`" != '    3532' ]
  778. then    echo 'Unpack for main.c failed!'
  779.     exit 1
  780. else    echo 'Unpacked main.c'
  781. fi
  782. sed -e 's/^XX//' <<'====End of SHAR metric.c====' >metric.c
  783. XX/*----------------------------------------------------------------------*/
  784. XX/*                                    */
  785. XX/*    This module will do software metrics one day...            */
  786. XX/*                                    */
  787. XX/*----------------------------------------------------------------------*/
  788. XX
  789. XX
  790. XX#include    <stdio.h>
  791. XX#include    "check.h"
  792. XX#include    "y.tab.h"
  793. XX
  794. XXtypedef    struct    Metric {
  795. XX    int    sep_nouns;
  796. XX    int    sep_verbs;
  797. XX    int    tot_nouns;
  798. XX    int    tot_verbs;
  799. XX    int    stmts;
  800. XX    int    comments;
  801. XX    int    lines;
  802. XX    int    decisions;
  803. XX    int    knots;
  804. XX}    Metric;
  805. XX
  806. XXMetric    total, local;
  807. XX
  808. XX
  809. XXvoid swm (m)
  810. XXMetric    *m;
  811. XX{
  812. XX    /*  This procedure will print the Software Metrics  */
  813. XX
  814. XX/*  Commented out until Lex & Grammar re-written to increment counts ...
  815. XX    extern    double    log();
  816. XX
  817. XX    double    vocab, length, volume, diff, effort, lang;
  818. XX    double    decid, comms, layout;
  819. XX    double    mccabe, knots;
  820. XX
  821. XX    vocab    = m->sep_verbs + m->sep_nouns;
  822. XX    length    = m->tot_verbs + m->tot_nouns;
  823. XX    volume    = length * log(vocab) / log(2.0);
  824. XX    diff    = (m->sep_verbs*m->tot_nouns)/(2.0*m->sep_nouns);
  825. XX    effort    = volume * diff;
  826. XX    lang    = volume / (diff * diff);
  827. XX
  828. XX    decid    = m->decisions / m->stmts;
  829. XX    comms    = m->comments / m->stmts;
  830. XX    layout    = (m->stmts + m->comments) / m->lines;
  831. XX
  832. XX    mccabe    = m->decisions + 1;
  833. XX    knots    = m->knots;
  834. XX
  835. XX    Printf ("%8.2g %8.2g %8.2g %8.2g %8.2g %8.2g %8.2g\n",
  836. XX        volume, diff, effort, lang,
  837. XX        decid, comms, layout,
  838. XX        mccabe, knots
  839. XX    );
  840. XX............................................................ */
  841. XX}
  842. XX
  843. XX
  844. XXvoid metrics (this_proc)
  845. XXchar    *this_proc;
  846. XX{
  847. XX    /*  Report on the Software Metrics for current procedure, or  */
  848. XX    /*  report on the total for the file if this_proc is null.    */
  849. XX
  850. XX/*  Commented out until Lex re-written to increment counts ...
  851. XX    if    (this_proc)
  852. XX    {
  853. XX        Printf ("%12.10s ", this_proc);
  854. XX        swm (&local);
  855. XX    }
  856. XX    else
  857. XX    {
  858. XX        Printf ("%12.10s ", "Total:");
  859. XX        swm (&total);
  860. XX    }
  861. XX............................................................ */
  862. XX}
  863. XX
  864. XX
  865. XXvoid proc_start ()
  866. XX{
  867. XX    /*  Initialise the counts for a procedure  */
  868. XX
  869. XX    local.sep_nouns    = 1;
  870. XX    local.sep_verbs    = 1;
  871. XX    local.tot_nouns    = 1;
  872. XX    local.tot_verbs    = 1;
  873. XX    local.stmts    = 1;
  874. XX    local.comments    = 1;
  875. XX    local.lines    = 1;
  876. XX    local.decisions    = 1;
  877. XX    local.knots    = 1;
  878. XX}
  879. XX
  880. XX
  881. XXvoid met_init ()
  882. XX{
  883. XX    /*  Initialise the counts for a file  */
  884. XX
  885. XX    proc_start ();
  886. XX
  887. XX    total.sep_nouns    = 1;
  888. XX    total.sep_verbs    = 1;
  889. XX    total.tot_nouns    = 1;
  890. XX    total.tot_verbs    = 1;
  891. XX    total.stmts    = 1;
  892. XX    total.comments    = 1;
  893. XX    total.lines    = 1;
  894. XX    total.decisions    = 1;
  895. XX    total.knots    = 1;
  896. XX}
  897. ====End of SHAR metric.c====
  898. if    [ "`wc -c <'metric.c'`" != '    2326' ]
  899. then    echo 'Unpack for metric.c failed!'
  900.     exit 1
  901. else    echo 'Unpacked metric.c'
  902. fi
  903. sed -e 's/^XX//' <<'====End of SHAR parse.awk====' >parse.awk
  904. XXawk '
  905. XXBEGIN            { state = 0; }
  906. XX/^state/        { --state; }
  907. XX/shift\/reduce/        { state = 2; }
  908. XX/reduce\/reduce/    { state = 2; }
  909. XX/terminals,/        { state = 2; }
  910. XX            { if (state > 0) printf "%s\n", $0; }
  911. XX
  912. XX' y.output >yacclist
  913. ====End of SHAR parse.awk====
  914. chmod +x parse.awk
  915. if    [ "`wc -c <'parse.awk'`" != '     208' ]
  916. then    echo 'Unpack for parse.awk failed!'
  917.     exit 1
  918. else    echo 'Unpacked parse.awk'
  919. fi
  920. sed -e 's/^XX//' <<'====End of SHAR parse.y====' >parse.y
  921. XX/*    YACC Grammar for C - not very strict.        */
  922. XX/*    No attempt is made to conform to or accept    */
  923. XX/*    ANSI C yet.  Some obsolete constructs are    */
  924. XX/*    not supported (deliberately).            */
  925. XX/*                            */
  926. XX/*    If your terminal can handle it, view/edit this    */
  927. XX/*    file in 120 or 132 column mode, as all the    */
  928. XX/*    actions start in column 72.            */
  929. XX/*                            */
  930. XX/*    Note that TYPEDEF names must be recognised as    */
  931. XX/*    such, and return a different token from the    */
  932. XX/*    Lexical Analyser.                */
  933. XX/*                            */
  934. XX/*    The Actions build a Parse Tree.            */
  935. XX
  936. XX%{
  937. XX#include    <stdio.h>
  938. XX#include    "check.h"
  939. XX
  940. XX
  941. XX    /*----------  Macros for Tree Building  ----------*/
  942. XX
  943. XX
  944. XX#define        Z            (NodePtr) 0
  945. XX#define        node0(t)        new_node (t, Z, Z, Z, Z);
  946. XX#define        node1(t,a)        new_node (t, a, Z, Z, Z);
  947. XX#define        node2(t,a,b)        new_node (t, a, b, Z, Z);
  948. XX#define        node3(t,a,b,c)        new_node (t, a, b, c, Z);
  949. XX#define        node4(t,a,b,c,d)    new_node (t, a, b, c, d);
  950. XX
  951. XX%}
  952. XX
  953. XX%union {                /*  Type for Parser Stack    */
  954. XX    Symbol        *id;        /*  Name for ID, or string    */
  955. XX    int        ival;        /*  integer constants        */
  956. XX    unsigned    uval;        /*  octal & hex constants    */
  957. XX    NodePtr        ptr;        /*  pointer to Parse Tree Node    */
  958. XX}
  959. XX
  960. XX%token    <id>    IDENTIFIER    TYPENAME
  961. XX
  962. XX%token    <ival>    CONSTANT
  963. XX
  964. XX%token        AUTO        BREAK        CASE        CHAR
  965. XX        CONTINUE    DEFAULT        DO        DOUBLE
  966. XX        ELSE        ENUM        EXTERN        FLOAT
  967. XX        FOR        GOTO        IF        INT
  968. XX        LONG        REGISTER    RETURN        SHORT
  969. XX        SIZEOF        STATIC        STRUCT        SWITCH
  970. XX        TYPEDEF        UNION        UNSIGNED    VOID
  971. XX        WHILE
  972. XX
  973. XX        Shift        And        Or        Rel_Op
  974. XX        Eq_Op        IncDec        Asgn_Op        Point
  975. XX
  976. XX%right        Asgn_Op
  977. XX%right        '?'        ':'
  978. XX%left        Or
  979. XX%left        And
  980. XX%left        '|'
  981. XX%left        '^'
  982. XX%left        '&'
  983. XX%left        Eq_Op
  984. XX%left        Rel_Op
  985. XX%left        Shift
  986. XX%left        '+'        '-'
  987. XX%left        '*'        '/'        '%'
  988. XX%left        Prefix
  989. XX%left        SizeOf
  990. XX%left        IncDec        Point        '.'
  991. XX%left        '['        '('
  992. XX
  993. XX%type    <id>    declarator
  994. XX
  995. XX%type    <ptr>    top_level_decls        top_level_decl        function_decl
  996. XX        type_name        compound        statements
  997. XX        statement        label            expr_opt
  998. XX        expr_list        expression        tag
  999. XX
  1000. XX%%
  1001. XX
  1002. XX
  1003. XX/*--------------------------   DECLARATIONS   -------------------------------*/
  1004. XX
  1005. XX
  1006. XXprogram        :    top_level_decls                    { Tree = $1; }
  1007. XX        ;
  1008. XX
  1009. XXtop_level_decls    :    /*  empty  */                    { proc_start(); $$ = node0 (0); }
  1010. XX        |    top_level_decls top_level_decl            { proc_start(); $$ = node2 (Seq, $1, $2); }
  1011. XX        ;
  1012. XX
  1013. XXtop_level_decl    :    function_decl                    { $$ = $1; }
  1014. XX        |    declaration                    { $$ = node0 (0); }
  1015. XX        |    error '}'                    { $$ = node0 (Error); }
  1016. XX        |    error ';'                    { $$ = node0 (Error); }
  1017. XX        ;
  1018. XX
  1019. XXfunction_decl    :    specifiers declarator declarations compound    { $$ = $4; metrics ($2->name); }
  1020. XX        |    declarator declarations compound        { $$ = $3; metrics ($1->name); }
  1021. XX        ;
  1022. XX
  1023. XXdeclarations    :    /*  empty  */
  1024. XX        |    declarations declaration
  1025. XX        ;
  1026. XX
  1027. XXdeclaration    :    specifiers init_dclrtrs ';'
  1028. XX        |    specifiers ';'
  1029. XX        ;
  1030. XX
  1031. XXspecifiers    :    storage
  1032. XX        |    storage type_spec
  1033. XX        |    type_spec
  1034. XX        ;
  1035. XX
  1036. XXstorage        :    AUTO
  1037. XX        |    EXTERN
  1038. XX        |    REGISTER
  1039. XX        |    STATIC
  1040. XX        ;
  1041. XX
  1042. XXtype_spec    :    int_spec
  1043. XX        |    UNSIGNED int_spec
  1044. XX        |    UNSIGNED
  1045. XX        |    float_spec
  1046. XX        |    enum_spec
  1047. XX        |    struct_spec
  1048. XX        |    union_spec
  1049. XX        |    TYPENAME
  1050. XX        |    VOID
  1051. XX        ;
  1052. XX
  1053. XXdeclarator    :    IDENTIFIER                    { $$ = $1; }
  1054. XX        |    '(' declarator ')'                { $$ = $2; }
  1055. XX        |    declarator '(' parameter_list ')'        { $$ = $1; }
  1056. XX        |    declarator '(' ')'                { $$ = $1; }
  1057. XX        |    declarator '[' expr_opt ']'            { $$ = $1; }
  1058. XX        |    '*' declarator %prec Prefix            { $$ = $2; }
  1059. XX        ;
  1060. XX
  1061. XXparameter_list    :    IDENTIFIER
  1062. XX        |    parameter_list ',' IDENTIFIER
  1063. XX        ;
  1064. XX
  1065. XXinit_dclrtrs    :    declarator
  1066. XX        |    declarator Asgn_Op initialiser
  1067. XX        |    init_dclrtrs ',' declarator
  1068. XX        |    init_dclrtrs ',' declarator Asgn_Op initialiser
  1069. XX        ;
  1070. XX
  1071. XXinitialiser    :    expression
  1072. XX        |    '{' init_list '}'
  1073. XX        |    '{' init_list ',' '}'
  1074. XX        ;
  1075. XX
  1076. XXinit_list    :    initialiser
  1077. XX        |    init_list ',' initialiser
  1078. XX        ;
  1079. XX
  1080. XXdeclaration    :    TYPEDEF type_spec type_decls ';'
  1081. XX        ;
  1082. XX
  1083. XXtype_decls    :    declarator                    { $1->token = TYPENAME; }
  1084. XX        |    type_decls ',' declarator            { $3->token = TYPENAME; }
  1085. XX        ;
  1086. XX
  1087. XX
  1088. XX/*----------------------------   TYPES   ----------------------------------*/
  1089. XX
  1090. XX
  1091. XXint_spec    :    CHAR | SHORT | SHORT INT | INT | LONG INT | LONG ;
  1092. XXfloat_spec    :    FLOAT | LONG FLOAT | DOUBLE ;
  1093. XX
  1094. XXenum_spec    :    ENUM IDENTIFIER
  1095. XX        |    ENUM IDENTIFIER '{' enum_fields '}'
  1096. XX        |    ENUM '{' enum_fields '}'
  1097. XX        ;
  1098. XX
  1099. XXstruct_spec    :    STRUCT IDENTIFIER
  1100. XX        |    STRUCT IDENTIFIER '{' struct_fields '}'
  1101. XX        |    STRUCT '{' struct_fields '}'
  1102. XX        ;
  1103. XX
  1104. XXunion_spec    :    UNION IDENTIFIER
  1105. XX        |    UNION IDENTIFIER '{' struct_fields '}'
  1106. XX        |    UNION '{' struct_fields '}'
  1107. XX        ;
  1108. XX
  1109. XXenum_fields    :    enum_const
  1110. XX        |    enum_fields ',' enum_const
  1111. XX        ;
  1112. XX
  1113. XXenum_const    :    IDENTIFIER
  1114. XX        |    IDENTIFIER Asgn_Op expression
  1115. XX        ;
  1116. XX
  1117. XXstruct_fields    :    type_spec field_list ';'
  1118. XX        |    struct_fields type_spec field_list ';'
  1119. XX        |    error ';'
  1120. XX        ;
  1121. XX
  1122. XXfield_list    :    field
  1123. XX        |    field_list ',' field
  1124. XX        ;
  1125. XX
  1126. XXfield        :    declarator
  1127. XX        |    declarator ':' expression
  1128. XX        |    ':' expression
  1129. XX        ;
  1130. XX
  1131. XXtype_name    :    type_spec                    { $$ = node0 (Type); }
  1132. XX        |    type_spec abstract                { $$ = node0 (Type); }
  1133. XX        ;
  1134. XX
  1135. XXabstract    :    '(' abstract ')'
  1136. XX        |    '(' ')'
  1137. XX        |    abstract '(' ')'
  1138. XX        |    '[' expr_opt ']'
  1139. XX        |    abstract '[' expr_opt ']'
  1140. XX        |    '*' %prec Prefix
  1141. XX        |    '*' abstract %prec Prefix
  1142. XX        ;
  1143. XX
  1144. XX
  1145. XX/*--------------------------   STATEMENTS   --------------------------------*/
  1146. XX
  1147. XX
  1148. XXcompound    :    '{' declarations statements '}'            { $$ = node1 (Seq, $3); }
  1149. XX        |    '{' '}'                        { $$ = node0 (0); }
  1150. XX        |    error '}'                    { $$ = node0 (Error); }
  1151. XX        ;
  1152. XX
  1153. XXstatements    :    statement                    { $$ = $1; }
  1154. XX        |    statements statement                { $$ = node2 (Seq, $1, $2); }
  1155. XX        ;
  1156. XX
  1157. XXstatement    :    expr_list ';'                    { $$ = $1; }
  1158. XX        |    label ':' statement                { $$ = node2 (Label, $1, $3); }
  1159. XX        |    compound                    { $$ = $1; }
  1160. XX        |    IF '(' expr_list ')' statement            { $$ = node3 (IF, $3, $5, Z); }
  1161. XX        |    IF '(' expr_list ')' statement ELSE statement    { $$ = node3 (IF, $3, $5, $7); }
  1162. XX        |    WHILE '(' expr_list ')' statement        { $$ = node2 (WHILE, $3, $5); }
  1163. XX        |    DO statement WHILE '(' expr_list ')' ';'    { $$ = node2 (DO, $2, $5); }
  1164. XX        |    FOR '(' expr_opt ';' expr_opt ';' expr_opt ')'
  1165. XX            statement                    { $$ = node4 (FOR, $3, $5, $7, $9); }
  1166. XX        |    SWITCH '(' expr_list ')' statement        { $$ = node2 (SWITCH, $3, $5); }
  1167. XX        |    BREAK ';'                    { $$ = node0 (BREAK); }
  1168. XX        |    CONTINUE ';'                    { $$ = node0 (CONTINUE); }
  1169. XX        |    RETURN expr_opt ';'                { $$ = node1 (RETURN, $2); }
  1170. XX        |    GOTO tag ';'                    { $$ = node1 (GOTO, Z); }
  1171. XX        |    ';'                        { $$ = node0 (';'); }
  1172. XX        |    error ';'                    { $$ = node0 (Error); }
  1173. XX        ;
  1174. XX
  1175. XXlabel        :    tag                        { $$ = $1; }
  1176. XX        |    CASE expression                    { $$ = node1 (CASE, $2); }
  1177. XX        |    DEFAULT                        { $$ = node0 (DEFAULT); }
  1178. XX        ;
  1179. XX
  1180. XX
  1181. XX/*---------------------------   EXPRESSIONS   -------------------------------*/
  1182. XX
  1183. XX
  1184. XXexpr_opt    :    /*  empty  */                    { $$ = node0 (0); }
  1185. XX        |    expr_list                    { $$ = $1; }
  1186. XX        ;
  1187. XX
  1188. XXexpr_list    :    expression                    { $$ = $1; }
  1189. XX        |    expr_list ',' expression            { $$ = node2 (',', $1, $3); }
  1190. XX        ;
  1191. XX
  1192. XXexpression    :    expression Asgn_Op expression            { $$ = node2 (Asgn_Op, $1, $3); }
  1193. XX        |    expression '?' expr_list ':' expression        { $$ = node3 ('?', $1, $3, $5); }
  1194. XX        |    expression Or expression            { $$ = node2 (Or, $1, $3); }
  1195. XX        |    expression And expression            { $$ = node2 (And, $1, $3); }
  1196. XX        |    expression '|' expression            { $$ = node2 ('|', $1, $3); }
  1197. XX        |    expression '^' expression            { $$ = node2 ('^', $1, $3); }
  1198. XX        |    expression '&' expression            { $$ = node2 ('&', $1, $3); }
  1199. XX        |    expression Eq_Op expression            { $$ = node2 (Eq_Op, $1, $3); }
  1200. XX        |    expression Rel_Op expression            { $$ = node2 (Rel_Op, $1, $3); }
  1201. XX        |    expression Shift expression            { $$ = node2 (Shift, $1, $3); }
  1202. XX        |    expression '+' expression            { $$ = node2 ('+', $1, $3); }
  1203. XX        |    expression '-' expression            { $$ = node2 ('-', $1, $3); }
  1204. XX        |    expression '*' expression            { $$ = node2 ('*', $1, $3); }
  1205. XX        |    expression '/' expression            { $$ = node2 ('/', $1, $3); }
  1206. XX        |    expression '%' expression            { $$ = node2 ('%', $1, $3); }
  1207. XX        |    '*' expression %prec Prefix            { $$ = node1 (Indirect, $2); }
  1208. XX        |    '&' expression %prec Prefix            { $$ = node1 (Addr, $2); }
  1209. XX        |    '+' expression %prec Prefix            { $$ = node1 (Uplus, $2); }
  1210. XX        |    '-' expression %prec Prefix            { $$ = node1 (Uminus, $2); }
  1211. XX        |    '!' expression %prec Prefix            { $$ = node1 ('!', $2); }
  1212. XX        |    '~' expression %prec Prefix            { $$ = node1 ('~', $2); }
  1213. XX        |    '(' type_name ')' expression %prec Prefix    { $$ = node2 (Cast, $2, $4); }
  1214. XX        |    IncDec expression %prec Prefix            { $$ = node1 (Pre_Inc, $2); }
  1215. XX        |    SIZEOF '(' type_name ')' %prec SizeOf        { $$ = node1 (Size_Type, $3); }
  1216. XX        |    SIZEOF expression %prec SizeOf            { $$ = node1 (Size_Expr, $2); }
  1217. XX        |    expression IncDec                { $$ = node1 (Post_Inc, $1); }
  1218. XX        |    expression Point tag                { $$ = node2 (Point, $1, $3); }
  1219. XX        |    expression '.' tag                { $$ = node2 ('.', $1, $3); }
  1220. XX        |    expression '(' ')'                { $$ = node2 ('(', $1, Z); }
  1221. XX        |    expression '(' expr_list ')'            { $$ = node2 ('(', $1, $3); }
  1222. XX        |    expression '[' expr_list ']'            { $$ = node2 ('[', $1, $3); }
  1223. XX        |    '(' expr_list ')'                { $$ = $2; }
  1224. XX        |    tag                        { $$ = $1; }
  1225. XX        |    CONSTANT                    { $$ = node1 (CONSTANT, Z); }
  1226. XX        ;
  1227. XX
  1228. XXtag        :    IDENTIFIER                    { $$ = node1 (IDENTIFIER, (NodePtr) $1); }
  1229. XX        ;
  1230. ====End of SHAR parse.y====
  1231. if    [ "`wc -c <'parse.y'`" != '    8625' ]
  1232. then    echo 'Unpack for parse.y failed!'
  1233.     exit 1
  1234. else    echo 'Unpacked parse.y'
  1235. fi
  1236. sed -e 's/^XX//' <<'====End of SHAR symbol.c====' >symbol.c
  1237. XX/*----------------------------------------------------------------------*/
  1238. XX/*                                    */
  1239. XX/*    This module handles a symbol/type hash table            */
  1240. XX/*                                    */
  1241. XX/*----------------------------------------------------------------------*/
  1242. XX
  1243. XX
  1244. XX#include    <stdio.h>
  1245. XX#ifdef    BSD
  1246. XX#include    <strings.h>
  1247. XX#define        memset(p,c,n)    {register int i;for(i=0;i<(n);i++)(p)[i]=(c);}
  1248. XX#else
  1249. XX#include    <string.h>
  1250. XX#include    <memory.h>
  1251. XX#endif
  1252. XX#include    "check.h"
  1253. XX#include    "y.tab.h"
  1254. XX
  1255. XX#define        HASH_SIZE    1000  /*  Allow for 750 names at 75% full  */
  1256. XX
  1257. XXunsigned hsize;        /* Size of the hash table */
  1258. XXSymbol    **htable;    /* Pointer to an array of ponters to hash entries */
  1259. XX
  1260. XX#ifdef    DEBUG
  1261. XXunsigned *hcount;    /* Pointer to an array of hash counts  */
  1262. XX#endif
  1263. XX
  1264. XX
  1265. XXunsigned hash (key)
  1266. XXregister char    *key;
  1267. XX{
  1268. XX    /*  Hash a key string  */
  1269. XX
  1270. XX    register unsigned    hval = 0;
  1271. XX
  1272. XX    while  (*key)  hval = (hval << 3) + (hval >> 29) + *key++;
  1273. XX
  1274. XX    hval = (hval & 0x7fffffff) % hsize;
  1275. XX    return hval;
  1276. XX}
  1277. XX
  1278. XX
  1279. XXvoid mkhash (size)
  1280. XXunsigned    size;        /* Minimum size for hash table */
  1281. XX{
  1282. XX    /*  Create a hash table of size rounded up to next power of two-1  */
  1283. XX
  1284. XX    register unsigned tsize = size;
  1285. XX
  1286. XX    hsize = 1;        /* Actual hash table size  */
  1287. XX    while    (tsize)
  1288. XX    {
  1289. XX        tsize >>= 1;
  1290. XX        hsize <<= 1;
  1291. XX    }
  1292. XX    hsize--;
  1293. XX    if  (hsize == 0)  hsize++;   /* Silly, but it will work! */
  1294. XX
  1295. XX    htable = (Symbol **) emalloc (hsize * sizeof(Symbol *));
  1296. XX    memset ((char *) htable, 0, (int) (hsize * sizeof(Symbol *)));
  1297. XX
  1298. XX#ifdef    DEBUG
  1299. XX    Printf ("mkhash table size %d\n", hsize);
  1300. XX    hcount = (unsigned *) emalloc (hsize * sizeof(unsigned));
  1301. XX    memset ((char *) hcount, 0, (int) (hsize * sizeof(unsigned)));
  1302. XX#endif
  1303. XX}
  1304. XX
  1305. XX
  1306. XXvoid rmhash ()
  1307. XX{
  1308. XX    /*  Destroy hash table and all chained entries  */
  1309. XX
  1310. XX    register Symbol    **pp, *p;
  1311. XX    extern void    free();
  1312. XX
  1313. XX    for    (pp = htable; pp < htable + hsize; pp++)
  1314. XX    {
  1315. XX        while    (p = *pp)
  1316. XX        {
  1317. XX            *pp = p->next;
  1318. XX            free (p->name);
  1319. XX            free ((char *)p);
  1320. XX        }
  1321. XX    }
  1322. XX
  1323. XX    free((char *) htable);
  1324. XX    htable = 0;
  1325. XX}
  1326. XX
  1327. XX
  1328. XXSymbol *findsym (name, token, action)
  1329. XXchar    *name;        /* name to be inserted or found */
  1330. XXToken    token;        /* type of symbol */
  1331. XXAction    action;        /* Create or Find */
  1332. XX{
  1333. XX    /*  Search for, and create if required, an entry in the hash table  */
  1334. XX
  1335. XX    register Symbol        **pp;    /* address of pointer to entry    */
  1336. XX    register Symbol        *p;    /* search through linked list    */
  1337. XX    register unsigned    hval;    /* hash value from name        */
  1338. XX    register int        res;    /* result of strcmp        */
  1339. XX
  1340. XX    pp = &htable[hval = hash(name)];
  1341. XX    p = *pp;
  1342. XX
  1343. XX    while    (p != NULL)
  1344. XX    {
  1345. XX        if    ((res = strcmp(name, p->name)) == 0)
  1346. XX        {
  1347. XX            return p;
  1348. XX        }
  1349. XX        elif    (res < 0)
  1350. XX        {
  1351. XX            /*  past point where name would be in sorted chain  */
  1352. XX            break;
  1353. XX        }
  1354. XX        pp = &(p->next);
  1355. XX        p = *pp;
  1356. XX    }
  1357. XX
  1358. XX    /* Item is not yet on list */
  1359. XX    if    (action == Find)
  1360. XX        return NilSym;
  1361. XX    else
  1362. XX    {
  1363. XX#ifdef    DEBUG
  1364. XX        /*  Accumulate hashing statistics  */
  1365. XX        hcount[hval]++;
  1366. XX#endif
  1367. XX        p = (Symbol *) emalloc (sizeof(Symbol));
  1368. XX        p->name = strcpy (emalloc ((unsigned) strlen(name)+1), name);
  1369. XX        p->token = token;
  1370. XX        p->next = *pp;
  1371. XX        *pp = p;
  1372. XX        return p;
  1373. XX    }
  1374. XX}
  1375. XX
  1376. XX
  1377. XXstatic struct Keyword {
  1378. XX    char    *name;
  1379. XX    Token    token;
  1380. XX} keywords [] = {
  1381. XX    "auto",        AUTO,
  1382. XX    "break",    BREAK,
  1383. XX    "case",        CASE,
  1384. XX    "char",        CHAR,
  1385. XX    "continue",    CONTINUE,
  1386. XX    "default",    DEFAULT,
  1387. XX    "do",        DO,
  1388. XX    "double",    DOUBLE,
  1389. XX    "else",        ELSE,
  1390. XX    "enum",        ENUM,
  1391. XX    "extern",    EXTERN,
  1392. XX    "float",    FLOAT,
  1393. XX    "for",        FOR,
  1394. XX    "goto",        GOTO,
  1395. XX    "if",        IF,
  1396. XX    "int",        INT,
  1397. XX    "long",        LONG,
  1398. XX    "register",    REGISTER,
  1399. XX    "return",    RETURN,
  1400. XX    "short",    SHORT,
  1401. XX    "sizeof",    SIZEOF,
  1402. XX    "static",    STATIC,
  1403. XX    "struct",    STRUCT,
  1404. XX    "switch",    SWITCH,
  1405. XX    "typedef",    TYPEDEF,
  1406. XX    "union",    UNION,
  1407. XX    "unsigned",    UNSIGNED,
  1408. XX    "void",        VOID,
  1409. XX    "while",    WHILE,
  1410. XX    0,        0
  1411. XX};
  1412. XX
  1413. XX
  1414. XXvoid sy_init ()
  1415. XX{
  1416. XX    /*  Initialise the Symbol Table with the reserved words  */
  1417. XX
  1418. XX    register struct Keyword *kw;
  1419. XX
  1420. XX    mkhash (HASH_SIZE);
  1421. XX    for    (kw = keywords; kw->name; kw++)
  1422. XX    {
  1423. XX        (void) findsym (kw->name, kw->token, Create);
  1424. XX    }
  1425. XX}
  1426. XX
  1427. XX
  1428. XXvoid sy_tidy ()
  1429. XX{
  1430. XX    /*  Remove all but reserved words from the Symbol Table  */
  1431. XX    /*  This is achieved by brute force; destroy & recreate! */
  1432. XX
  1433. XX#ifdef    DEBUG
  1434. XX    /*  print hash statistics  */
  1435. XX    register unsigned i, j, tot = 0, maxc = 0, unused = 0;
  1436. XX    for  (i=0; i<hsize; i++)
  1437. XX    {
  1438. XX        /*  print hash count if non-zero  */
  1439. XX        if    (j = hcount[i])
  1440. XX        {
  1441. XX            Printf ("hash %6d : %d\n", i, j);
  1442. XX            if  (j > maxc)  maxc = j;
  1443. XX            tot += j;
  1444. XX        }
  1445. XX        else    unused++;
  1446. XX    }
  1447. XX    Printf ("Total=%d, max chain length=%d, unused=%d\n",tot,maxc,unused);
  1448. XX#endif
  1449. XX    rmhash ();
  1450. XX    sy_init ();
  1451. XX}
  1452. ====End of SHAR symbol.c====
  1453. if    [ "`wc -c <'symbol.c'`" != '    4271' ]
  1454. then    echo 'Unpack for symbol.c failed!'
  1455.     exit 1
  1456. else    echo 'Unpacked symbol.c'
  1457. fi
  1458. sed -e 's/^XX//' <<'====End of SHAR tables.sh====' >tables.sh
  1459. XX
  1460. XX#    Make tables.h from check.h and y.xxx.h
  1461. XX
  1462. XX(
  1463. XXsed <check.h -n -e '/    Parse/,$ s/^#define[     ][     ]*//p'
  1464. XXsed <y.xxx.h -n -e 's/^#[     ]*define[     ][     ]*//p'
  1465. XX) |
  1466. XXawk -e '
  1467. XXBEGIN    {
  1468. XX        printf "typedef struct NodeName {\n"
  1469. XX        printf "\tint val;\n"
  1470. XX        printf "\tchar *str;\n"
  1471. XX        printf "} NodeName;\n\n"
  1472. XX        printf "NodeName\tnodenames[] = {\n"
  1473. XX    }
  1474. XX    {
  1475. XX        printf "\t%d, \"%s\",\n", $2, $1
  1476. XX    }
  1477. XXEND    {
  1478. XX        printf "    0, 0\n};\n"
  1479. XX    }' >tables.h
  1480. ====End of SHAR tables.sh====
  1481. chmod +x tables.sh
  1482. if    [ "`wc -c <'tables.sh'`" != '     412' ]
  1483. then    echo 'Unpack for tables.sh failed!'
  1484.     exit 1
  1485. else    echo 'Unpacked tables.sh'
  1486. fi
  1487. sed -e 's/^XX//' <<'====End of SHAR test.c====' >test.c
  1488. XX/*----------------------------------------------------------------------*/
  1489. XX/*                                    */
  1490. XX/*        C Checker Main Entry Point                */
  1491. XX/*    Modified version of 'main.c' to see messages from check.    */
  1492. XX/*                                    */
  1493. XX/*----------------------------------------------------------------------*/
  1494. XX
  1495. XX
  1496. XX#include    <stdio.h>
  1497. XX#include    <ctype.h>
  1498. XX#include    "check.h"
  1499. XX#include    "y.tab.h"
  1500. XX
  1501. XX#define        MAXNAME        120
  1502. XX#define        CPP        "/lib/cpp -C %s %s"
  1503. XX
  1504. XXextern void    perror(), exit();
  1505. XX
  1506. XXint    errors = 0;            /*  count of number of errors    */
  1507. XXchar    filebuf [MAXNAME];        /*  Buffer for file names    
  1508. XXchar    *filename;            /*  Pointer to file name    */
  1509. XXchar    *progname;            /*  Name of this program    */
  1510. XX
  1511. XX/*  Really should recode this to avoid using fixed buffer sizes;  */
  1512. XX/*  malloc and realloc are not difficult to use!                  */
  1513. XXchar    options [BUFSIZ];        /*  Buffer for cpp options    */
  1514. XX
  1515. XX
  1516. XXint main (argc, argv)
  1517. XXint    argc;
  1518. XXchar    *argv[];
  1519. XX{
  1520. XX    /*    Main Entry Point to C Checker        */
  1521. XX    /*  Check each file as specified by arguments    */
  1522. XX
  1523. XX    char        command [BUFSIZ];    /*  for cpp command  */
  1524. XX    register char    *opts = options;
  1525. XX    register char    *opt_end = & options [BUFSIZ-2];
  1526. XX    register int    pnames;
  1527. XX    register int    ptree = FALSE;
  1528. XX    extern char    *strncat ();
  1529. XX    extern FILE    *popen ();
  1530. XX
  1531. XX    sy_init ();
  1532. XX    progname = *argv++;
  1533. XX
  1534. XX    /*  Extract C PreProcessor options  */
  1535. XX
  1536. XX    while    (--argc && **argv == '-')
  1537. XX    {
  1538. XX        register char *ap = *argv++;
  1539. XX
  1540. XX        if    (strcmp ("--", ap) == 0)
  1541. XX        {
  1542. XX            /*  End of Options  */
  1543. XX
  1544. XX            break;
  1545. XX        }
  1546. XX#if    YYDEBUG
  1547. XX        elif    (strcmp ("-yydebug", ap) == 0)
  1548. XX        {
  1549. XX            /*  Turn on Yacc Tracing  */
  1550. XX
  1551. XX            extern int yydebug;
  1552. XX            yydebug = 1;
  1553. XX        }
  1554. XX#endif
  1555. XX        elif    (strcmp ("-TP", ap) == 0)
  1556. XX        {
  1557. XX            /*  Print Parse Tree option (debug)  */
  1558. XX
  1559. XX            ptree = TRUE;
  1560. XX        }
  1561. XX        else
  1562. XX        {
  1563. XX            /*  C PreProcessor option  */
  1564. XX
  1565. XX            while    (*ap && (opts < opt_end)) *opts++ = *ap++;
  1566. XX            *opts++ = ' ';
  1567. XX        }
  1568. XX    }
  1569. XX    *opts++ = ' ';
  1570. XX    *opts++ = '\0';
  1571. XX
  1572. XX    pnames = argc - 1;
  1573. XX    while    (argc--)
  1574. XX    {
  1575. XX        /*  Open a pipe for reading from C PreProcessor  */
  1576. XX
  1577. XX        filename = *argv++;
  1578. XX        (void) sprintf (command, CPP, options, filename);
  1579. XX        if  (pnames > 0 && filename != NULL && othertests());
  1580. XX            Printf ("%s:\n", filename);
  1581. XX
  1582. XX        if  ((yyin = popen (command, "r")) == NULL)
  1583. XX            if  (yyin == NULL) perror ("cannot open pipe");
  1584. XX        else
  1585. XX        {
  1586. XX            /*  Analyse one C source file  */
  1587. XX
  1588. XX            lex_init ();
  1589. XX            met_init ();
  1590. XX            if  (yyparse ())  warn ("fatal syntax error");
  1591. XX
  1592. XX            /*  Report on results of analysis  */
  1593. XX
  1594. XX            if  (ptree)  treeprint ();
  1595. XX            check_prog ();
  1596. XX            metrics ((char *) 0);
  1597. XX
  1598. XX            /*  Tidy up, ready for another source file  */
  1599. XX
  1600. XX            (void) pclose (yyin);
  1601. XX            tidy_prog ();
  1602. XX            sy_tidy ();
  1603. XX        }
  1604. XX    }
  1605. XX
  1606. XX    return errors;
  1607. XX}
  1608. XX
  1609. XX
  1610. XXchar *emalloc (n)
  1611. XXunsigned n;
  1612. XX{
  1613. XX    /*====  Allocate Memory  ====*/
  1614. XX
  1615. XX    char    *p, *malloc ();
  1616. XX
  1617. XX    p = malloc (n);
  1618. XX
  1619. XX    if (p = 0)  error ("out of memory");
  1620. XX
  1621. XX    return p;
  1622. XX}
  1623. XX
  1624. XX
  1625. XXvoid yyerror (s)
  1626. XXchar    *s;
  1627. XX{
  1628. XX    /*  Syntax Error from Yacc  */
  1629. XX
  1630. XX    errors++;
  1631. XX    Fprintf (stderr, "%s: %s at or near line %d, token %d\n",
  1632. XX        filename, s, yylineno, yychar);
  1633. XX}
  1634. XX
  1635. XX
  1636. XXvoid warn (s)
  1637. XXchar    *s;
  1638. XX{
  1639. XX    /*  Generate a warning message  */
  1640. XX
  1641. XX    errors++;
  1642. XX    Fprintf (stderr, "%s: %s at or near line %d\n",
  1643. XX        filename, s, yylineno);
  1644. XX}
  1645. XX
  1646. XX
  1647. XXvoid error (s)
  1648. XXchar    *s;
  1649. XX{
  1650. XX    /*  Handle fatal errors  */
  1651. XX
  1652. XX    warn (s);
  1653. XX    exit (errors);
  1654. XX}
  1655. XX
  1656. XX
  1657. XXvoid setline (line)
  1658. XXchar    *line;
  1659. XX{
  1660. XX    /*  Handle a #line directive  */
  1661. XX
  1662. XX    register char    *cp  = line;
  1663. XX    register char    *fn  = filebuf;
  1664. XX    register int    lnum = 0;
  1665. XX
  1666. XX    if    (*cp != '#')        error ("invalid call to setline");
  1667. XX
  1668. XX    while    (*cp && !isdigit(*cp))    cp++;
  1669. XX    while    (*cp && isdigit (*cp))    lnum = lnum*10 + (*cp++ - '0');
  1670. XX    while    (*cp && *cp != '"')    cp++;
  1671. XX    if    (lnum)            yylineno = lnum;
  1672. XX
  1673. XX    if    (*cp++ == 0)        return;
  1674. XX    while    (*cp && *cp != '"')    *fn++ = *cp++;
  1675. XX    if    (fn == filename)    return;
  1676. XX
  1677. XX    *fn     = '\0';
  1678. XX    filename = filebuf;
  1679. XX}
  1680. XX
  1681. XX/*  Unterminated comment here ...
  1682. XX
  1683. XXvoid uncompiled (not_passed)
  1684. XX{
  1685. XX    int    not_here;
  1686. XX
  1687. XX    not_called ();
  1688. XX}
  1689. ====End of SHAR test.c====
  1690. if    [ "`wc -c <'test.c'`" != '    3731' ]
  1691. then    echo 'Unpack for test.c failed!'
  1692.     exit 1
  1693. else    echo 'Unpacked test.c'
  1694. fi
  1695. sed -e 's/^XX//' <<'====End of SHAR tree.c====' >tree.c
  1696. XX/*----------------------------------------------------------------------*/
  1697. XX/*                                    */
  1698. XX/*    This module handles Parse Tree building and walking        */
  1699. XX/*                                    */
  1700. XX/*----------------------------------------------------------------------*/
  1701. XX
  1702. XX
  1703. XX#include    <stdio.h>
  1704. XX#include    <ctype.h>
  1705. XX#include    "check.h"
  1706. XX#include    "y.tab.h"
  1707. XX#include    "tables.h"
  1708. XX
  1709. XX#define        CHUNK        1024    /*  No. of nodes allocated    */
  1710. XX
  1711. XXNodePtr        Tree;        /*  holds the base of the Parse Tree,    */
  1712. XX                /*  built by the Yacc-generated Parser.    */
  1713. XX
  1714. XXNodePtr        next_node,    /*  the next free node for allocation    */
  1715. XX        last_node,    /*  node not available for allocation    */
  1716. XX        node_list;    /*  head of list of blocks of nodes    */
  1717. XX
  1718. XX
  1719. XXNodePtr new_node (nt, p1, p2, p3, p4)
  1720. XXint    nt;
  1721. XXNodePtr    p1, p2, p3, p4;
  1722. XX{
  1723. XX    /*  Build a node for the Parse Tree  */
  1724. XX
  1725. XX    register NodePtr    np;
  1726. XX
  1727. XX    if    (next_node == last_node)
  1728. XX    {
  1729. XX        /*  Allocate a new batch of nodes  */
  1730. XX
  1731. XX        next_node = (NodePtr) emalloc (sizeof (Node) * CHUNK);
  1732. XX        last_node = next_node + CHUNK;
  1733. XX
  1734. XX        next_node -> f1.ptr = node_list;
  1735. XX        node_list = next_node++;
  1736. XX    }
  1737. XX
  1738. XX    np = next_node++;
  1739. XX
  1740. XX    np -> type    =  nt;
  1741. XX    np -> line    =  yylineno;
  1742. XX    np -> f1.ptr    =  p1;
  1743. XX    np -> f2.ptr    =  p2;
  1744. XX    np -> f3.ptr    =  p3;
  1745. XX    np -> f4.ptr    =  p4;
  1746. XX
  1747. XX    return np;
  1748. XX}
  1749. XX
  1750. XX
  1751. XXvoid tidy_prog ()
  1752. XX{
  1753. XX    /*  Delete the parse tree and release its memory space;        */
  1754. XX    /*  Leave just the first block of nodes for the    next program    */
  1755. XX    /*  No attempt is made to return the freed space to the system    */
  1756. XX    /*  by using (s)brk, but this could be added if desired.    */
  1757. XX    /*  My own view is that if one program builds a huge tree,    */
  1758. XX    /*  others in the same call to check may also, so let's keep    */
  1759. XX    /*  the space.  But in that case, why even return it to malloc?    */
  1760. XX    /*  Because it makes it easier to add the (s)brk, and it might    */
  1761. XX    /*  alleviate heap fragmentation if other modules are also    */
  1762. XX    /*  using malloc, and because it just feels neater to me!    */
  1763. XX
  1764. XX    register NodePtr    np;
  1765. XX    extern void        free();
  1766. XX
  1767. XX    Tree = NilNode;
  1768. XX
  1769. XX    for  (np = node_list->f1.ptr; np; np = np->f1.ptr)  free ((char *) np);
  1770. XX    node_list -> f1.ptr = NilNode;
  1771. XX    next_node = node_list + 1;
  1772. XX    last_node = node_list + CHUNK;
  1773. XX}
  1774. XX
  1775. XX
  1776. XXvoid treewalk (depth, parent, branch, np, action)
  1777. XXint    depth, parent, branch;
  1778. XXNodePtr    np;
  1779. XXvoid    (*action) ();
  1780. XX{
  1781. XX    /*  Perform required action for this node, and all nodes below it  */
  1782. XX
  1783. XX    register int    here;
  1784. XX
  1785. XX    if  (np == NilNode)  return;
  1786. XX    yylineno = np -> line;
  1787. XX
  1788. XX    action (depth, parent, branch, np);
  1789. XX
  1790. XX    switch  (here = np -> type)
  1791. XX    {
  1792. XX        /* = = =  Terminal Nodes  = = = */
  1793. XX
  1794. XX        case IDENTIFIER:
  1795. XX        case CONSTANT:
  1796. XX        case DEFAULT:
  1797. XX        case BREAK:
  1798. XX        case CONTINUE:
  1799. XX        case ';':
  1800. XX        case Type:
  1801. XX        case Error:
  1802. XX        case 0:        break;
  1803. XX
  1804. XX        /* = = =  Unary Nodes  = = = */
  1805. XX
  1806. XX        case GOTO:
  1807. XX        case RETURN:
  1808. XX        case CASE:
  1809. XX        case Indirect:
  1810. XX        case Addr:
  1811. XX        case Uplus:
  1812. XX        case Uminus:
  1813. XX        case '!':
  1814. XX        case '~':
  1815. XX        case Pre_Inc:
  1816. XX        case Post_Inc:
  1817. XX        case Size_Type:
  1818. XX        case Size_Expr:
  1819. XX                treewalk (depth+1,here,1,np->f1.ptr,action);
  1820. XX                break;
  1821. XX
  1822. XX        /* = = =  Binary Nodes  = = = */
  1823. XX
  1824. XX        case Seq:
  1825. XX        case Label:
  1826. XX        case WHILE:
  1827. XX        case DO:
  1828. XX        case SWITCH:
  1829. XX        case ',':
  1830. XX        case Or:
  1831. XX        case And:
  1832. XX        case '|':
  1833. XX        case '^':
  1834. XX        case '&':
  1835. XX        case Eq_Op:
  1836. XX        case Rel_Op:
  1837. XX        case Shift:
  1838. XX        case '+':
  1839. XX        case '-':
  1840. XX        case '*':
  1841. XX        case '/':
  1842. XX        case '%':
  1843. XX        case Cast:
  1844. XX        case Point:
  1845. XX        case '.':
  1846. XX        case '(':
  1847. XX        case '[':
  1848. XX        case Asgn_Op:
  1849. XX                treewalk (depth+1,here,1,np->f1.ptr,action);
  1850. XX                treewalk (depth+1,here,2,np->f2.ptr,action);
  1851. XX                break;
  1852. XX
  1853. XX        /* = = =  Ternary Nodes  = = = */
  1854. XX
  1855. XX        case IF:
  1856. XX        case '?':
  1857. XX                treewalk (depth+1,here,1,np->f1.ptr,action);
  1858. XX                treewalk (depth+1,here,2,np->f2.ptr,action);
  1859. XX                treewalk (depth+1,here,3,np->f3.ptr,action);
  1860. XX                break;
  1861. XX
  1862. XX        /* = = =  Quaternary Nodes  = = = */
  1863. XX
  1864. XX        case FOR:
  1865. XX                treewalk (depth+1,here,1,np->f1.ptr,action);
  1866. XX                treewalk (depth+1,here,2,np->f2.ptr,action);
  1867. XX                treewalk (depth+1,here,3,np->f3.ptr,action);
  1868. XX                treewalk (depth+1,here,4,np->f4.ptr,action);
  1869. XX                break;
  1870. XX
  1871. XX
  1872. XX        default:    Printf ("node type %d encountered\n", here);
  1873. XX                error ("treewalk: parse tree corrupt");
  1874. XX    }
  1875. XX}
  1876. XX
  1877. XX
  1878. XXvoid walk_prog (action)
  1879. XXvoid    (*action) ();
  1880. XX{
  1881. XX    /*  Start off the Parse Tree walk  */
  1882. XX
  1883. XX    treewalk (0, 0, 0, Tree, action);
  1884. XX}
  1885. XX
  1886. XX
  1887. XX/*ARGSUSED*/
  1888. XXvoid printnode (depth, parent, branch, np)
  1889. XXint    depth, parent, branch;
  1890. XXNodePtr    np;
  1891. XX{
  1892. XX    /*  Print one node of the tree  */
  1893. XX
  1894. XX    register int type = np->type;
  1895. XX
  1896. XX    while  (depth--)  Printf ("  ");
  1897. XX    Printf ("(%d) line %d:  ", branch, np->line);
  1898. XX
  1899. XX    if    (type > 256)
  1900. XX    {
  1901. XX        register NodeName *q = nodenames;
  1902. XX
  1903. XX        while  (q->val != 0 && q->val != type)  q++;
  1904. XX        Printf ("%s\n", q->str);
  1905. XX    }
  1906. XX    elif    (type == 256)
  1907. XX        Printf ("ERROR/EOF\n");
  1908. XX    elif    (isprint(type))
  1909. XX        Printf ("%c\n", type);
  1910. XX    else    Printf ("type %d/0x%02x\n", type, type);
  1911. XX}
  1912. XX
  1913. XX
  1914. XXvoid treeprint ()
  1915. XX{
  1916. XX    /*  Print the Parse Tree  */
  1917. XX
  1918. XX    treewalk (0, 0, 0, Tree, printnode);
  1919. XX}
  1920. ====End of SHAR tree.c====
  1921. if    [ "`wc -c <'tree.c'`" != '    4678' ]
  1922. then    echo 'Unpack for tree.c failed!'
  1923.     exit 1
  1924. else    echo 'Unpacked tree.c'
  1925. fi
  1926.  
  1927.