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:
parent
72769146ee
commit
f2629d53a2
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue