Parse create entities with ports

Create entity objects from entity declarations in the source,
and populate them with ports.
This commit is contained in:
Stephen Williams 2011-01-03 08:30:09 +02:00
parent 1f6bf09984
commit 02820c9e34
13 changed files with 586 additions and 7 deletions

View File

@ -51,7 +51,7 @@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@ @EXTRALIBS@
O = main.o lexor.o lexor_keyword.o parse.o
O = main.o compiler.o entity.o lexor.o lexor_keyword.o parse.o StringHeap.o
all: dep vhdlpp@EXEEXT@

201
vhdlpp/StringHeap.cc Normal file
View File

@ -0,0 +1,201 @@
/*
* 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>
#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;
}

121
vhdlpp/StringHeap.h Normal file
View File

@ -0,0 +1,121 @@
#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

21
vhdlpp/compiler.cc Normal file
View File

@ -0,0 +1,21 @@
/*
* Copyright (c) 2011 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 "compiler.h"
StringHeapLex lex_strings;

View File

@ -1,7 +1,7 @@
#ifndef __compiler_H
#define __compiler_H
/*
* Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2011 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
@ -19,6 +19,10 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "StringHeap.h"
const int GN_KEYWORD_2008 = 0x0001;
extern StringHeapLex lex_strings;
#endif

71
vhdlpp/entity.cc Normal file
View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2011 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 "entity.h"
# include <fstream>
# include <iomanip>
using namespace std;
std::map<perm_string,Entity*> design_entities;
static ostream& operator << (ostream&out, port_mode_t that)
{
switch (that) {
case PORT_NONE:
out << "NO-PORT";
break;
case PORT_IN:
out << "IN";
break;
case PORT_OUT:
out << "OUT";
break;
default:
out << "PORT-????";
break;
}
return out;
}
static void dump_design_entity(ostream&out, Entity*obj)
{
out << "entity " << obj->name << endl;
if (obj->ports.size() == 0) {
out << " No ports" << endl;
} else {
out << " PORTS:" << endl;
for (vector<InterfacePort*>::iterator cur = obj->ports.begin()
; cur != obj->ports.end() ; ++cur) {
InterfacePort*item = *cur;
out << setw(6) << "" << item->name
<< " : " << item->mode << endl;
}
}
}
void dump_design_entities(const char*path)
{
ofstream file (path);
for (map<perm_string,Entity*>::iterator cur = design_entities.begin()
; cur != design_entities.end() ; ++cur) {
dump_design_entity(file, cur->second);
}
}

54
vhdlpp/entity.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef __entity_H
#define __entity_H
/*
* Copyright (c) 2011 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 <map>
# include <vector>
# include "StringHeap.h"
typedef enum { PORT_NONE=0, PORT_IN, PORT_OUT } port_mode_t;
class InterfacePort {
public:
port_mode_t mode;
perm_string name;
};
class Entity {
public:
perm_string name;
std::vector<InterfacePort*> ports;
};
/*
* As the parser parses entities, it puts them into this map. It uses
* a map because sometimes it needs to look back at an entity by name.
*/
extern std::map<perm_string,Entity*> design_entities;
/*
* Use this function to dump a description of the design entities to a
* file. This is for debug, not for any useful purpose.
*/
extern void dump_design_entities(const char*path);
#endif

View File

@ -25,7 +25,7 @@
# include "parse_api.h"
# include "lexor_keyword.h"
# include "parse.h"
# include "parse_wrap.h"
extern int lexor_keyword_code (const char*str, unsigned len);
@ -38,6 +38,11 @@ extern int lexor_keyword_code (const char*str, unsigned len);
*/
extern YYLTYPE yylloc;
static char* strdupnew(char const *str)
{
return str ? strcpy(new char [strlen(str)+1], str) : 0;
}
static int comment_enter;
%}
@ -70,6 +75,13 @@ W [ \t\b\f\r]+
[a-zA-Z_][a-zA-Z0-9_]* {
int rc = lexor_keyword_code(yytext, yyleng);
switch (rc) {
case IDENTIFIER:
yylval.text = strdupnew(yytext);
break;
default:
break;
}
return rc;
}

View File

@ -10,7 +10,8 @@
#include "vhdlpp_config.h"
#include <cstring>
#include "compiler.h"
#include "parse.h"
#include "parse_api.h"
#include "parse_wrap.h"
%}
struct lexor_keyword { const char*name; int mask; int tokenType; };

View File

@ -38,6 +38,7 @@ const char NOTICE[] =
" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
;
# include "compiler.h"
# include "parse_api.h"
# include <cstdio>
# include <cstdlib>
@ -46,7 +47,10 @@ const char NOTICE[] =
# include <getopt.h>
#endif
bool verbose_flag = false;
// Where to dump design entities
const char*dump_design_entities_path = 0;
static void process_debug_token(const char*word)
{
@ -54,6 +58,8 @@ static void process_debug_token(const char*word)
yydebug = 1;
} else if (strcmp(word, "no-yydebug") == 0) {
yydebug = 0;
} else if (strncmp(word, "entities=", 9) == 0) {
dump_design_entities_path = strdup(word+9);
}
}
@ -106,5 +112,9 @@ int main(int argc, char*argv[])
fclose(fd);
}
if (dump_design_entities_path)
dump_design_entities(dump_design_entities_path);
lex_strings.cleanup();
return 0;
}

View File

@ -20,8 +20,10 @@
*/
# include "vhdlpp_config.h"
# include "compiler.h"
# include "parse_api.h"
# include <cstdarg>
# include <list>
static void yyerror(const char*msg);
@ -29,6 +31,14 @@ static void errormsg(const YYLTYPE&loc, const char*msg, ...);
int parse_errors = 0;
%}
%union {
port_mode_t port_mode;
char*text;
InterfacePort*interface_element;
std::list<InterfacePort*>* interface_list;
};
/* The keywords are all tokens. */
%token K_abs K_access K_after K_alias K_all K_and K_architecture
%token K_array K_assert K_assume K_assume_guarantee K_attribute
@ -55,10 +65,15 @@ int parse_errors = 0;
%token K_wait K_when K_while K_with
%token K_xnor K_xor
/* Identifiers that are not keywords are identifiers. */
%token IDENTIFIER
%token <text> IDENTIFIER
/* compound symbols */
%token LEQ GEQ VASSIGN
/* The rules may have types. */
%type <interface_element> interface_element
%type <interface_list> interface_list entity_header port_clause
%type <port_mode> mode
%%
/* The design_file is the root for the VHDL parse. */
@ -116,12 +131,28 @@ design_units
| design_unit
;
/* As an entity is declared, add it to the map of design entities. */
entity_declaration
: K_entity IDENTIFIER K_is entity_header K_end K_entity ';'
{ Entity*tmp = new Entity;
// Store the name
tmp->name = lex_strings.make($2);
delete[]$2;
// Transfer the ports
std::list<InterfacePort*>*ports = $4;
while (ports->size() > 0) {
tmp->ports.push_back(ports->front());
ports->pop_front();
}
delete ports;
// Save the entity in the entity map.
design_entities[tmp->name] = tmp;
}
;
entity_header
: port_clause
{ $$ = $1; }
;
expression
@ -138,11 +169,26 @@ factor : primary ;
/* The interface_element is also an interface_declaration */
interface_element
: IDENTIFIER ':' mode IDENTIFIER
{ InterfacePort*tmp = new InterfacePort;
tmp->mode = $3;
tmp->name = lex_strings.make($1);
delete[]$1;
delete[]$4;
$$ = tmp;
}
;
interface_list
: interface_list ';' interface_element
{ std:list<InterfacePort*>*tmp = $1;
tmp->push_back($3);
$$ = tmp;
}
| interface_element
{ std::list<InterfacePort*>*tmp = new std::list<InterfacePort*>;
tmp->push_back($1);
$$ = tmp;
}
;
library_clause
@ -165,9 +211,15 @@ logical_name_list
| logical_name
;
mode : K_in | K_out ;
mode
: K_in { $$ = PORT_IN; }
| K_out { $$ = PORT_OUT; }
;
port_clause : K_port '(' interface_list ')' ';' ;
port_clause
: K_port '(' interface_list ')' ';'
{ $$ = $3; }
;
primary
: IDENTIFIER

View File

@ -20,6 +20,7 @@
*/
# include <cstdio>
# include "entity.h"
/*
* The vlltype supports the passing of detailed source file location

31
vhdlpp/parse_wrap.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef __parse_wrap_H
#define __parse_wrap_H
/*
* Copyright (c) 2011 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
*/
/*
* This header wraps the parse.h header file that is generated from
* the parse.y source file. This is used to include definitions that
* are needed by the parse type, etc.
*/
# include <list>
# include "parse.h"
#endif