Add support for nested when/else expressions.
This commit is contained in:
parent
1249b5dd32
commit
9b816f6478
|
|
@ -292,11 +292,22 @@ void ExpConditional::dump(ostream&out, int indent) const
|
|||
(*cur)->dump(out, indent+4);
|
||||
}
|
||||
|
||||
out << setw(indent) << "" << " else:" << endl;
|
||||
for (list<Expression*>::const_iterator cur = else_clause_.begin()
|
||||
for (list<else_t*>::const_iterator cur = else_clause_.begin()
|
||||
; cur != else_clause_.end() ; ++cur) {
|
||||
(*cur)->dump(out, indent);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpConditional::else_t::dump(ostream&out, int indent) const
|
||||
{
|
||||
out << setw(indent) << "" << "when:" << endl;
|
||||
if (cond_) cond_->dump(out, indent+4);
|
||||
out << setw(indent) << "" << "do:" << endl;
|
||||
for (list<Expression*>::const_iterator cur = true_clause_.begin()
|
||||
; cur != true_clause_.end() ; ++cur) {
|
||||
(*cur)->dump(out, indent+4);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ExpEdge::dump(ostream&out, int indent) const
|
||||
|
|
|
|||
|
|
@ -256,11 +256,12 @@ ExpCharacter::~ExpCharacter()
|
|||
{
|
||||
}
|
||||
|
||||
ExpConditional::ExpConditional(Expression*co, list<Expression*>*tru, list<Expression*>*els)
|
||||
ExpConditional::ExpConditional(Expression*co, list<Expression*>*tru,
|
||||
list<ExpConditional::else_t*>*fal)
|
||||
: cond_(co)
|
||||
{
|
||||
if (tru) true_clause_.splice(true_clause_.end(), *tru);
|
||||
if (els) else_clause_.splice(else_clause_.end(), *els);
|
||||
if (fal) else_clause_.splice(else_clause_.end(), *fal);
|
||||
}
|
||||
|
||||
ExpConditional::~ExpConditional()
|
||||
|
|
@ -272,12 +273,29 @@ ExpConditional::~ExpConditional()
|
|||
delete tmp;
|
||||
}
|
||||
while (! else_clause_.empty()) {
|
||||
Expression*tmp = else_clause_.front();
|
||||
else_t*tmp = else_clause_.front();
|
||||
else_clause_.pop_front();
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
|
||||
ExpConditional::else_t::else_t(Expression*cond, std::list<Expression*>*tru)
|
||||
: cond_(cond)
|
||||
{
|
||||
if (tru) true_clause_.splice(true_clause_.end(), *tru);
|
||||
}
|
||||
|
||||
ExpConditional::else_t::~else_t()
|
||||
{
|
||||
delete cond_;
|
||||
while (! true_clause_.empty()) {
|
||||
Expression*tmp = true_clause_.front();
|
||||
true_clause_.pop_front();
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ExpEdge::ExpEdge(ExpEdge::fun_t typ, Expression*op)
|
||||
: ExpUnary(op), fun_(typ)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -339,9 +339,25 @@ class ExpCharacter : public Expression {
|
|||
*/
|
||||
class ExpConditional : public Expression {
|
||||
|
||||
public:
|
||||
class else_t : public LineInfo {
|
||||
public:
|
||||
else_t(Expression*cond, std::list<Expression*>*tru);
|
||||
~else_t();
|
||||
|
||||
int elaborate_expr(Entity*ent, Architecture*arc, const VType*lt);
|
||||
int emit_when_else(ostream&out, Entity*ent, Architecture*arc);
|
||||
int emit_else(ostream&out, Entity*ent, Architecture*arc);
|
||||
void dump(ostream&out, int indent = 0) const;
|
||||
|
||||
private:
|
||||
Expression*cond_;
|
||||
std::list<Expression*> true_clause_;
|
||||
};
|
||||
|
||||
public:
|
||||
ExpConditional(Expression*cond, std::list<Expression*>*tru,
|
||||
std::list<Expression*>*els);
|
||||
std::list<else_t*>*fal);
|
||||
~ExpConditional();
|
||||
|
||||
const VType*probe_type(Entity*ent, Architecture*arc) const;
|
||||
|
|
@ -353,7 +369,7 @@ class ExpConditional : public Expression {
|
|||
private:
|
||||
Expression*cond_;
|
||||
std::list<Expression*> true_clause_;
|
||||
std::list<Expression*> else_clause_;
|
||||
std::list<else_t*> else_clause_;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -330,7 +330,7 @@ int ExpConditional::elaborate_expr(Entity*ent, Architecture*arc, const VType*lty
|
|||
errors += (*cur)->elaborate_expr(ent, arc, ltype);
|
||||
}
|
||||
|
||||
for (list<Expression*>::const_iterator cur = else_clause_.begin()
|
||||
for (list<else_t*>::const_iterator cur = else_clause_.begin()
|
||||
; cur != else_clause_.end() ; ++cur) {
|
||||
errors += (*cur)->elaborate_expr(ent, arc, ltype);
|
||||
}
|
||||
|
|
@ -338,6 +338,21 @@ int ExpConditional::elaborate_expr(Entity*ent, Architecture*arc, const VType*lty
|
|||
return errors;
|
||||
}
|
||||
|
||||
int ExpConditional::else_t::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype)
|
||||
{
|
||||
int errors = 0;
|
||||
|
||||
if (cond_)
|
||||
errors += cond_->elaborate_expr(ent, arc, 0);
|
||||
|
||||
for (list<Expression*>::const_iterator cur = true_clause_.begin()
|
||||
; cur != true_clause_.end() ; ++cur) {
|
||||
errors += (*cur)->elaborate_expr(ent, arc, ltype);
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
int ExpFunc::elaborate_expr(Entity*ent, Architecture*arc, const VType*)
|
||||
{
|
||||
int errors = 0;
|
||||
|
|
|
|||
|
|
@ -328,7 +328,7 @@ int ExpConditional::emit(ostream&out, Entity*ent, Architecture*arc)
|
|||
out << ")? (";
|
||||
|
||||
if (true_clause_.size() > 1) {
|
||||
cerr << get_fileline() << ": sorry: Multiple expressions not supported here." << endl;
|
||||
cerr << get_fileline() << ": sorry: Multiple expression waveforms not supported here." << endl;
|
||||
errors += 1;
|
||||
}
|
||||
|
||||
|
|
@ -337,15 +337,66 @@ int ExpConditional::emit(ostream&out, Entity*ent, Architecture*arc)
|
|||
|
||||
out << ") : (";
|
||||
|
||||
// Draw out any when-else expressions. These are all the else_
|
||||
// clauses besides the last.
|
||||
if (else_clause_.size() > 1) {
|
||||
cerr << get_fileline() << ": sorry: Multiple expressions not supported here." << endl;
|
||||
list<else_t*>::iterator last = else_clause_.end();
|
||||
-- last;
|
||||
|
||||
for (list<else_t*>::iterator cur = else_clause_.begin()
|
||||
; cur != last ; ++cur) {
|
||||
errors += (*cur) ->emit_when_else(out, ent, arc);
|
||||
}
|
||||
}
|
||||
|
||||
errors += else_clause_.back()->emit_else(out, ent, arc);
|
||||
out << ")";
|
||||
|
||||
// The emit_when_else() functions do not close the last
|
||||
// parentheses so that the following expression can be
|
||||
// nested. But that means come the end, we have some
|
||||
// expressions to close.
|
||||
for (size_t idx = 1 ; idx < else_clause_.size() ; idx += 1)
|
||||
out << ")";
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
int ExpConditional::else_t::emit_when_else(ostream&out, Entity*ent, Architecture*arc)
|
||||
{
|
||||
int errors = 0;
|
||||
assert(cond_ != 0);
|
||||
|
||||
out << "(";
|
||||
errors += cond_->emit(out, ent, arc);
|
||||
out << ")? (";
|
||||
|
||||
if (true_clause_.size() > 1) {
|
||||
cerr << get_fileline() << ": sorry: Multiple expression waveforms not supported here." << endl;
|
||||
errors += 1;
|
||||
}
|
||||
|
||||
tmp = else_clause_.front();
|
||||
Expression*tmp = true_clause_.front();
|
||||
errors += tmp->emit(out, ent, arc);
|
||||
|
||||
out << ")";
|
||||
out << ") : (";
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
int ExpConditional::else_t::emit_else(ostream&out, Entity*ent, Architecture*arc)
|
||||
{
|
||||
int errors = 0;
|
||||
// Trailing else must have no condition.
|
||||
assert(cond_ == 0);
|
||||
|
||||
if (true_clause_.size() > 1) {
|
||||
cerr << get_fileline() << ": sorry: Multiple expression waveforms not supported here." << endl;
|
||||
errors += 1;
|
||||
}
|
||||
|
||||
Expression*tmp = true_clause_.front();
|
||||
errors += tmp->emit(out, ent, arc);
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -205,6 +205,9 @@ static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
|
|||
IfSequential::Elsif*elsif;
|
||||
std::list<IfSequential::Elsif*>*elsif_list;
|
||||
|
||||
ExpConditional::else_t*exp_else;
|
||||
std::list<ExpConditional::else_t*>*exp_else_list;
|
||||
|
||||
CaseSeqStmt::CaseStmtAlternative* case_alt;
|
||||
std::list<CaseSeqStmt::CaseStmtAlternative*>* case_alt_list;
|
||||
|
||||
|
|
@ -282,7 +285,9 @@ static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
|
|||
%type <instantiation_list> instantiation_list
|
||||
%type <component_specification> component_specification
|
||||
|
||||
%type <arch_statement> concurrent_statement component_instantiation_statement concurrent_signal_assignment_statement
|
||||
%type <arch_statement> concurrent_statement component_instantiation_statement
|
||||
%type <arch_statement> concurrent_conditional_signal_assignment
|
||||
%type <arch_statement> concurrent_signal_assignment_statement
|
||||
%type <arch_statement> for_generate_statement generate_statement if_generate_statement
|
||||
%type <arch_statement> process_statement
|
||||
%type <arch_statement_list> architecture_statement_part generate_statement_body
|
||||
|
|
@ -334,6 +339,9 @@ static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
|
|||
%type <elsif> if_statement_elsif
|
||||
%type <elsif_list> if_statement_elsif_list if_statement_elsif_list_opt
|
||||
|
||||
%type <exp_else> else_when_waveform
|
||||
%type <exp_else_list> else_when_waveforms
|
||||
|
||||
%%
|
||||
|
||||
/* The design_file is the root for the VHDL parse. This rule is also
|
||||
|
|
@ -653,7 +661,54 @@ composite_type_definition
|
|||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
concurrent_signal_assignment_statement
|
||||
|
||||
/* The when...else..when...else syntax is not a general expression
|
||||
in VHDL but a specific sort of assignment statement model. We
|
||||
create Exppression objects for it, but the parser will only
|
||||
recognize it it in specific situations. */
|
||||
concurrent_conditional_signal_assignment /* IEEE 1076-2008 P11.6 */
|
||||
: name LEQ waveform K_when expression else_when_waveforms ';'
|
||||
{ ExpConditional*tmp = new ExpConditional($5, $3, $6);
|
||||
FILE_NAME(tmp, @3);
|
||||
delete $3;
|
||||
delete $6;
|
||||
|
||||
ExpName*name = dynamic_cast<ExpName*> ($1);
|
||||
assert(name);
|
||||
SignalAssignment*tmpa = new SignalAssignment(name, tmp);
|
||||
FILE_NAME(tmpa, @1);
|
||||
|
||||
$$ = tmpa;
|
||||
}
|
||||
;
|
||||
|
||||
else_when_waveforms
|
||||
: else_when_waveforms else_when_waveform
|
||||
{ list<ExpConditional::else_t*>*tmp = $1;
|
||||
tmp ->push_back($2);
|
||||
$$ = tmp;
|
||||
}
|
||||
| else_when_waveform
|
||||
{ list<ExpConditional::else_t*>*tmp = new list<ExpConditional::else_t*>;
|
||||
tmp->push_back($1);
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
else_when_waveform
|
||||
: K_else waveform K_when expression
|
||||
{ ExpConditional::else_t*tmp = new ExpConditional::else_t($4, $2);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_else waveform
|
||||
{ ExpConditional::else_t*tmp = new ExpConditional::else_t(0, $2);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
concurrent_signal_assignment_statement /* IEEE 1076-2008 P11.6 */
|
||||
: name LEQ waveform ';'
|
||||
{ ExpName*name = dynamic_cast<ExpName*> ($1);
|
||||
assert(name);
|
||||
|
|
@ -663,19 +718,9 @@ concurrent_signal_assignment_statement
|
|||
$$ = tmp;
|
||||
delete $3;
|
||||
}
|
||||
| name LEQ waveform K_when expression K_else waveform ';'
|
||||
{ ExpConditional*tmp = new ExpConditional($5, $3, $7);
|
||||
FILE_NAME(tmp, @3);
|
||||
delete $3;
|
||||
delete $7;
|
||||
|
||||
ExpName*name = dynamic_cast<ExpName*> ($1);
|
||||
assert(name);
|
||||
SignalAssignment*tmpa = new SignalAssignment(name, tmp);
|
||||
FILE_NAME(tmpa, @1);
|
||||
| concurrent_conditional_signal_assignment
|
||||
|
||||
$$ = tmpa;
|
||||
}
|
||||
| name LEQ error ';'
|
||||
{ errormsg(@2, "Syntax error in signal assignment waveform.\n");
|
||||
delete $1;
|
||||
|
|
|
|||
Loading…
Reference in New Issue