Add file/line information to entities and ports

Include the compiler infrastructure to vhdlpp for collecting the
file and line information and attaching it to entities and ports.
Make the parser store the file name during parse.

Create a libmisc library where I can put source files that are
used by multiple programs within the source tree.
This commit is contained in:
Stephen Williams 2011-01-06 09:27:30 -08:00
parent d72f7ea249
commit ab8f623cea
14 changed files with 42 additions and 338 deletions

View File

@ -80,9 +80,9 @@ PS2PDF = @PS2PDF@
GIT = @GIT@
ifeq (@srcdir@,.)
INCLUDE_PATH = -I.
INCLUDE_PATH = -I. -Ilibmisc
else
INCLUDE_PATH = -I. -I$(srcdir)
INCLUDE_PATH = -I. -Ilibmisc -I$(srcdir) -I$(srcdir)/libmisc
endif
CPPFLAGS = @DEFS@ $(INCLUDE_PATH) @CPPFLAGS@
@ -91,6 +91,9 @@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@
PICFLAGS = @PICFLAG@
LDFLAGS = @rdynamic@ @LDFLAGS@
# Source files in the libmisc directory
M = LineInfo.o StringHeap.o
TT = t-dll.o t-dll-api.o t-dll-expr.o t-dll-proc.o t-dll-analog.o
FF = cprop.o nodangle.o synth.o synth2.o syn-rules.o
@ -104,9 +107,9 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
net_udp.o pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \
pform_disciplines.o pform_dump.o pform_types.o set_width.o \
symbol_search.o sync.o sys_funcs.o verinum.o verireal.o target.o \
Attrib.o HName.o LineInfo.o Module.o PDelays.o PEvent.o PExpr.o PGate.o \
Attrib.o HName.o Module.o PDelays.o PEvent.o PExpr.o PGate.o \
PGenerate.o PScope.o PSpec.o PTask.o PUdp.o PFunction.o PWire.o \
Statement.o AStatement.o StringHeap.o $(FF) $(TT)
Statement.o AStatement.o $M $(FF) $(TT)
all: dep config.h _pli_types.h version_tag.h ivl@EXEEXT@ version.exe iverilog-vpi.man
$(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true
@ -197,7 +200,7 @@ ifeq (@WIN32@,yes)
# The first step makes an ivl.exe that dlltool can use to make an
# export and import library, and the last link makes a, ivl.exe
# that really exports the things that the import library imports.
ivl@EXEEXT@: $O $(srcdir)/ivl.def
ivl@EXEEXT@: $O $(srcdir)/ivl.def
$(CXX) -o ivl@EXEEXT@ $O $(dllib) @EXTRALIBS@
dlltool --dllname ivl@EXEEXT@ --def $(srcdir)/ivl.def \
--output-lib libivl.a --output-exp ivl.exp
@ -229,6 +232,10 @@ version.exe: $(srcdir)/version.c $(srcdir)/version_base.h version_tag.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o
mv $*.d dep/$*.d
%.o: $(srcdir)/libmisc/%.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o
mv $*.d dep/$*.d
# Here are some explicit dependencies needed to get things going.
main.o: main.cc version_tag.h

View File

@ -1,202 +0,0 @@
/*
* Copyright (c) 2002-2010 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form 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
*/
# include "StringHeap.h"
# include <cstdlib>
# include <cstring>
# include <cassert>
# include "ivl_alloc.h"
#ifdef CHECK_WITH_VALGRIND
static char **string_pool = NULL;
static unsigned string_pool_count = 0;
#endif
StringHeap::StringHeap()
{
cell_base_ = 0;
cell_ptr_ = HEAPCELL;
cell_count_ = 0;
}
StringHeap::~StringHeap()
{
// This is a planned memory leak. The string heap is intended
// to hold permanently-allocated strings.
}
const char* StringHeap::add(const char*text)
{
unsigned len = strlen(text);
assert((len+1) <= HEAPCELL);
unsigned rem = HEAPCELL - cell_ptr_;
if (rem < (len+1)) {
cell_base_ = (char*)malloc(HEAPCELL);
#ifdef CHECK_WITH_VALGRIND
string_pool_count += 1;
string_pool = (char **) realloc(string_pool,
string_pool_count*sizeof(char **));
string_pool[string_pool_count-1] = cell_base_;
#endif
cell_ptr_ = 0;
cell_count_ += 1;
assert(cell_base_ != 0);
}
char*res = cell_base_ + cell_ptr_;
memcpy(res, text, len);
cell_ptr_ += len;
cell_base_[cell_ptr_++] = 0;
assert(cell_ptr_ <= HEAPCELL);
return res;
}
perm_string StringHeap::make(const char*text)
{
return perm_string(add(text));
}
StringHeapLex::StringHeapLex()
{
hit_count_ = 0;
add_count_ = 0;
for (unsigned idx = 0 ; idx < HASH_SIZE ; idx += 1)
hash_table_[idx] = 0;
}
StringHeapLex::~StringHeapLex()
{
}
void StringHeapLex::cleanup()
{
#ifdef CHECK_WITH_VALGRIND
for (unsigned idx = 0 ; idx < string_pool_count ; idx += 1) {
free(string_pool[idx]);
}
free(string_pool);
string_pool = NULL;
string_pool_count = 0;
for (unsigned idx = 0 ; idx < HASH_SIZE ; idx += 1) {
hash_table_[idx] = 0;
}
#endif
}
unsigned StringHeapLex::add_hit_count() const
{
return hit_count_;
}
unsigned StringHeapLex::add_count() const
{
return add_count_;
}
static unsigned hash_string(const char*text)
{
unsigned h = 0;
while (*text) {
h = (h << 4) ^ (h >> 28) ^ *text;
text += 1;
}
return h;
}
const char* StringHeapLex::add(const char*text)
{
unsigned hash_value = hash_string(text) % HASH_SIZE;
/* If we easily find the string in the hash table, then return
that and be done. */
if (hash_table_[hash_value]
&& (strcmp(hash_table_[hash_value], text) == 0)) {
hit_count_ += 1;
return hash_table_[hash_value];
}
/* The existing hash entry is not a match. Replace it with the
newly allocated value, and return the new pointer as the
result to the add. */
const char*res = StringHeap::add(text);
hash_table_[hash_value] = res;
add_count_ += 1;
return res;
}
perm_string StringHeapLex::make(const char*text)
{
return perm_string(add(text));
}
perm_string StringHeapLex::make(const string&text)
{
return perm_string(add(text.c_str()));
}
bool operator == (perm_string a, const char*b)
{
if (a.str() == b)
return true;
if (! (a.str() && b))
return false;
if (strcmp(a.str(), b) == 0)
return true;
return false;
}
bool operator == (perm_string a, perm_string b)
{
return a == b.str();
}
bool operator != (perm_string a, const char*b)
{
return ! (a == b);
}
bool operator != (perm_string a, perm_string b)
{
return ! (a == b);
}
bool operator < (perm_string a, perm_string b)
{
if (b.str() && !a.str())
return true;
if (b.str() == a.str())
return false;
if (strcmp(a.str(), b.str()) < 0)
return true;
return false;
}

View File

@ -17,11 +17,11 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "config.h"
# include "LineInfo.h"
# include <sstream>
using namespace std;
LineInfo::LineInfo()
: lineno_(0)
{

View File

@ -19,7 +19,6 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "config.h"
# include <string>
using namespace std;

View File

@ -40,9 +40,9 @@ LEX = @LEX@
YACC = @YACC@
ifeq (.,.)
INCLUDE_PATH = -I. -I..
INCLUDE_PATH = -I. -I.. -I../libmisc
else
INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/..
INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/../libmisc
endif
CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@
@ -51,8 +51,10 @@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@ @EXTRALIBS@
M = StringHeap.o LineInfo.o
O = main.o compiler.o entity.o entity_elaborate.o \
lexor.o lexor_keyword.o parse.o StringHeap.o
lexor.o lexor_keyword.o parse.o $M
all: dep vhdlpp@EXEEXT@
@ -73,6 +75,9 @@ dep:
vhdlpp@EXEEXT@: $O
$(CXX) -o vhdlpp@EXEEXT@ $(LDFLAGS) $O $(LIBS)
%.o: $(srcdir)/../libmisc/%.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o
%.o: %.cc vhdlpp_config.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o
mv $*.d dep/$*.d

View File

@ -1,121 +0,0 @@
#ifndef __StringHeap_H
#define __StringHeap_H
/*
* Copyright (c) 2002-2009 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form 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
*/
# include "config.h"
# include <string>
using namespace std;
class perm_string {
public:
perm_string() : text_(0) { }
perm_string(const perm_string&that) : text_(that.text_) { }
~perm_string() { }
perm_string& operator = (const perm_string&that)
{ text_ = that.text_; return *this; }
const char*str() const { return text_; }
operator const char* () const { return str(); }
// This is an escape for making perm_string objects out of
// literals. For example, perm_string::literal("Label"); Please
// do *not* cheat and pass arbitrary const char* items here.
static perm_string literal(const char*t) { return perm_string(t); }
private:
friend class StringHeap;
friend class StringHeapLex;
perm_string(const char*t) : text_(t) { };
private:
const char*text_;
};
extern bool operator == (perm_string a, perm_string b);
extern bool operator == (perm_string a, const char* b);
extern bool operator != (perm_string a, perm_string b);
extern bool operator != (perm_string a, const char* b);
extern bool operator > (perm_string a, perm_string b);
extern bool operator < (perm_string a, perm_string b);
extern bool operator >= (perm_string a, perm_string b);
extern bool operator <= (perm_string a, perm_string b);
/*
* The string heap is a way to permanently allocate strings
* efficiently. They only take up the space of the string characters
* and the terminating nul, there is no malloc overhead.
*/
class StringHeap {
public:
StringHeap();
~StringHeap();
const char*add(const char*);
perm_string make(const char*);
private:
enum { HEAPCELL = 0x10000 };
char*cell_base_;
unsigned cell_ptr_;
unsigned cell_count_;
private: // not implemented
StringHeap(const StringHeap&);
StringHeap& operator= (const StringHeap&);
};
/*
* A lexical string heap is a string heap that makes an effort to
* return the same pointer for identical strings. This saves further
* space by not allocating duplicate strings, so in a system with lots
* of identifiers, this can theoretically save more space.
*/
class StringHeapLex : private StringHeap {
public:
StringHeapLex();
~StringHeapLex();
const char*add(const char*);
perm_string make(const char*);
perm_string make(const string&);
unsigned add_count() const;
unsigned add_hit_count() const;
void cleanup();
private:
enum { HASH_SIZE = 4096 };
const char*hash_table_[HASH_SIZE];
unsigned add_count_;
unsigned hit_count_;
private: // not implemented
StringHeapLex(const StringHeapLex&);
StringHeapLex& operator= (const StringHeapLex&);
};
#endif

View File

@ -19,3 +19,5 @@
# include "compiler.h"
StringHeapLex lex_strings;
StringHeapLex filename_strings;

View File

@ -28,4 +28,6 @@ extern bool verbose_flag;
extern StringHeapLex lex_strings;
extern StringHeapLex filename_strings;
#endif

View File

@ -47,7 +47,7 @@ static ostream& operator << (ostream&out, port_mode_t that)
static void dump_design_entity(ostream&out, Entity*obj)
{
out << "entity " << obj->name << endl;
out << "entity " << obj->name << " file=" << obj->get_fileline() << endl;
if (obj->ports.size() == 0) {
out << " No ports" << endl;
} else {
@ -57,7 +57,8 @@ static void dump_design_entity(ostream&out, Entity*obj)
InterfacePort*item = *cur;
out << setw(6) << "" << item->name
<< " : " << item->mode
<< ", type=" << item->type_name << endl;
<< ", type=" << item->type_name
<< ", file=" << item->get_fileline() << endl;
}
}
}

View File

@ -22,10 +22,11 @@
# include <map>
# include <vector>
# include "StringHeap.h"
# include "LineInfo.h"
typedef enum { PORT_NONE=0, PORT_IN, PORT_OUT } port_mode_t;
class InterfacePort {
class InterfacePort : public LineInfo {
public:
// Port direction from the source code.
port_mode_t mode;
@ -35,7 +36,7 @@ class InterfacePort {
perm_string type_name;
};
class Entity {
class Entity : public LineInfo {
public:
int elaborate();

View File

@ -98,6 +98,7 @@ extern void yyparse_set_filepath(const char*path);
void reset_lexor(FILE*fd, const char*path)
{
yylloc.text = path;
yylloc.first_line = 1;
yyrestart(fd);

View File

@ -25,6 +25,13 @@
# include <cstdarg>
# include <list>
inline void FILE_NAME(LineInfo*tmp, const struct yyltype&where)
{
tmp->set_lineno(where.first_line);
tmp->set_file(filename_strings.make(where.text));
}
static void yyerror(const char*msg);
static void errormsg(const YYLTYPE&loc, const char*msg, ...);
@ -135,6 +142,7 @@ design_units
entity_declaration
: K_entity IDENTIFIER K_is entity_header K_end K_entity ';'
{ Entity*tmp = new Entity;
FILE_NAME(tmp, @1);
// Store the name
tmp->name = lex_strings.make($2);
delete[]$2;
@ -170,6 +178,7 @@ factor : primary ;
interface_element
: IDENTIFIER ':' mode IDENTIFIER
{ InterfacePort*tmp = new InterfacePort;
FILE_NAME(tmp, @1);
tmp->mode = $3;
tmp->name = lex_strings.make($1);
tmp->type_name = lex_strings.make($4);