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