Add support for nested when/else expressions.

This commit is contained in:
Stephen Williams 2012-03-24 10:23:50 -07:00
parent 1249b5dd32
commit 9b816f6478
6 changed files with 181 additions and 25 deletions

View File

@ -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

View File

@ -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)
{

View File

@ -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_;
};
/*

View File

@ -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;

View File

@ -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;
}

View File

@ -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;