/* begend - a program for viewing Verilog begin/end case/endcase By Jeff Winston http://www.kwcpa.com/tools Rev. 1.0, 2/5/03 Copyright (C) 2003 BEGEND.C parses a verilog file and generates a report file that shows counts and nesting of begin/end and case/endcase keywords. This is useful for quickly finding extra or missing keywords, or checking for nesting problems. Type begend -h for more information --------------------------------------------------------------------- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. or check out http://www.gnu.org/copyleft/gpl.html --------------------------------------------------------------------- To compile: gcc begend.c -o begend */ # include # include char instr[255], /* temps */ tokens[32][32], dispstr[4], /* for output formatting */ infile[32], /* filenames */ outfile[32]; long i, /* temp vars */ ntk, line_begin, /* counters */ line_end, total_begend, line_cnt, total_cases, line_case_cnt, line_endcase_cnt, novalid; /* for comment parsing */ FILE *infile_ptr,*outfile_ptr; int get_tokens(char *str); main(argc,argv) int argc; /* Parse input file from command line */ char *argv[]; { printf("\nBEGEND Rev 1.0 by J. Winston\n"); if (argc != 2) /* print help message if too few input parameters */ { printf("Error: Incorrect number of parameters on command line\n"); printf("Type begend -h for help\n"); exit(0); } else { ++argv; strcpy(instr,*argv); /* help information */ if (strcmp(instr,"-h")==0) { printf("\nUse: begend \n"); printf("The input filename should be the name of a .v file, without the .v extension\n"); printf("The output report file will be the sane name of the input file,\n"); printf("with .bnd as the extension\n\n"); printf("BEGEND.C parses a verilog file and generates a report file that shows counts\n"); printf("and nesting of begin/end and case/endcase keywords. This is useful for quickly\n"); printf("finding extra or missing keywords, or checking for nesting problems.\n\n"); exit(0); } } /* gen filenames, open files */ strcpy(infile,*argv); strcpy(outfile,infile); strcat(infile,".v"); strcat(outfile,".bnd"); if ( (infile_ptr=fopen(infile, "r")) ==NULL ) { printf("Error: Error opening input file /%s/\n\n",infile); printf("Enter only the input filename without extension. Exiting...\n"); exit(1); } if ((outfile_ptr=fopen(outfile, "w")) ==NULL) { printf("Error: Error opening output file /%s/\n\n",outfile); printf("Enter only the input filename without extension. Exiting...\n"); exit(2); } /* print banner */ fprintf(outfile_ptr,"Output of BEGEND.C, by Jeff Winston. Input file: %s\n\n",infile); fprintf(outfile_ptr," Nests\n"); fprintf(outfile_ptr,"Line B/E c/e Type/Source\n"); total_begend=0; line_cnt=0; total_cases=0; novalid=0; /* initialize global counters */ while (fgets(instr,200,infile_ptr) != NULL) /* Keep getting lines until no more data */ { line_begin=0; line_end=0; line_case_cnt=0; line_endcase_cnt=0; /* initialize local counters */ strcpy(dispstr,""); ntk = get_tokens(instr); for (i = 0; i < ntk; i++) /* count stuff */ { if (strcmp(tokens[i],"begin") ==0) { line_begin++; strcat(dispstr,"B");} if (strcmp(tokens[i],"end") ==0) { line_end++; strcat(dispstr,"E");} if (strcmp(tokens[i],"case") ==0) {line_case_cnt++; strcat(dispstr,"c");} if (strcmp(tokens[i],"endcase")==0) {line_endcase_cnt++; strcat(dispstr,"e");} } /* calculate global counts from local ones */ total_begend = total_begend+line_begin-line_end; total_cases = total_cases +line_case_cnt - line_endcase_cnt; line_cnt++; fprintf(outfile_ptr,"%4d|%3d %2d%4s|%s",line_cnt,total_begend,total_cases,dispstr,instr); /* print line with counts */ } /* print final conclusions */ if ((total_cases == 0) && (total_begend == 0) ) printf("Begend: %4d lines. Looks ok. Output written to: %s\n",line_cnt,outfile); else printf("Begend: %4d lines. Final Balances: %3d/%3d, Output written to: %s\n",line_cnt,total_begend,total_cases,outfile); } int get_tokens(char *str) /* parser - get tokens on line. Put in global tokens[][], return count */ { int len, loc, cnt, sp, start; len = strlen(str); sp=1; cnt=0; if (novalid != 9) novalid = 0; for (loc=0; loc <= len; loc++) { if ( (loc < (len-1)) && (str[loc] == '/') && (str[loc+1] == '*') ) novalid = 9; else if ( (loc < (len-1)) && (str[loc] == '/') && (str[loc+1] == '/') ) novalid = 1; else if ( (loc < (len-1)) && (str[loc] == '*') && (str[loc+1] == '/') ) novalid = 0; if ( (loc < len) && (str[loc] != ' ') && (str[loc] != ';') && (str[loc] != ' ') && (str[loc] != '\n') && (str[loc] != ',') && (str[loc] != '(') && (str[loc] != '{') && (str[loc] != '}') && (str[loc] != ')') && (novalid == 0) ) /* if valid char */ { if (sp==1) /* if state = waiting */ { cnt++; /* incr token count, flip state to running, assign start */ sp=0; start=loc; } } else /* if not valid character */ { if (sp==0) /* if state = running, flip state to waiting, append good characters to string */ { sp=1; strncpy(tokens[cnt-1],&str[start],loc-start); strncpy(&tokens[cnt-1][loc-start],"\0",1); } } } return(cnt); }