Handle the basics of aggregate expressions

This takes care of the parser support, and a shell of the
elaboration. Handle some special cases all the way through.
This commit is contained in:
Stephen Williams 2011-09-03 17:11:55 -07:00
parent 4464c5849b
commit 6d28c989ce
6 changed files with 315 additions and 11 deletions

View File

@ -161,6 +161,39 @@ void Expression::dump(ostream&out, int indent) const
<< " at " << get_fileline()<< endl;
}
void ExpAggregate::dump(ostream&out, int indent) const
{
out << setw(indent) << "" << "Aggregate expression at " << get_fileline() << endl;
for (size_t idx = 0 ; idx < elements_.size() ; idx += 1)
elements_[idx]->dump(out, indent+2);
}
void ExpAggregate::element_t::dump(ostream&out, int indent) const
{
out << setw(indent) << "" << "choices:" << endl;
for (size_t idx = 0 ; idx < fields_.size() ; idx += 1)
fields_[idx]->dump(out, indent+4);
out << setw(indent) << "" << "expression:" << endl;
val_->dump(out, indent+4);
}
void ExpAggregate::choice_t::dump(ostream&out, int indent) const
{
if (others()) {
out << setw(indent) << "" << "=> others" << endl;
return;
}
if (expr_) {
expr_->dump(out, indent);
return;
}
out << setw(indent) << "" << "?choice_t?" << endl;
}
void ExpArithmetic::dump(ostream&out, int indent) const
{
const char*fun_name = "?";

View File

@ -117,6 +117,73 @@ ExpUnary::~ExpUnary()
delete operand1_;
}
ExpAggregate::ExpAggregate(std::list<element_t*>*el)
: elements_(el? el->size() : 0)
{
assert(el);
size_t idx = 0;
while (! el->empty()) {
assert(idx < elements_.size());
elements_[idx++] = el->front();
el->pop_front();
}
}
ExpAggregate::~ExpAggregate()
{
for (size_t idx = 0 ; idx < elements_.size() ; idx += 1)
delete elements_[idx];
}
ExpAggregate::choice_t::choice_t(Expression*exp)
: expr_(exp)
{
}
ExpAggregate::choice_t::choice_t()
: expr_(0)
{
}
ExpAggregate::choice_t::~choice_t()
{
if (expr_) delete expr_;
}
bool ExpAggregate::choice_t::others() const
{
return expr_ == 0;
}
Expression*ExpAggregate::choice_t::simple_expression(bool detach_flag)
{
Expression*res = expr_;
if (detach_flag)
expr_ = 0;
return res;
}
ExpAggregate::element_t::element_t(list<choice_t*>*fields, Expression*val)
: fields_(fields? fields->size() : 0), val_(val)
{
size_t idx = 0;
if (fields) {
while (! fields->empty()) {
assert(idx < fields_.size());
fields_[idx++] = fields->front();
fields->pop_front();
}
}
}
ExpAggregate::element_t::~element_t()
{
for (size_t idx = 0 ; idx < fields_.size() ; idx += 1)
delete fields_[idx];
delete val_;
}
ExpArithmetic::ExpArithmetic(ExpArithmetic::fun_t op, Expression*op1, Expression*op2)
: ExpBinary(op1, op2), fun_(op)
{

View File

@ -156,6 +156,77 @@ class ExpBinary : public Expression {
Expression*operand2_;
};
class ExpAggregate : public Expression {
public:
class choice_t {
public:
// Create an "others" choice
choice_t();
// Create a simple_expression choice
explicit choice_t(Expression*exp);
// Create a named choice
explicit choice_t(perm_string name);
~choice_t();
// true if this represents an "others" choice
bool others() const;
// Return expression if this reprents simple_expression.
Expression*simple_expression(bool detach_flag =true);
void dump(ostream&out, int indent) const;
private:
Expression*expr_;
private: // not implemented
choice_t(const choice_t&);
choice_t& operator= (const choice_t&);
};
struct choice_element {
choice_t*choice;
Expression*expr;
bool alias_flag;
};
class element_t {
public:
explicit element_t(std::list<choice_t*>*fields, Expression*val);
~element_t();
size_t count_choices() const { return fields_.size(); }
void map_choices(choice_element*dst);
void dump(ostream&out, int indent) const;
private:
std::vector<choice_t*>fields_;
Expression*val_;
private: // not implemented
element_t(const element_t&);
element_t& operator = (const element_t&);
};
public:
ExpAggregate(std::list<element_t*>*el);
~ExpAggregate();
int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
int emit(ostream&out, Entity*ent, Architecture*arc);
void dump(ostream&out, int indent = 0) const;
private:
int elaborate_expr_array_(Entity*ent, Architecture*arc, const VTypeArray*ltype);
private:
// This is the elements as directly parsed.
std::vector<element_t*> elements_;
// These are the elements after elaboration. This form is
// easier to check and emit.
std::vector<choice_element> aggregate_;
};
class ExpArithmetic : public ExpBinary {
public:

View File

@ -153,6 +153,71 @@ int ExpBinary::elaborate_exprs(Entity*ent, Architecture*arc, const VType*ltype)
return errors;
}
int ExpAggregate::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype)
{
if (ltype == 0) {
cerr << get_fileline() << ": error: Elaboration of aggregate types needs wel known type context?" << endl;
return 1;
}
set_type(ltype);
if (const VTypeArray*larray = dynamic_cast<const VTypeArray*>(ltype)) {
return elaborate_expr_array_(ent, arc, larray);
}
cerr << get_fileline() << ": internal error: I don't know how to elaborate aggregate expressions. type=" << typeid(*ltype).name() << endl;
return 1;
}
/*
* Elaboration of array aggregates is elaboration of the element
* expressions using the element type as the ltype for the
* subexpression.
*/
int ExpAggregate::elaborate_expr_array_(Entity*ent, Architecture*arc, const VTypeArray*ltype)
{
const VType*element_type = ltype->element_type();
int errors = 0;
size_t choice_count = 0;
for (size_t edx = 0 ; edx < elements_.size() ; edx += 1) {
element_t*ecur = elements_[edx];
choice_count += ecur->count_choices();
}
aggregate_.resize(choice_count);
size_t cdx = 0;
for (size_t edx = 0 ; edx < elements_.size() ; edx += 1) {
element_t*ecur = elements_[edx];
ecur->map_choices(&aggregate_[cdx]);
cdx += ecur->count_choices();
}
assert(cdx == choice_count);
for (size_t idx = 0 ; idx < aggregate_.size() ; idx += 1) {
if (aggregate_[idx].alias_flag)
continue;
errors += aggregate_[idx].expr->elaborate_expr(ent, arc, element_type);
}
elements_.clear();
return errors;
}
void ExpAggregate::element_t::map_choices(ExpAggregate::choice_element*dst)
{
for (size_t idx = 0 ; idx < fields_.size() ; idx += 1) {
dst->choice = fields_[idx];
dst->expr = val_;
dst->alias_flag = (idx != 0);
dst += 1;
}
}
int ExpArithmetic::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype)
{
int errors = 0;

View File

@ -21,6 +21,7 @@
# include "vtype.h"
# include <typeinfo>
# include <iostream>
# include <cstdlib>
# include <cassert>
using namespace std;
@ -65,6 +66,30 @@ int ExpUnary::emit_operand1(ostream&out, Entity*ent, Architecture*arc)
return errors;
}
int ExpAggregate::emit(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;
// Special case: The aggregate is a single "others" item.
if (aggregate_.size() == 1 && aggregate_[0].choice->others()) {
const VTypeArray*atype = dynamic_cast<const VTypeArray*> (peek_type());
assert(atype);
assert(atype->dimensions() == 1);
const VTypeArray::range_t&rang = atype->dimension(0);
assert(! rang.is_box());
int asize = abs(rang.msb() - rang.lsb()) + 1;
out << "{" << asize << "{";
errors += aggregate_[0].expr->emit(out, ent, arc);
out << "}}";
return errors;
}
return Expression::emit(out, ent, arc);
}
int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;

View File

@ -176,6 +176,11 @@ const VType*parse_type_by_name(perm_string name)
range_t* range;
ExpAggregate::choice_t*choice;
std::list<ExpAggregate::choice_t*>*choice_list;
ExpAggregate::element_t*element;
std::list<ExpAggregate::element_t*>*element_list;
std::list<InterfacePort*>* interface_list;
Architecture::Statement* arch_statement;
@ -231,7 +236,12 @@ const VType*parse_type_by_name(perm_string name)
%type <arch_statement> process_statement
%type <arch_statement_list> architecture_statement_part
%type <expr> choice expression factor primary relation
%type <choice> choice
%type <choice_list> choices
%type <element> element_association
%type <element_list> element_association_list
%type <expr> expression factor primary relation
%type <expr> expression_logical expression_logical_and expression_logical_or
%type <expr> expression_logical_xnor expression_logical_xor
%type <expr> name
@ -453,27 +463,48 @@ case_statement_alternative_list
}
;
/*
* The case_statement_alternative uses the "choice" rule to select the
* reference expression, but that rule is shared with the aggregate
* expression. So convert the ExpAggregate::choice_t to a case
* statement alternative and pass that up instead.
*/
case_statement_alternative
: K_when choice ARROW sequence_of_statements
{
CaseSeqStmt::CaseStmtAlternative* tmp =
new CaseSeqStmt::CaseStmtAlternative($2, $4);
FILE_NAME(tmp, @1);
delete $4;
$$ = tmp;
{ CaseSeqStmt::CaseStmtAlternative* tmp;
if ($2->others()) {
tmp = new CaseSeqStmt::CaseStmtAlternative(0, $4);
} else if (Expression*ex = $2->simple_expression()) {
tmp = new CaseSeqStmt::CaseStmtAlternative(ex, $4);
} else {
errormsg(@2, "I don't know what to make of the case choice\n");
tmp = 0;
}
if (tmp) FILE_NAME(tmp, @1);
delete $2;
delete $4;
$$ = tmp;
}
;
choice
: simple_expression
{ $$ = $1;}
{ $$ = new ExpAggregate::choice_t($1);}
| K_others
{ $$ = 0; }
{ $$ = new ExpAggregate::choice_t; }
;
choices
: choices '|' choice
{ std::list<ExpAggregate::choice_t*>*tmp = $1;
tmp->push_back($3);
$$ = tmp;
}
| choice
{ std::list<ExpAggregate::choice_t*>*tmp = new std::list<ExpAggregate::choice_t*>;
tmp->push_back($1);
$$ = tmp;
}
;
component_configuration
@ -682,11 +713,22 @@ direction : K_to { $$ = false; } | K_downto { $$ = true; } ;
element_association
: choices ARROW expression
{ ExpAggregate::element_t*tmp = new ExpAggregate::element_t($1, $3);
$$ = tmp;
}
;
element_association_list
: element_association_list ',' element_association
{ std::list<ExpAggregate::element_t*>*tmp = $1;
tmp->push_back($3);
$$ = tmp;
}
| element_association
{ std::list<ExpAggregate::element_t*>*tmp = new std::list<ExpAggregate::element_t*>;
tmp->push_back($1);
$$ = tmp;
}
;
/* As an entity is declared, add it to the map of design entities. */
@ -1334,8 +1376,9 @@ primary
| '(' expression ')'
{ $$ = $2; }
| '(' element_association_list ')'
{ sorrymsg(@1, "Aggregate expressions not supported\n");
$$ = 0;
{ ExpAggregate*tmp = new ExpAggregate($2);
FILE_NAME(tmp,@1);
$$ = tmp;
}
;