/* SapecNG - Next Generation Symbolic Analysis Program for Electric Circuit Copyright (C) 2009, Michele Caini This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "crc_circuit.h" #include "../exception/sapecngexception.h" #include #include #include #include #include #include #include #include #include namespace client { struct selm { sapecng::abstract_builder::dual_component_type dct; std::string name; int na; int nb; double value; bool symbolic; }; struct celm { sapecng::abstract_builder::quad_component_type qct; std::string name; int na; int nb; int nac; int nbc; double value; bool symbolic; }; struct acelm { sapecng::abstract_builder::quad_component_type qct; std::string name; int na; int nb; int nac; int nbc; }; struct circuit { std::vector selms; std::vector celms; std::vector acelms; std::vector comments; int out; }; } BOOST_FUSION_ADAPT_STRUCT( client::selm, (sapecng::abstract_builder::dual_component_type, dct) (std::string, name) (int, na) (int, nb) (double, value) (bool, symbolic) ) BOOST_FUSION_ADAPT_STRUCT( client::celm, (sapecng::abstract_builder::quad_component_type, qct) (std::string, name) (int, na) (int, nb) (int, nac) (int, nbc) (double, value) (bool, symbolic) ) BOOST_FUSION_ADAPT_STRUCT( client::acelm, (sapecng::abstract_builder::quad_component_type, qct) (std::string, name) (int, na) (int, nb) (int, nac) (int, nbc) ) BOOST_FUSION_ADAPT_STRUCT( client::circuit, (std::vector, comments) (std::vector, selms) (std::vector, celms) (std::vector, acelms) (int, out) ) struct dcp_ : boost::spirit::qi::symbols < char, sapecng::abstract_builder::dual_component_type > { dcp_() { add ("R", sapecng::abstract_builder::R) ("G", sapecng::abstract_builder::G) ("L", sapecng::abstract_builder::L) ("C", sapecng::abstract_builder::C) ("V", sapecng::abstract_builder::V) ("I", sapecng::abstract_builder::I) ; } }; struct qcp_ : boost::spirit::qi::symbols < char, sapecng::abstract_builder::quad_component_type > { qcp_() { add ("H", sapecng::abstract_builder::VCCS) ("E", sapecng::abstract_builder::VCVS) ("F", sapecng::abstract_builder::CCCS) ("Y", sapecng::abstract_builder::CCVS) ; } }; struct aqcp_ : boost::spirit::qi::symbols < char, sapecng::abstract_builder::quad_component_type > { aqcp_() { add ("A", sapecng::abstract_builder::AO) ; } }; template < typename It > struct crc_parser : boost::spirit::qi::grammar< It, ::client::circuit(), boost::spirit::qi::ascii::space_type > { typedef boost::spirit::qi::ascii::space_type space_type; crc_parser(std::ostream& err): crc_parser::base_type(circ, "crc") { using namespace boost::spirit; using namespace boost::phoenix; comment %= qi::lexeme['#' >> +(ascii::char_)]; selm = qi::char_("RGLCVI") [at_c<0>(_val) = (dcp_() << _1), at_c<1>(_val) = _1] >> *qi::char_("_a-zA-Z0-9") [at_c<1>(_val) += _1] >> qi::int_ [at_c<2>(_val) = _1] >> qi::int_ [at_c<3>(_val) = _1] >> qi::double_ [at_c<4>(_val) = _1] >> qi::bool_ [at_c<5>(_val) = _1] ; celm = qi::char_("HEFY") [at_c<0>(_val) = (dcp_() << _1), at_c<1>(_val) = _1] >> *qi::char_("_a-zA-Z0-9") [at_c<1>(_val) += _1] >> qi::int_ [at_c<2>(_val) = _1] >> qi::int_ [at_c<3>(_val) = _1] >> qi::int_ [at_c<4>(_val) = _1] >> qi::int_ [at_c<5>(_val) = _1] >> qi::double_ [at_c<6>(_val) = _1] >> qi::bool_ [at_c<7>(_val) = _1] ; acelm = qi::char_("A") [at_c<0>(_val) = (dcp_() << _1), at_c<1>(_val) = _1] >> *qi::char_("_a-zA-Z0-9") [at_c<1>(_val) += _1] >> qi::int_ [at_c<2>(_val) = _1] >> qi::int_ [at_c<3>(_val) = _1] >> qi::int_ [at_c<4>(_val) = _1] >> qi::int_ [at_c<5>(_val) = _1] ; circ = eps [at_c<4>(_val) = 0] >> *(comment) [push_back(at_c<0>(_val), _1)] >> +( selm [push_back(at_c<1>(_val), _1)] | celm [push_back(at_c<2>(_val), _1)] | acelm [push_back(at_c<3>(_val), _1)] ) >> ".OUT" >> qi::int_ [at_c<4>(_val) = _1] >> ".END"; ; comment.name("comment"); selm.name("selm component"); celm.name("celm component"); acelm.name("acelm component"); circ.name("circuit"); qi::on_error (circ, err << val("Syntax error. Expecting ") << _4 << val(" here: \"") << construct(_3, _2) << val("\"") << std::endl ); } boost::spirit::qi::rule comment; boost::spirit::qi::rule selm; boost::spirit::qi::rule celm; boost::spirit::qi::rule acelm; boost::spirit::qi::rule circ; }; namespace sapecng { void crc_parser::parse(abstract_builder& builder) { std::stringstream ss; while(stream_.good()) ss << (char)stream_.get(); std::string crc = ss.str(); std::string::const_iterator iter = crc.begin(); std::string::const_iterator end = crc.end(); ::client::circuit c; std::ostringstream oss; ::crc_parser g(oss); bool r = boost::spirit::qi::phrase_parse(iter, end, g, boost::spirit::qi::ascii::space, c); if(!r || iter != end) { typedef boost::error_info what; sapecng::stream_read_error e; e << what(oss.str()); throw e; } else { builder.add_out_component(c.out); for(std::vector::size_type i = 0; i < c.comments.size(); ++i) { std::stringstream cnt; cnt << i; builder.add_circuit_property( "comment_" + cnt.str(), c.comments.at(i) ); } for(std::vector< client::selm >::size_type i = 0; i < c.selms.size(); ++i) builder.add_dual_component( c.selms.at(i).dct, c.selms.at(i).name, c.selms.at(i).value, c.selms.at(i).symbolic, c.selms.at(i).na, c.selms.at(i).nb ); for(std::vector< client::celm >::size_type i = 0; i < c.celms.size(); ++i) builder.add_quad_component( c.celms.at(i).qct, c.celms.at(i).name, c.celms.at(i).value, c.celms.at(i).symbolic, c.celms.at(i).na, c.celms.at(i).nb, c.celms.at(i).nac, c.celms.at(i).nbc ); for(std::vector< client::acelm >::size_type i = 0; i < c.acelms.size(); ++i) builder.add_quad_component( c.acelms.at(i).qct, c.acelms.at(i).name, 1., true, c.acelms.at(i).na, c.acelms.at(i).nb, c.acelms.at(i).nac, c.acelms.at(i).nbc ); } } void crc_builder::add_out_component( unsigned int v, std::map props ) { out_ = v; } void crc_builder::add_dual_component( abstract_builder::dual_component_type c_type, std::string name, double value, bool symbolic, unsigned int va, unsigned int vb, std::map props ) { std::vector nodes; nodes.push_back(va); nodes.push_back(vb); switch(c_type) { case abstract_builder::R: { if(name.size() == 0 || name.at(0) != 'R') name = "R_" + name; add_item(name, value, symbolic, nodes); break; } case abstract_builder::G: { if(name.size() == 0 || name.at(0) != 'G') name = "G_" + name; add_item(name, value, symbolic, nodes); break; } case abstract_builder::L: { if(name.size() == 0 || name.at(0) != 'L') name = "L_" + name; add_item(name, value, symbolic, nodes); break; } case abstract_builder::C: { if(name.size() == 0 || name.at(0) != 'C') name = "C_" + name; add_item(name, value, symbolic, nodes); break; } case abstract_builder::V: { if(name.size() == 0 || name.at(0) != 'V') name = "V_" + name; add_item(name, value, symbolic, nodes); break; } case abstract_builder::I: { if(name.size() == 0 || name.at(0) != 'I') name = "I_" + name; add_item(name, value, symbolic, nodes); break; } default: break; } } void crc_builder::add_quad_component( abstract_builder::quad_component_type c_type, std::string name, double value, bool symbolic, unsigned int va, unsigned int vb, unsigned int vac, unsigned int vbc, std::map props ) { std::vector nodes; nodes.push_back(va); nodes.push_back(vb); nodes.push_back(vac); nodes.push_back(vbc); switch(c_type) { case abstract_builder::VCCS: { if(name.size() == 0 || name.at(0) != 'H') name = "H_" + name; add_item(name, value, symbolic, nodes); break; } case abstract_builder::VCVS: { if(name.size() == 0 || name.at(0) != 'E') name = "E_" + name; add_item(name, value, symbolic, nodes); break; } case abstract_builder::CCCS: { if(name.size() == 0 || name.at(0) != 'F') name = "F_" + name; add_item(name, value, symbolic, nodes); break; } case abstract_builder::CCVS: { if(name.size() == 0 || name.at(0) != 'Y') name = "Y_" + name; add_item(name, value, symbolic, nodes); break; } case abstract_builder::AO: { if(name.size() == 0 || name.at(0) != 'A') name = "A_" + name; stream_ << name << " "; for(unsigned int i = 0; i < nodes.size(); ++i) stream_ << nodes[i] << " "; stream_ << std::endl; break; } default: break; } } void crc_builder::flush() { stream_ << ".OUT " << out_ << std::endl; stream_ << ".END" << std::endl; } void crc_builder::add_item( std::string name, double value, bool symbolic, std::vector nodes ) { stream_ << name << " "; for(unsigned int i = 0; i < nodes.size(); ++i) stream_ << nodes[i] << " "; stream_ << value << " "; stream_ << symbolic << std::endl; } }