From 5b7b980ead0fccf9eaca94a8552bbb679fd1c517 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 3 Feb 2015 16:52:19 +0100 Subject: [PATCH] vhdlpp: Support for multiple choices in case statements. --- vhdlpp/parse.y | 46 ++++++++++++++++++++++++---------- vhdlpp/sequential.cc | 3 ++- vhdlpp/sequential.h | 4 +-- vhdlpp/sequential_debug.cc | 4 ++- vhdlpp/sequential_elaborate.cc | 8 ++++-- vhdlpp/sequential_emit.cc | 23 ++++++++++++++--- 6 files changed, 65 insertions(+), 23 deletions(-) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index bd3add632..a509d8fa6 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -573,20 +573,40 @@ case_statement_alternative_list * statement alternative and pass that up instead. */ case_statement_alternative - : K_when choice ARROW sequence_of_statements + : K_when choices ARROW sequence_of_statements { 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; + std::list*choices = $2; + std::list*exp_list = new std::list; + bool others = false; + + for(std::list::iterator it = choices->begin(); + it != choices->end(); ++it) { + if((*it)->others() || others) + // If there is one "others", then it also covers all other alternatives + // Continue the loop to delete every choice_t, but do not + // bother to add the expressions to the exp_list (we are going to + // delete them very soon) + others = true; + else + exp_list->push_back((*it)->simple_expression()); + + delete (*it); + } + + if(others) { + tmp = new CaseSeqStmt::CaseStmtAlternative(0, $4); + for(std::list::iterator it = exp_list->begin(); + it != exp_list->end(); ++it) { + delete (*it); + } + } else { + tmp = new CaseSeqStmt::CaseStmtAlternative(exp_list, $4); + } + if (tmp) FILE_NAME(tmp, @1); + + delete choices; + delete $4; + $$ = tmp; } ; diff --git a/vhdlpp/sequential.cc b/vhdlpp/sequential.cc index dc6043d70..f6fe41d0d 100644 --- a/vhdlpp/sequential.cc +++ b/vhdlpp/sequential.cc @@ -146,7 +146,8 @@ void CaseSeqStmt::visit(SeqStmtVisitor& func) func(this); } -CaseSeqStmt::CaseStmtAlternative::CaseStmtAlternative(Expression* exp, list* stmts) +CaseSeqStmt::CaseStmtAlternative::CaseStmtAlternative(std::list*exp, + list*stmts) : exp_(exp) { if (stmts) stmts_.splice(stmts_.end(), *stmts); diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index 06fff7b8d..c9f039fea 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -167,7 +167,7 @@ class CaseSeqStmt : public SequentialStmt { public: class CaseStmtAlternative : public LineInfo { public: - CaseStmtAlternative(Expression* exp, std::list* stmts); + CaseStmtAlternative(std::list*exp, std::list*stmts); ~CaseStmtAlternative(); void dump(std::ostream& out, int indent) const; int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); @@ -177,7 +177,7 @@ class CaseSeqStmt : public SequentialStmt { void visit(SeqStmtVisitor& func); private: - Expression* exp_; + std::list*exp_; std::list stmts_; private: // not implemented CaseStmtAlternative(const CaseStmtAlternative&); diff --git a/vhdlpp/sequential_debug.cc b/vhdlpp/sequential_debug.cc index b28d0f8cc..31f3655d2 100644 --- a/vhdlpp/sequential_debug.cc +++ b/vhdlpp/sequential_debug.cc @@ -105,7 +105,9 @@ void CaseSeqStmt::CaseStmtAlternative::dump(ostream& out, int indent) const out << setw(indent) << "" << "when "; if (exp_) - exp_->dump(out, 0); + for (list::iterator it = exp_->begin(); it != exp_->end(); ++it) { + (*it)->dump(out, 0); + } else out << "others" << endl; diff --git a/vhdlpp/sequential_elaborate.cc b/vhdlpp/sequential_elaborate.cc index 88d215de7..2244e0f16 100644 --- a/vhdlpp/sequential_elaborate.cc +++ b/vhdlpp/sequential_elaborate.cc @@ -62,8 +62,12 @@ int CaseSeqStmt::elaborate(Entity*ent, ScopeBase*scope) int CaseSeqStmt::CaseStmtAlternative::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype) { int errors = 0; - if (exp_) - errors += exp_->elaborate_expr(ent, scope, ltype); + if (exp_) { + for (list::iterator it = exp_->begin(); it != exp_->end(); + ++it) { + errors += (*it)->elaborate_expr(ent, scope, ltype); + } + } return errors; } diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index 36e784a4e..895d1d839 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -271,12 +271,19 @@ int CaseSeqStmt::CaseStmtAlternative::emit(ostream&out, Entity*ent, ScopeBase*sc { int errors = 0; + bool first = true; if (exp_) { - errors += exp_->emit(out, ent, scope); - out << ":" << endl; + for (list::iterator it = exp_->begin(); it != exp_->end(); ++it) { + if(first) + first = false; + else + out << ","; + errors += (*it)->emit(out, ent, scope); + } } else { - out << "default:" << endl; + out << "default"; } + out << ":" << endl; SequentialStmt*curp; @@ -306,7 +313,15 @@ void CaseSeqStmt::CaseStmtAlternative::write_to_stream(ostream&fd) { fd << "when "; if (exp_) { - exp_->write_to_stream(fd); + bool first = true; + for (list::iterator it = exp_->begin(); it != exp_->end(); ++it) { + if(first) + first = false; + else + fd << "|"; + + (*it)->write_to_stream(fd); + } } else { fd << "others" << endl; }