From d5fe5689e1afbb34122aaa6a2e449824c1dbd479 Mon Sep 17 00:00:00 2001 From: Cary R Date: Sat, 29 Sep 2007 17:48:36 -0700 Subject: [PATCH] Command files can nest, -f is an alias for -c and better error messages. This patch adds the ability to call command files from other command files. There is currently a limit of 16 total levels deep (15 stored plus the current file). -f is now an alias for -c for both the command line and command files. The parser also reports errors when they occur along with the file name and line number to aid in debugging problems. --- driver/cflexor.lex | 94 ++++++++++++++++++++++++++++++------- driver/cfparse.y | 18 ++++++- driver/cfparse_misc.h | 25 +--------- driver/iverilog.man | 12 +++-- driver/main.c | 106 +++++------------------------------------- 5 files changed, 118 insertions(+), 137 deletions(-) diff --git a/driver/cflexor.lex b/driver/cflexor.lex index 1309806f5..4da101db0 100644 --- a/driver/cflexor.lex +++ b/driver/cflexor.lex @@ -27,17 +27,21 @@ # include "globals.h" # include -/* - * Lexical location information is passed in the yylloc variable to th - * parser. The file names, strings, are kept in a list so that I can - * re-use them. The set_file_name function will return a pointer to - * the name as it exists in the list (and delete the passed string.) - * If the name is new, it will be added to the list. - */ -YYLTYPE yylloc; - static int comment_enter; - static char* trim_trailing_white(char*txt, int trim); +static char* trim_trailing_white(char*txt, int trim); + +/* + * Mostly copied from the flex manual. Do not make this arbitrary + * depth without checking for looping files. + */ +#define MAX_CMDFILE_DEPTH 15 + +typedef struct t_cmdfile { + char *cmdfile; + YY_BUFFER_STATE buffer; +} s_cmdfile; +s_cmdfile cmdfile_stack[MAX_CMDFILE_DEPTH]; +int cmdfile_stack_ptr = 0; %} @@ -51,12 +55,12 @@ static int comment_enter; /* Accept C++ style comments. */ "//".* { comment_enter = YY_START; BEGIN(LCOMMENT); } . { yymore(); } -\n { yylloc.first_line += 1; BEGIN(comment_enter); } +\n { cflloc.first_line += 1; BEGIN(comment_enter); } /* Accept C style comments. */ "/*" { comment_enter = YY_START; BEGIN(CCOMMENT); } . { yymore(); } -\n { yylloc.first_line += 1; yymore(); } +\n { cflloc.first_line += 1; yymore(); } "*/" { BEGIN(comment_enter); } /* Accept shell type comments. */ @@ -65,7 +69,7 @@ static int comment_enter; /* Skip white space. */ [ \t\f\r] { ; } /* Skip line ends, but also count the line. */ -\n { yylloc.first_line += 1; } +\n { cflloc.first_line += 1; } "+define+" { BEGIN(PLUS_ARGS); return TOK_DEFINE; } @@ -100,12 +104,16 @@ static int comment_enter; [ \t\b\f\r] { BEGIN(0); } \n { - yylloc.first_line += 1; + cflloc.first_line += 1; BEGIN(0); } /* Notice the -a flag. */ "-a" { return TOK_Da; } + /* Notice the -c or -f flag. */ +"-c" { return TOK_Dc; } +"-f" { return TOK_Dc; } + /* Notice the -v flag. */ "-v" { return TOK_Dv; } @@ -142,6 +150,18 @@ static int comment_enter; /* Fallback match. */ . { return yytext[0]; } + /* At the end of file switch back to the previous buffer. */ +<> { + if (--cmdfile_stack_ptr < 0) { + free(current_file); + yyterminate(); + } else { + yy_delete_buffer(YY_CURRENT_BUFFER); + yy_switch_to_buffer(cmdfile_stack[cmdfile_stack_ptr].buffer); + free(current_file); + current_file = cmdfile_stack[cmdfile_stack_ptr].cmdfile; + } } + %% static char* trim_trailing_white(char*text, int trim) @@ -164,10 +184,52 @@ int yywrap() return 1; } +void switch_to_command_file(const char *file) +{ + char path[4096]; + char *cp; + + if (cmdfile_stack_ptr >= MAX_CMDFILE_DEPTH) { + fprintf(stderr, "Error: command files nested too deeply (%d) " + "at %s:%d.\n", MAX_CMDFILE_DEPTH, current_file, + cflloc.first_line); + exit(1); + } + + cmdfile_stack[cmdfile_stack_ptr].buffer = YY_CURRENT_BUFFER; + cmdfile_stack[cmdfile_stack_ptr].cmdfile = current_file; + cmdfile_stack_ptr += 1; + + /* + * If this is a relative file then add the current path to the + * file name. + */ + if (file[0] != '/') { + strcpy(path, current_file); + cp = strrchr(path, '/'); + if (cp == 0) strcpy(path, file); /* A base file. */ + else { + *(cp+1) = '\0'; + strcat(path, file); + } + } else strcpy(path, file); /* An absolute path. */ + + yyin = fopen(path, "r"); + if (yyin == NULL) { + fprintf(stderr, "Error: unable to read nested command file (%s) " + "at %s:%d.\n", path, current_file, cflloc.first_line); + exit(1); + } + + current_file = strdup(path); + yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); + cflloc.first_line = 1; +} + void cfreset(FILE*fd, const char*path) { yyin = fd; yyrestart(fd); - yylloc.first_line = 1; - yylloc.text = (char*)path; + current_file = strdup(path); + cflloc.first_line = 1; } diff --git a/driver/cfparse.y b/driver/cfparse.y index f957e319a..67d85db94 100644 --- a/driver/cfparse.y +++ b/driver/cfparse.y @@ -60,7 +60,7 @@ static void translate_file_name(char*text) char*text; }; -%token TOK_Da TOK_Dv TOK_Dy +%token TOK_Da TOK_Dc TOK_Dv TOK_Dy %token TOK_DEFINE TOK_INCDIR TOK_LIBDIR TOK_LIBDIR_NOCASE TOK_LIBEXT %token TOK_INTEGER_WIDTH %token TOK_PLUSARG TOK_PLUSWORD TOK_STRING @@ -93,6 +93,16 @@ item | TOK_Da { } + /* Match a -c or -f */ + + | TOK_Dc TOK_STRING + { char*tmp = substitutions($2); + translate_file_name(tmp); + switch_to_command_file(tmp); + free($2); + free(tmp); + } + /* The -v flag is ignored, and the is processed as an ordinary source file. */ @@ -173,6 +183,12 @@ item } free($1); } + + | error + { fprintf(stderr, "Error: unable to parse line %d in " + "%s.\n", cflloc.first_line, current_file); + return 1; + } ; /* inc_args are +incdir+ arguments in order. */ diff --git a/driver/cfparse_misc.h b/driver/cfparse_misc.h index 927428e00..5ccdb8d40 100644 --- a/driver/cfparse_misc.h +++ b/driver/cfparse_misc.h @@ -36,32 +36,11 @@ struct cfltype { const char*text; }; # define YYLTYPE struct cfltype -extern YYLTYPE yylloc; int cflex(void); int cferror(const char *); int cfparse(void); +void switch_to_command_file(const char *); +char *current_file; -/* - * $Log: cfparse_misc.h,v $ - * Revision 1.6 2004/02/15 18:03:30 steve - * Cleanup of warnings. - * - * Revision 1.5 2003/09/26 21:25:58 steve - * Warnings cleanup. - * - * Revision 1.4 2002/08/12 01:35:01 steve - * conditional ident string using autoconfig. - * - * Revision 1.3 2002/01/02 02:39:34 steve - * Use my own cfltype to defend against bison 1.30. - * - * Revision 1.2 2001/11/12 18:47:32 steve - * Support +incdir in command files, and ignore other - * +args flags. Also ignore -a and -v flags. - * - * Revision 1.1 2001/11/12 01:26:36 steve - * More sophisticated command file parser. - * - */ #endif diff --git a/driver/iverilog.man b/driver/iverilog.man index aff1d5ce2..e71013bab 100644 --- a/driver/iverilog.man +++ b/driver/iverilog.man @@ -4,7 +4,7 @@ iverilog - Icarus Verilog compiler .SH SYNOPSIS .B iverilog -[-ESVv] [-Bpath] [-ccmdfile] [-Dmacro[=defn]] [-pflag=value] +[-ESVv] [-Bpath] [-ccmdfile|-fcmdfile] [-Dmacro[=defn]] [-pflag=value] [-g1|-g2|-g2x|-gspecify|-gxtypes|-gio-range-error] [-Iincludedir] [-mmodule] [-Mfile] [-Nfile] [-ooutputfilename] [-stopmodule] [-ttype] [-Tmin/typ/max] [-Wclass] [-ypath] sourcefile @@ -29,8 +29,8 @@ program. However, the \fB-B\fP switch allows the user to select a different set of programs. The path given is used to locate \fIivlpp\fP, \fIivl\fP, code generators and the VPI modules. .TP 8 -.B -c\fIfile\fP -This flag specifies an input file that contains a list of Verilog +.B -c\fIfile\fP -f\fIfile\fP +These flags specifies an input file that contains a list of Verilog source files. This is similar to the \fIcommand file\fP of other Verilog simulators, in that it is a file that contains the file names instead of taking them on the command line. See \fBCommand Files\fP below. @@ -278,6 +278,12 @@ A simple file name or file path is taken to be the name of a Verilog source file. The path starts with the first non-white-space character. Variables are substituted in file names. +.TP 8 +.B -c\ \fIcmdfile\fP -f\ \fIcmdfile\fP +A \fB-c\fP or \fB-f\fP token prefixes a command file, exactly like it +does on the command line. The cmdfile may be on the same line or the +next non-comment line. + .TP 8 .B -y\ \fIlibdir\fP A \fB-y\fP token prefixes a library directory in the command file, diff --git a/driver/main.c b/driver/main.c index ed66f5371..fea8b3c7c 100644 --- a/driver/main.c +++ b/driver/main.c @@ -39,12 +39,13 @@ const char NOTICE[] = ; const char HELP[] = -"Usage: iverilog [-ESvV] [-B base] [-c cmdfile] [-g1|-g2|-g2x]\n" +"Usage: iverilog [-ESvV] [-B base] [-c cmdfile|-f cmdfile] [-g1|-g2|-g2x]\n" " [-D macro[=defn]] [-I includedir] [-M depfile] [-m module]\n" " [-N file] [-o filename] [-p flag=value]\n" " [-s topmodule] [-t target] [-T min|typ|max]\n" " [-W class] [-y dir] [-Y suf] source_file(s)\n" -"See man page for details."; +"\n" +"See the man page for details."; #define MAXSIZE 4096 @@ -448,7 +449,7 @@ int process_generation(const char*name) else { fprintf(stderr, "Unknown/Unsupported Language generation " - "%s\n", name); + "%s\n\n", name); fprintf(stderr, "Supported generations are:\n"); fprintf(stderr, " 1 -- IEEE1364-1995 (Verilog 1)\n" " 2 -- IEEE1364-2001 (Verilog 2001)\n" @@ -586,7 +587,8 @@ int main(int argc, char **argv) base=optarg; } break; - case 'c': + case 'c': + case 'f': add_cmd_file(optarg); break; case 'D': @@ -595,8 +597,6 @@ int main(int argc, char **argv) case 'E': e_flag = 1; break; - case 'f': - fprintf(stderr, "warning: The -f flag is moved to -p\n"); case 'p': fprintf(iconfig_file, "flag:%s\n", optarg); break; @@ -678,7 +678,7 @@ int main(int argc, char **argv) pbase = base; if (version_flag || verbose_flag) { - printf("Icarus Verilog version " VERSION " ($Name: $)\n"); + printf("Icarus Verilog version " VERSION " ($Name: $)\n\n"); printf("Copyright 1998-2003 Stephen Williams\n"); puts(NOTICE); @@ -711,16 +711,16 @@ int main(int argc, char **argv) int rc; if (( fp = fopen(command_filename, "r")) == NULL ) { - fprintf(stderr, "%s: Can't open %s\n", - argv[0], command_filename); + fprintf(stderr, "%s: cannot open command file %s " + "for reading.\n", argv[0], command_filename); return 1; } cfreset(fp, command_filename); rc = cfparse(); if (rc != 0) { - fprintf(stderr, "%s: error reading command file\n", - command_filename); + fprintf(stderr, "%s: parsing failed in base command " + "file %s.\n", argv[0], command_filename); return 1; } free(command_filename); @@ -743,8 +743,7 @@ int main(int argc, char **argv) defines_file = 0; if (source_count == 0) { - fprintf(stderr, "%s: No input files.\n", argv[0]); - fprintf(stderr, "%s\n", HELP); + fprintf(stderr, "%s: no source files.\n\n%s\n", argv[0], HELP); return 1; } @@ -809,84 +808,3 @@ int main(int argc, char **argv) return 0; } -/* - * $Log: main.c,v $ - * Revision 1.76 2007/06/05 01:56:12 steve - * Bring in .SFT file automatically if -m used. - * - * Revision 1.75 2007/04/19 02:52:53 steve - * Add support for -v flag in command file. - * - * Revision 1.74 2007/04/18 03:23:38 steve - * Add support for multiple command files. (Cary R.) - * - * Revision 1.73 2007/03/07 04:24:59 steve - * Make integer width controllable. - * - * Revision 1.72 2006/10/02 18:15:47 steve - * Fix handling of dep path in new argument passing method. - * - * Revision 1.71 2006/09/28 04:35:18 steve - * Support selective control of specify and xtypes features. - * - * Revision 1.70 2006/09/20 22:30:52 steve - * Do not pass -D__ICARUS__ to ivlpp. - * - * Revision 1.69 2006/07/26 00:11:40 steve - * Pass depfiles through temp defines file. - * - * Revision 1.68 2006/07/26 00:02:48 steve - * Pass defines and includes through temp file. - * - * Revision 1.67 2005/07/14 23:38:44 steve - * Display as version 0.9.devel - * - * Revision 1.66 2005/06/28 04:25:55 steve - * Remove reference to SystemVerilog. - * - * Revision 1.65 2004/06/17 14:47:22 steve - * Add a .sft file for the system functions. - * - * Revision 1.64 2004/03/10 04:51:25 steve - * Add support for system function table files. - * - * Revision 1.63 2004/02/15 18:03:30 steve - * Cleanup of warnings. - * - * Revision 1.62 2003/12/12 04:36:48 steve - * Fix make check to support -tconf configuration method. - * - * Revision 1.61 2003/11/18 06:31:46 steve - * Remove the iverilog.conf file. - * - * Revision 1.60 2003/11/13 05:55:33 steve - * Move the DLL= flag to target config files. - * - * Revision 1.59 2003/11/13 04:09:49 steve - * Pass flags through the temporary config file. - * - * Revision 1.58 2003/11/01 04:21:57 steve - * Add support for a target static config file. - * - * Revision 1.57 2003/10/26 22:43:42 steve - * Improve -V messages, - * - * Revision 1.56 2003/09/26 21:25:58 steve - * Warnings cleanup. - * - * Revision 1.55 2003/09/23 05:57:15 steve - * Pass -m flag from driver via iconfig file. - * - * Revision 1.54 2003/09/22 01:12:09 steve - * Pass more ivl arguments through the iconfig file. - * - * Revision 1.53 2003/08/26 16:26:02 steve - * ifdef idents correctly. - * - * Revision 1.52 2003/02/22 04:55:36 steve - * portbind adds p, not i, flag. - * - * Revision 1.51 2003/02/22 04:12:49 steve - * Add the portbind warning. - */ -