Add VHDL support for named libraries

Named libraries are similar to the work library, but they are not
written to implicitly, or imported implicitly. They are only brought
in by a "library" clause, the the packages within the library are
brought in by a "use" clause.
This commit is contained in:
Stephen Williams 2011-07-30 15:04:07 -07:00
parent 72769146ee
commit f2629d53a2
7 changed files with 145 additions and 25 deletions

View File

@ -2,15 +2,30 @@
vhdlpp COMMAND LINE FLAGS:
-D <token>
Debug flags. The token can be
Debug flags. The token can be:
* yydebug | no-yydebug
* entities=<path>
-L <path>
Library path. Add the directory name to the front of the library
search path. The library search path is initially empty.
-V
Display version on stdout
-v
Verbose: Display version on stderr, and enable verbose messages to
stderr.
-w <path>
Work path. This is the directory where the working directory is.
LIBRARY FORMAT:
The vhdlpp program stores libraries as directory that contain
packages. The name of the directory (in lower case) is the name of the
library as used on the "import" statement. Within that library, there
are packages in files named <foo>.pkg.

View File

@ -31,5 +31,6 @@ extern StringHeapLex lex_strings;
extern StringHeapLex filename_strings;
extern void library_set_work_path(const char*work_path);
extern void library_add_directory(const char*directory);
#endif

View File

@ -21,34 +21,81 @@
# include "compiler.h"
# include "package.h"
# include <fstream>
# include <list>
# include <map>
# include <string>
# include <sys/stat.h>
# include <cassert>
using namespace std;
/*
* The library_work_path is the path to the work directory.
*/
static const char*library_work_path = 0;
static void store_package_in_work(const Package*pack);
/*
* The library_search_path is a list of directory names to search to
* find a named library. The library name is the name given to the
* "import" statement.
*/
static list<string> library_search_path;
/*
* The "import" statement causes me to build a map of a library name
* to a library directory.
*/
static map<perm_string,string> library_dir;
/*
* The "libraries" table maps library name to a set of packages. This
* map is filled in by "use" statements.
*/
struct library_contents {
map<perm_string,Package*> packages;
};
static map<perm_string,struct library_contents> libraries;
void library_add_directory(const char*directory)
{
// Make sure the directory path really is a directory. Ignore
// it if it is not.
struct stat stat_buf;
int rc = stat(directory, &stat_buf);
if (rc < 0 || !S_ISDIR(stat_buf.st_mode)) {
return;
}
library_search_path .push_front(directory);
}
static void store_package_in_work(const Package*pack);
static string make_work_package_path(const char*name)
{
return string(library_work_path).append("/").append(name).append(".pkg");
}
static string make_library_package_path(perm_string lib_name, perm_string name)
{
string path = library_dir[lib_name];
if (path == "")
return "";
struct library_contents {
map<perm_string,Package*> packages;
};
path = path.append("/").append(name).append(".pkg");
return path;
}
static void import_ieee(void);
static void import_ieee_use(ActiveScope*res, perm_string package, perm_string name);
static map<perm_string,struct library_contents> libraries;
static void dump_library_package(ostream&file, perm_string lname, perm_string pname, Package*pack)
{
file << "package " << lname << "." << pname << endl;
pack->dump_scope(file);
if (pack) {
pack->dump_scope(file);
} else {
file << " <missing>" << endl;
}
file << "end package " << lname << "." << pname << endl;
}
@ -72,22 +119,45 @@ void dump_libraries(ostream&file)
* This function saves a package into the named library. Create the
* library if necessary.
*/
void library_save_package(const char*libname, Package*pack, bool parse_work)
void library_save_package(perm_string parse_library_name, Package*pack)
{
if (libname == 0)
libname = "work";
perm_string use_libname = lex_strings.make(libname);
perm_string use_libname = parse_library_name.str()
? parse_library_name
: perm_string::literal("work");
struct library_contents&lib = libraries[use_libname];
lib.packages[pack->name()] = pack;
// If this is a work package, and we are NOT parsing the work
// library right now, then store it in the work library.
if (use_libname == "work" && !parse_work)
if (parse_library_name.str() == 0)
store_package_in_work(pack);
}
static void import_library_name(const YYLTYPE&loc, perm_string name)
{
if (library_dir[name] != string())
return;
for (list<string>::const_iterator cur = library_search_path.begin()
; cur != library_search_path.end() ; ++cur) {
string curdir = *cur;
string try_path = curdir.append("/").append(name);
struct stat stat_buf;
int rc = stat(try_path.c_str(), &stat_buf);
if (rc < 0)
continue;
if (!S_ISDIR(stat_buf.st_mode))
continue;
library_dir[name] = try_path;
return;
}
errormsg(loc, "library import cannot find library %s\n", name.str());
}
void library_import(const YYLTYPE&loc, const std::list<perm_string>*names)
{
for (std::list<perm_string>::const_iterator cur = names->begin()
@ -96,8 +166,12 @@ void library_import(const YYLTYPE&loc, const std::list<perm_string>*names)
// The ieee library is special and handled by an
// internal function.
import_ieee();
} else if (*cur == "work") {
// The work library is always implicitly imported.
} else {
sorrymsg(loc, "library import (%s) not implemented.\n", cur->str());
// Otherwise, do a generic library import
import_library_name(loc, *cur);
}
}
}
@ -126,9 +200,23 @@ void library_use(const YYLTYPE&loc, ActiveScope*res,
// parsed, then see if it exists unparsed.
if (use_library=="work" && pack == 0) {
string path = make_work_package_path(use_package.str());
parse_source_file(path.c_str(), true);
parse_source_file(path.c_str(), use_library);
pack = lib.packages[use_package];
} else if (use_library != "ieee" && pack == 0) {
string path = make_library_package_path(use_library, use_package);
if (path == "") {
errormsg(loc, "Unable to find library %s\n", use_library.str());
return;
}
int rc = parse_source_file(path.c_str(), use_library);
if (rc < 0)
errormsg(loc, "Unable to open library file %s\n", path.c_str());
else if (rc > 0)
errormsg(loc, "Errors in library file %s\n", path.c_str());
else
pack = lib.packages[use_package];
}
// If the package is still not found, then error.
if (pack == 0) {
errormsg(loc, "No package %s in library %s\n",

View File

@ -111,12 +111,16 @@ int main(int argc, char*argv[])
int rc;
const char*work_path = "ivl_vhdl_work";
while ( (opt=getopt(argc, argv, "D:vVw:")) != EOF) switch (opt) {
while ( (opt=getopt(argc, argv, "D:L:vVw:")) != EOF) switch (opt) {
case 'D':
process_debug_token(optarg);
break;
case 'L':
library_add_directory(optarg);
break;
case 'v':
fprintf(stderr, "Icarus Verilog VHDL Parse version "
VERSION " (" VERSION_TAG ")\n\n");
@ -159,7 +163,7 @@ int main(int argc, char*argv[])
for (int idx = optind ; idx < argc ; idx += 1) {
parse_errors = 0;
parse_sorrys = 0;
rc = parse_source_file(argv[idx], false);
rc = parse_source_file(argv[idx], perm_string());
if (rc < 0)
return 1;

View File

@ -3,7 +3,7 @@
%lex-param { yyscan_t yyscanner }
%parse-param {yyscan_t yyscanner }
%parse-param {const char*file_path}
%parse-param {bool parsing_work }
%parse-param {perm_string parse_library_name}
%{
/*
* Copyright (c) 2011 Stephen Williams (steve@icarus.com)
@ -1140,8 +1140,10 @@ package_declaration
delete[]$1;
if ($6) delete[]$6;
pop_scope();
/* Put this package into the work library. */
library_save_package(0, tmp, parsing_work);
/* Put this package into the work library, or the currently
parsed library. Note that parse_library_name is an
argument to the parser. */
library_save_package(parse_library_name, tmp);
}
| package_declaration_start K_is error K_end K_package_opt identifier_opt ';'
{ errormsg(@3, "Syntax error in package clause.\n");
@ -1718,7 +1720,7 @@ void sorrymsg(const YYLTYPE&loc, const char*fmt, ...)
extern yyscan_t prepare_lexor(FILE*fd);
extern void destroy_lexor(yyscan_t scanner);
int parse_source_file(const char*file_path, bool work_library_flag)
int parse_source_file(const char*file_path, perm_string parse_library_name)
{
FILE*fd = fopen(file_path, "r");
if (fd == 0) {
@ -1727,7 +1729,7 @@ int parse_source_file(const char*file_path, bool work_library_flag)
}
yyscan_t scanner = prepare_lexor(fd);
int rc = yyparse(scanner, file_path, work_library_flag);
int rc = yyparse(scanner, file_path, parse_library_name);
fclose(fd);
destroy_lexor(scanner);

View File

@ -39,8 +39,11 @@ struct yyltype {
/*
* This calls the bison-generated parser with the given file path as
* the input stream. If the file cannot be opened, this returns -1.
* The "library_name" argument is the name of the library that is
* being parsed. If this is a regular source file, then this name is
* nil. Note that the "work" library is handled specially.
*/
extern int parse_source_file(const char*file_path, bool parse_work_library);
extern int parse_source_file(const char*file_path, perm_string library_name);
/*
* Use this function during parse to generate error messages. The "loc"

View File

@ -47,7 +47,14 @@ extern const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_n
*/
extern const VType* parse_type_by_name(perm_string name);
extern void library_save_package(const char*libname, Package*pack, bool parse_work);
/*
* The parser calls the library_save_package function when it parses a
* package. The library_parse_name is the name of the library that is
* currently being processed (by a recursive call to the parser to
* load a package from a library) or a nil name to indicate that this
* is from the live parser.
*/
extern void library_save_package(perm_string library_parse_name, Package*pack);
extern void library_import(const YYLTYPE&loc, const std::list<perm_string>*names);