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:
parent
4464c5849b
commit
6d28c989ce
|
|
@ -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 = "?";
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue