/* cxxsim: creates a C++ simulation from MTT elementary system equations
* Copyright (C) 2000,2002 Geraint Paul Bevan
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <fstream>
#include <list>
#include <map>
#include <string>
namespace cxxsim {
class cr {
public:
cr (std::string system_name);
void read (std::ifstream &file);
void write (std::ofstream &file);
friend std::ifstream &operator>> (std::ifstream &file, cr &c);
friend std::ofstream &operator<< (std::ofstream &file, cr &c);
private:
std::string name;
std::list<std::string> L;
};
class equations {
public:
equations (std::string system_name);
void read (std::ifstream &file);
void write (std::ofstream &file);
friend std::ifstream &operator>> (std::ifstream &file, equations &e);
friend std::ofstream &operator<< (std::ofstream &file, equations &e);
private:
void descend (std::string s);
void parse (void);
std::string name; // system name
// list of statements collected by reader
std::list<std::string> statements;
std::list<std::string> leqn; // final expressions
std::list<std::string> lvar; // intermediate expressions
std::list<std::string> loop; // algebraic loops
// table of final and intermediate expressions
std::map<std::string, std::string> meqn; // lhs, rhs mapping
std::map<std::string, std::string> mvar;
// tag is symbol denoting an intermediate variable
std::string tag; // denotes intermediates
// token delimiters (not ([{.`'" or alphanumeric)
std::string delim;
};
class parameter {
public:
parameter (std::string system_name);
void read (std::ifstream &file);
void write (std::ofstream &file);
friend std::ifstream &operator>> (std::ifstream &file, parameter &p);
friend std::ofstream &operator<< (std::ofstream &file, parameter &p);
private:
std::string name;
struct record {
std::string variable;
std::string component;
};
typedef struct record record_t;
std::list<record_t> L;
};
class structure {
public:
structure (std::string system_name);
void read (std::ifstream &file);
void write (std::ofstream &file);
friend std::ifstream &operator>> (std::ifstream &file, structure &s);
friend std::ofstream &operator<< (std::ofstream &file, structure &s);
private:
void write_declare (std::ofstream &file);
void write_input (std::ofstream &file);
void write_logic (std::ofstream &file);
void write_state (std::ofstream &file);
std::string name;
struct record {
std::string vec; // vector: u, x, y, yz
unsigned int num; // position of element in vector
std::string cmp; // component
std::string fnm; // full name
unsigned int rpt; // number of repetitions
};
typedef struct record record_t;
std::list<record_t> Lu;
std::list<record_t> Lx;
std::list<record_t> Ly;
std::list<record_t> Lyz;
std::list<record_t>::iterator i;
};
cr::cr (std::string system_name){
name = system_name;
}
void
cr::read (std::ifstream &file){
std::string r;
while (file >> r){
L.push_back(r);
}
}
void
cr::write (std::ofstream &file){
file << "enum causality { effort, flow, state };" << std::endl
<< "typedef enum causality causality_t;" << std::endl;
std::list<std::string>::iterator i;
for (i = L.begin(); i != L.end(); i++){
if ((*i != "SS") && (*i != "ISW")){
file << "#include <" << *i << ".hh>" << std::endl;
}
}
file << std::endl;
}
std::ifstream &operator>> (std::ifstream &file, cr &c){
c.read(file);
return file;
}
std::ofstream &operator<< (std::ofstream &file, cr &c){
c.write(file);
return file;
}
equations::equations (std::string system_name){
name = system_name;
tag = system_name;
delim = "~!@#$%^&*)-+=]}\\|;:,<>/?";
};
void
equations::read (std::ifstream &file){
char c;
std::string s;
std::string t;
unsigned int i;
// file.unsetf(ios::skipws);
file.setf(ios::skipws);
// read lines from file (no max length, unlike std::getline)
while (file >> c){
s = "";
while (c != ';' && file){
if (c == '%'){
file.unsetf(ios::skipws);
while ((c != '\n') && file){
file >> c; // eat comment
}
file.setf(ios::skipws);
} else {
if ((c != ' ') && (c != '\t')){ // strip whitespace
s += c;
}
file >> c;
}
}
// fix vector references
t = "MTTu\(";
while ((i = s.find(t)) < s.length()){
s.replace(i, 5, "mttu[");
i += s.substr(i, s.length()).find(",1)");
s.replace(i, 3, "]");
}
t = "MTTx\(";
while ((i = s.find(t)) < s.length()){
s.replace(i, 5, "mttx[");
i += s.substr(i, s.length()).find(",1)");
s.replace(i, 3, "]");
}
t = "MTTdX\(";
while ((i = s.find(t)) < s.length()){
s.replace(i, 6, "mttdx[");
i += s.substr(i, s.length()).find(",1)");
s.replace(i, 3, "]");
}
t = "MTTy\(";
while ((i = s.find(t)) < s.length()){
s.replace(i, 5, "mtty[");
i += s.substr(i, s.length()).find(",1)");
s.replace(i, 3, "]");
}
// strip newlines
while ((i = s.find('\n')) < s.length()){
s.replace(i, 1, "");
}
if ((s != "") && (s != "END")){
// add statement to list
statements.push_back(s);
}
}
// finished reading, time to comprehend ...
this->parse();
}
void
equations::write (std::ofstream &file){
std::list<std::string>::iterator eqn;
file << "void" << std::endl
<< this->name << "_ode(const double t," << std::endl
<< "\tdouble *mttu," << std::endl
<< "\tdouble *mttx," << std::endl
<< "\tdouble *mttdx," << std::endl
<< "\tdouble *mtty)" << std::endl
<< "{" << std::endl;
for (eqn = leqn.begin(); eqn != leqn.end(); eqn++){
file << *eqn << " = " << meqn[*eqn] << ";" << std::endl;
}
file << "} // " << this->name << "_ode" << std::endl;
};
void
equations::descend (std::string s){
char c;
unsigned int i;
bool cont;
std::list<std::string>::iterator var;
loop.push_back(s);
// find algebraic loops
for (var = loop.begin(); var != loop.end(); var++){
if ((i = mvar[s].find(*var)) < mvar[s].length()){
c = mvar[s].c_str()[i + var->length()];
if (delim.find(c) < delim.length()){
std::cerr << std::endl
<< "warning: algebraic loop" << std::endl
<< '\t' << s << " = " << mvar[s].substr(0, 60);
if (mvar[s].length() > 60){
std::cerr << " ...";
}
std::cerr << std::endl << std::endl;
mvar[s] = s + "____loop";
}
}
}
// substitutes intermediate variables for their expansion
do {
cont = false;
for (var = lvar.begin(); var != lvar.end(); var++){
// check for token match
while ((i = mvar[s].find(*var)) < mvar[s].length()){
// ensure exact match
c = mvar[s].c_str()[i + var->length()];
if (delim.find(c) < delim.length()){
// expand expression recursively
this->descend(*var);
// check match again, map may have changed
if ((i = mvar[s].find(*var)) < mvar[s].length()){
c = mvar[s].c_str()[i + var->length()];
if (delim.find(c) < delim.length()){
// substitute expression
mvar[s].replace(i, var->length(), mvar[*var]);
// continue
cont = true;
}
}
}
}
}
} while (cont);
loop.pop_back();
}
void
equations::parse (void){
char c;
unsigned int i;
std::string lhs;
std::string rhs;
std::list<std::string>::iterator s;
std::list<std::string>::iterator eqn;
std::list<std::string>::iterator var;
for (s = statements.begin(); s != statements.end(); s++){
// parse statement
if ((i = s->find(":=")) < s->length()){
lhs = s->substr(0, i);
rhs = s->substr(i+2, s->length());
// separate intermediate and final variables
if (s->substr(0, tag.length()) == tag){
// add to table of intermediate variables
lvar.push_back(lhs);
mvar[lhs] = "(" + rhs + ")";
} else {
// add to table of final variables
leqn.push_back(lhs);
meqn[lhs] = rhs + ";";
}
} else {
std::cerr << std::endl
<< "warning: non-assignment -- ignoring"
<< std::endl
<< '\t' << *s << std::endl
<< std::endl;
}
}
// expand rhs of intermediate variables
for (var = lvar.begin(); var != lvar.end(); var++){
loop.clear();
descend(*var);
}
// substitute expanded expressions into final equations
for (eqn = leqn.begin(); eqn != leqn.end(); eqn++){
for (var = lvar.begin(); var != lvar.end(); var++){
while ((i = meqn[*eqn].find(*var)) < meqn[*eqn].length()){
c = meqn[*eqn].c_str()[i + var->length()];
if (delim.find(c) < delim.length()){
meqn[*eqn].replace(i, var->length(), mvar[*var]);
}
}
}
}
}
std::ifstream &operator>> (std::ifstream &file, equations &e){
e.read(file);
return file;
}
std::ofstream &operator<< (std::ofstream &file, equations &e){
e.write(file);
return file;
}
parameter::parameter (std::string system_name){
name = system_name;
};
void
parameter::read (std::ifstream &file){
record_t r;
while (file >> r.variable >> r.component){
if (r.variable.find("#") == 0){
file.unsetf(ios::skipws);
char c = '\0';
while (c != '\n'){
file >> c;
}
file.setf(ios::skipws);
} else {
L.push_back(r);
}
}
}
void
parameter::write (std::ofstream &file){
std::list<record_t>::iterator i;
std::string type;
std::string value;
for (i = L.begin(); i != L.end(); i++){
if (i->variable.substr(0, 6) == "bool__"){
type = "bool";
value = "false";
} else if (i->variable.substr(0, 6) == "char__"){
type = "char";
value = "\0";
} else if (i->variable.substr(0, 8) == "double__"){
type = "double";
value = "1.0";
} else if (i->variable.substr(0, 7) == "float__"){
type = "float";
value = "1.0";
} else if (i->variable.substr(0, 5) == "int__"){
type = "int";
value = "1";
} else if (i->variable.substr(0, 7) == "string__"){
type = "std::string";
value = "hello world!";
} else {
type = "double";
value = "1.0";
}
file << "static " << type << "\t" << i->variable << " = " << value
<< ";\t// " << i->component << std::endl;
}
file << std::endl;
}
std::ifstream &operator>> (std::ifstream &file, parameter &p){
p.read(file);
return file;
}
std::ofstream &operator<< (std::ofstream &file, parameter &p){
p.write(file);
return file;
}
structure::structure (std::string system_name){
name = system_name;
};
void
structure::read (std::ifstream &file){
std::list<record_t> *p;
record_t r;
if (! file){
std::cerr << "warning: no structure data found (empty file)" << std::endl;
}
while (file >> r.vec >> r.num >> r.cmp >> r.fnm >> r.rpt){
if (r.vec == "input"){
p = &(this->Lu);
} else if (r.vec == "state"){
p = &(this->Lx);
} else if (r.vec == "output"){
p = &(this->Ly);
} else {
p = &(this->Lyz);
}
p->push_back(r);
}
};
void
structure::write (std::ofstream &file){
this->write_declare(file);
file << std::endl;
this->write_input(file);
file << std::endl;
this->write_logic(file);
file << std::endl;
this->write_state(file);
file << std::endl;
}
void
structure::write_declare (std::ofstream &file){
file << "const int mttNu\t= " << this->Lu.size() + 1 << ";" << std::endl
<< "const int mttNx\t= " << this->Lx.size() + 1 << ";" << std::endl
<< "const int mttNy\t= " << this->Ly.size() + 1 << ";" << std::endl
<< "static double mttu[mttNu];" << std::endl
<< "static double mttx[mttNx];" << std::endl
<< "static double mtty[mttNy];" << std::endl
<< "static double mttdx[mttNx];" << std::endl
<< std::endl;
}
void
structure::write_input (std::ofstream &file){
file << "void" << std::endl
<< this->name << "_input(const double t," << std::endl
<< "\tdouble *mttu," << std::endl
<< "\tdouble *mttx," << std::endl
<< "\tdouble *mtty)" << std::endl
<< "{" << std::endl;
for (i = Lu.begin(); i != Lu.end(); i++){
file << "\tmttu[" << i->num << "]\t= 1.0;"
<< "\t// " << i->cmp
<< "\t(" << i->fnm << ")" << std::endl;
}
file << "} // " << this->name << "_input" << std::endl;
}
void
structure::write_logic (std::ofstream &file){
file << "void" << std::endl
<< this->name << "_logic(const double t," << std::endl
<< "\tdouble *mttu," << std::endl
<< "\tdouble *mttx," << std::endl
<< "\tdouble *mttdx," << std::endl
<< "\tdouble *mtty)" << std::endl
<< "{" << std::endl;
for (i = Lx.begin(); i != Lx.end(); i++){
if (i->cmp == "MTT_SWITCH"){
file << "int " << i->fnm << " = 1;" << std::endl
<< "if ((" << i->fnm << " == 0)"
<< " || ((" << i->fnm << " < 0)"
<< " && (mttx[" << i->num << "] < 0.0))){" << std::endl
<< "\tmttx[" << i->num << "]\t = 0.0;" << std::endl
<< "\tmttdx[" << i->num << "]\t = 0.0;" << std::endl
<< "}" << std::endl;
}
}
file << "} // " << this->name << "_logic" << std::endl;
}
void
structure::write_state (std::ofstream &file){
file << "void" << std::endl
<< this->name << "_state(double *mttx)" << std::endl
<< "{" << std::endl;
for (i = Lx.begin(); i != Lx.end(); i++){
file << "\tmttx[" << i->num << "]\t= 0.0;"
<< "\t// " << i->cmp
<< "\t(" << i->fnm << ")" << std::endl;
}
file << "} // " << this->name << "_state" << std::endl;
}
std::ifstream &operator>> (std::ifstream &file, structure &s){
s.read(file);
return file;
}
std::ofstream &operator<< (std::ofstream &file, structure &s){
s.write(file);
return file;
}
};
void
usage(const char *program){
std::cerr << std::endl
<< "usage: " << program << " system" << std::endl
<< std::endl;
}
int main(int argc, char *argv[])
{
// check usage
if (argc != 2){
usage(argv[0]);
return 1;
}
std::string system_name = argv[1];
// open files for reading and writing
std::string cr_filename = system_name + "_cr.txt";
std::string parameter_filename = system_name + "_sympar.txt";
std::string structure_filename = system_name + "_struc.txt";
std::string equations_filename = system_name + "_ese.r";
std::string cxxsim_filename = system_name + "_cxxsim.cc";
std::ifstream cr_file (cr_filename.c_str());
std::ifstream parameter_file(parameter_filename.c_str());
std::ifstream structure_file(structure_filename.c_str());
std::ifstream equations_file(equations_filename.c_str());
std::ofstream cxxsim_file(cxxsim_filename.c_str());
// announce transformation
std::clog << "Creating " << cxxsim_filename << std::endl;
// do transformations (abracadabra!)
cxxsim::cr system_cr (system_name);
cxxsim::parameter system_parameter(system_name);
cxxsim::structure system_structure(system_name);
cxxsim::equations system_equations(system_name);
cr_file >> system_cr;
parameter_file >> system_parameter;
structure_file >> system_structure;
equations_file >> system_equations;
cxxsim_file << system_cr
<< system_parameter
<< system_structure
<< system_equations
<< std::endl;
cxxsim_file << std::endl
<< "int" << std::endl
<< "main(void){" << std::endl
<< std::endl
<< " double mttdt = 0.1; // integration time step" << std::endl
<< " double mttt;" << std::endl
<< " int i;" << std::endl
<< std::endl
<< " for (mttt = 0.0; mttt <= 10.0; mttt += mttdt){" << std::endl
<< std::endl
<< " // get inputs and rates" << std::endl
<< " " << system_name << "_input(mttt,mttu,mttx,mtty);" << std::endl
<< " " << system_name << "_ode(mttt,mttu,mttx,mttdx,mtty);" << std::endl
<< std::endl
<< " // integrate states (euler)" << std::endl
<< " for (i = 1; i < mttNx; i++){" << std::endl
<< " mttx[i] += mttdx[i] * mttdt;" << std::endl
<< " }" << std::endl
<< std::endl
<< " // overwrite switch states" << std::endl
<< " " << system_name << "_logic(mttt,mttu,mttx,mttdx,mtty);" << std::endl
<< std::endl
<< " // write: time outputs time states" << std::endl
<< " std::cout << mttt << '\\t';" << std::endl
<< " for (i = 1; i < mttNy; i++){" << std::endl
<< " std::cout << mtty[i] << ' ';" << std::endl
<< " }" << std::endl
<< " std::cout << '\\t' << mttt;" << std::endl
<< " for (i = 1; i < mttNx; i++){" << std::endl
<< " std::cout << ' ' << mttx[i];" << std::endl
<< " }" << std::endl
<< " std::cout << std::endl;" << std::endl
<< " }" << std::endl
<< " return 0;" << std::endl
<< "}" << std::endl;
// close files
cr_file.close();
parameter_file.close();
structure_file.close();
equations_file.close();
cxxsim_file.close();
return 0;
}