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;
|
<< " 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
|
void ExpArithmetic::dump(ostream&out, int indent) const
|
||||||
{
|
{
|
||||||
const char*fun_name = "?";
|
const char*fun_name = "?";
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,73 @@ ExpUnary::~ExpUnary()
|
||||||
delete operand1_;
|
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)
|
ExpArithmetic::ExpArithmetic(ExpArithmetic::fun_t op, Expression*op1, Expression*op2)
|
||||||
: ExpBinary(op1, op2), fun_(op)
|
: ExpBinary(op1, op2), fun_(op)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,77 @@ class ExpBinary : public Expression {
|
||||||
Expression*operand2_;
|
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 {
|
class ExpArithmetic : public ExpBinary {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,71 @@ int ExpBinary::elaborate_exprs(Entity*ent, Architecture*arc, const VType*ltype)
|
||||||
return errors;
|
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 ExpArithmetic::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype)
|
||||||
{
|
{
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
# include "vtype.h"
|
# include "vtype.h"
|
||||||
# include <typeinfo>
|
# include <typeinfo>
|
||||||
# include <iostream>
|
# include <iostream>
|
||||||
|
# include <cstdlib>
|
||||||
# include <cassert>
|
# include <cassert>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
@ -65,6 +66,30 @@ int ExpUnary::emit_operand1(ostream&out, Entity*ent, Architecture*arc)
|
||||||
return errors;
|
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 ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc)
|
||||||
{
|
{
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,11 @@ const VType*parse_type_by_name(perm_string name)
|
||||||
|
|
||||||
range_t* range;
|
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;
|
std::list<InterfacePort*>* interface_list;
|
||||||
|
|
||||||
Architecture::Statement* arch_statement;
|
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> process_statement
|
||||||
%type <arch_statement_list> architecture_statement_part
|
%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 expression_logical_and expression_logical_or
|
||||||
%type <expr> expression_logical_xnor expression_logical_xor
|
%type <expr> expression_logical_xnor expression_logical_xor
|
||||||
%type <expr> name
|
%type <expr> name
|
||||||
|
|
@ -453,12 +463,25 @@ 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
|
case_statement_alternative
|
||||||
: K_when choice ARROW sequence_of_statements
|
: K_when choice ARROW sequence_of_statements
|
||||||
{
|
{ CaseSeqStmt::CaseStmtAlternative* tmp;
|
||||||
CaseSeqStmt::CaseStmtAlternative* tmp =
|
if ($2->others()) {
|
||||||
new CaseSeqStmt::CaseStmtAlternative($2, $4);
|
tmp = new CaseSeqStmt::CaseStmtAlternative(0, $4);
|
||||||
FILE_NAME(tmp, @1);
|
} 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;
|
delete $4;
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
|
|
@ -466,14 +489,22 @@ case_statement_alternative
|
||||||
|
|
||||||
choice
|
choice
|
||||||
: simple_expression
|
: simple_expression
|
||||||
{ $$ = $1;}
|
{ $$ = new ExpAggregate::choice_t($1);}
|
||||||
| K_others
|
| K_others
|
||||||
{ $$ = 0; }
|
{ $$ = new ExpAggregate::choice_t; }
|
||||||
;
|
;
|
||||||
|
|
||||||
choices
|
choices
|
||||||
: choices '|' choice
|
: choices '|' choice
|
||||||
|
{ std::list<ExpAggregate::choice_t*>*tmp = $1;
|
||||||
|
tmp->push_back($3);
|
||||||
|
$$ = tmp;
|
||||||
|
}
|
||||||
| choice
|
| choice
|
||||||
|
{ std::list<ExpAggregate::choice_t*>*tmp = new std::list<ExpAggregate::choice_t*>;
|
||||||
|
tmp->push_back($1);
|
||||||
|
$$ = tmp;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
component_configuration
|
component_configuration
|
||||||
|
|
@ -682,11 +713,22 @@ direction : K_to { $$ = false; } | K_downto { $$ = true; } ;
|
||||||
|
|
||||||
element_association
|
element_association
|
||||||
: choices ARROW expression
|
: choices ARROW expression
|
||||||
|
{ ExpAggregate::element_t*tmp = new ExpAggregate::element_t($1, $3);
|
||||||
|
$$ = tmp;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
element_association_list
|
element_association_list
|
||||||
: element_association_list ',' element_association
|
: element_association_list ',' element_association
|
||||||
|
{ std::list<ExpAggregate::element_t*>*tmp = $1;
|
||||||
|
tmp->push_back($3);
|
||||||
|
$$ = tmp;
|
||||||
|
}
|
||||||
| element_association
|
| 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. */
|
/* As an entity is declared, add it to the map of design entities. */
|
||||||
|
|
@ -1334,8 +1376,9 @@ primary
|
||||||
| '(' expression ')'
|
| '(' expression ')'
|
||||||
{ $$ = $2; }
|
{ $$ = $2; }
|
||||||
| '(' element_association_list ')'
|
| '(' element_association_list ')'
|
||||||
{ sorrymsg(@1, "Aggregate expressions not supported\n");
|
{ ExpAggregate*tmp = new ExpAggregate($2);
|
||||||
$$ = 0;
|
FILE_NAME(tmp,@1);
|
||||||
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue