Page MenuHomec4science

lm_parser.cc
No OneTemporary

File Metadata

Created
Thu, Jul 25, 08:27

lm_parser.cc

/**
* @file lm_parser.cc
*
* @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
*
* @date Wed Jul 02 16:25:38 2014
*
* @brief This is the central parser for LM
*
* @section LICENSE
*
* Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
* Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
*
* LibMultiScale is free software: you can redistribute it and/or modify it
* under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* LibMultiScale 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 Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with LibMultiScale. If not, see <http://www.gnu.org/licenses/>.
*
*/
/* -------------------------------------------------------------------------- */
#include "lm_parser.hh"
#include "coupler_manager.hh"
#include "domain_multiscale.hh"
#include "factory_multiscale.hh"
#include "filter_interface.hh"
#include "lm_common.hh"
#include "lm_parsable.hh"
#include <unistd.h>
/* -------------------------------------------------------------------------- */
__BEGIN_LIBMULTISCALE__
/* -------------------------------------------------------------------------- */
std::string Parser::getCurrentConfigFile() { return opened_files.back(); }
/* -------------------------------------------------------------------------- */
UInt Parser::getCurrentLine() { return current_line.back(); }
/* -------------------------------------------------------------------------- */
// void Parser::parseGeometry(GeomID & g,stringstream & line){
// parseString(g,line);
// __attribute__((unused)) Geometry * geom =
// GeometryManager::getManager().getGeometry(g);
//}
/* -------------------------------------------------------------------------- */
void Parser::freeMemory() {
// math_parser.free_memory();
// DUMPFILE(fout,"memory cleaned");
fout.close();
}
/* -------------------------------------------------------------------------- */
void Parser::getLine(std::ifstream &file, std::string &line,
UInt &current_line) {
line = "";
std::string tmp_line;
getline(file, tmp_line);
size_t found = tmp_line.find("\\");
++current_line;
while (found != std::string::npos) {
line += tmp_line.substr(0, found - 1);
getline(file, tmp_line);
found = tmp_line.find("\\");
++current_line;
}
line += tmp_line;
}
/* -------------------------------------------------------------------------- */
void Parser::rewindToLine(UInt line) {
DUMPFILE(Parser::fout, "rewind to line" << line);
std::ifstream &f = *opened_ifstreams.back();
f.seekg(0, std::ios_base::beg);
std::string buffer;
current_line.back() = 0;
for (UInt i = 0; i < line - 1; ++i) {
Parser::getLine(f, buffer, current_line.back());
if (current_line.back() == line - 1)
break;
}
}
/* -------------------------------------------------------------------------- */
void Parser::parseConfigFile(const std::string &file,
const std::string &section_name,
const std::string &section_id, Parsable &obj) {
std::ifstream f;
f.open(file.c_str());
if (!f.is_open()) {
LM_FATAL("could not open config file " << file);
}
/// put the current file to stack
opened_files.push_back(file);
current_line.push_back(0);
opened_ifstreams.push_back(&f);
DUMP("parser state " << Parser::getParserState(), DBG_INFO);
std::string buffer;
bool section_flag = false;
bool found_section = false;
std::string mot;
units_converter.setOutUnits(code_unit_system);
// section_units.push_back(si_unit_system);
while (f.good()) {
Parser::getLine(f, buffer, current_line.back());
DUMP("treat line " << current_line.back(), DBG_DETAIL);
unsigned long found = buffer.find_first_of("#");
std::string buffer_comment_free = buffer.substr(0, found - 1);
buffer = buffer_comment_free;
/* si il s'agit d'un commentaire on ne fait rien */
if (buffer[0] == '#' || buffer == "") {
continue;
}
std::stringstream line(buffer);
try {
Parser::strNext(mot, line);
} catch (LibMultiScaleException &e) {
DUMP("Parser exception " << e.what() << std::endl
<< getParserState(),
DBG_WARNING);
continue;
}
if (!section_flag && mot == "Section") {
Parser::strNext(mot, line);
// search for ":"
size_t pos = mot.find(":");
std::string id;
std::string sec_name;
if (pos != std::string::npos) {
id = mot.substr(pos + 1);
sec_name = mot.substr(0, pos);
} else
sec_name = mot;
if (section_name == sec_name && id == section_id) {
section_flag = true;
found_section = true;
UnitSystem units;
try {
Parser::parse(units, line);
} catch (LibMultiScaleException &e) {
LM_FATAL("unit system was not provided for section " << section_name);
}
section_units.push_back(units);
units_converter.setInUnits(section_units.back());
units_converter.computeConversions();
continue;
}
}
if (section_flag && mot == "endSection") {
section_flag = false;
section_units.pop_back();
if (section_units.size() > 0)
units_converter.setInUnits(section_units.back());
units_converter.computeConversions();
}
if (section_flag) {
substituteVariables(buffer);
UInt result = parseGenericKeywords(buffer, obj);
if (!result)
result = obj.parseLine(buffer);
if (!result)
LM_FATAL("not parsed line " << buffer);
}
}
// if (section_units.back() != si_unit_system)
// LM_FATAL("problem in piling the section units");
if (!found_section)
LM_FATAL("section named " << section_name << " with id " << section_id
<< " is missing");
/// pop the current file from stack
opened_files.pop_back();
current_line.pop_back();
if (section_units.size() > 0)
units_converter.setInUnits(section_units.back());
units_converter.computeConversions();
opened_ifstreams.pop_back();
DUMP("parser state " << opened_files.size() << " " << current_line.size()
<< " " << Parser::getParserState(),
DBG_INFO);
}
/* -------------------------------------------------------------------------- */
void Parser::substituteVariables(std::string &str) {
size_t pos = str.find("${");
while (pos != std::string::npos) {
size_t pos2 = str.find("}", pos);
if (pos2 == std::string::npos)
LM_FATAL("syntax error: unclosed ${ } sequence \n"
<< Parser::getParserState());
std::string varname = str.substr(pos + 2, pos2 - pos - 2);
Real res;
try {
math_parser.parse(varname, res);
} catch (std::string mess) {
LM_FATAL(getParserState() << std::endl
<< "\"" << str << "\"" << std::endl
<< mess);
}
std::stringstream tmp;
tmp << res;
str.replace(pos, pos2 - pos + 1, tmp.str());
pos = str.find("${");
}
pos = str.find("$(");
while (pos != std::string::npos) {
size_t pos2 = str.find(")", pos);
if (pos2 == std::string::npos)
LM_FATAL("syntax error: unclosed $( ) sequence");
std::string varname = str.substr(pos + 2, pos2 - pos - 2);
char *var = lm_getenv(varname.c_str());
if (var != NULL)
str.replace(pos, pos2 - pos + 1, var);
else
LM_FATAL(getParserState()
<< std::endl
<< "\"" << str << "\"" << std::endl
<< "environment variable " << varname << " was not defined");
pos = str.find("$(");
}
}
/* -------------------------------------------------------------------------- */
UInt Parser::parseGenericKeywords(std::string &linebuffer, Parsable &obj) {
std::stringstream line(linebuffer);
std::string mot;
Parser::strNext(mot, line);
if (mot == "LET") {
std::stringstream var_buffer;
try {
while (1) {
std::string mot;
strNext(mot, line);
var_buffer << mot << " ";
}
} catch (UnableToParseWord &e) {
} catch (LibMultiScaleException &e) {
LM_FATAL_RE(e, std::endl << getParserState());
}
try {
Real res;
math_parser.parse(var_buffer.str(), res);
} catch (LibMultiScaleException &e) {
LM_FATAL_RE(e, std::endl
<< getParserState()
<< " cannot parse algebraic expression "
<< var_buffer.str());
}
return true;
} else if (mot == "PRINT") {
Real value;
if (math_parser.parse(line.str().substr(line.tellg()), value)) {
std::string key;
line >> key;
DUMPFILE(fout, key << " = " << value);
} else
return false;
return true;
} else if (mot == "INCLUDE") {
Parser::strNext(mot, line);
if (mot == "this") {
mot = opened_files.back();
}
std::string section;
try {
strNext(section, line);
} catch (LibMultiScaleException &e) {
LM_FATAL(" Missing section name in line " << current_line.back() << ": '"
<< line.str() << "'"
<< getParserState());
}
try {
std::string id;
strNext(id, line);
parseConfigFile(mot, section, id, obj);
} catch (LibMultiScaleException &e) {
parseConfigFile(mot, section, "", obj);
}
return true;
} else if (mot == "FOR") {
std::string mot;
// save starting point
for_starting_line.push_back(current_line.back() + 1);
Parser::strNext(mot, line);
// read name of the for variable
for_var.push_back(mot);
Parser::strNext(mot, line);
UInt pos = line.tellg();
if (mot != "in" || pos == line.str().length())
LM_FATAL(getParserState() << std::endl
<< "\"" << line.str() << "\"" << std::endl
<< "sytax error in for loop");
// construct the items to iterate
std::string buffer = line.str().substr(pos);
std::stringstream items(buffer);
Parser::strNext(mot, items);
std::list<std::string> item_vec;
if (mot == "range") {
UInt start, end, increment;
parse(start, items);
parse(end, items);
parse(increment, items);
for (UInt i = start; i < end; i += increment) {
std::stringstream sstr;
sstr << i;
item_vec.push_back(sstr.str());
}
} else {
while (!items.fail()) {
item_vec.push_back(mot);
try {
Parser::strNext(mot, items);
} catch (LibMultiScaleException &e) {
}
}
}
for_items.push_back(item_vec);
std::string value;
value = for_items.back().front();
for_items.back().pop_front();
// set the variable to the correct initial value
Real res;
math_parser.parse(for_var.back() + " = " + value, res);
return true;
} else if (mot == "endFOR") {
UInt nb_items_left = for_items.back().size();
// set the variable to the next value
if (nb_items_left == 0) {
// it is the end of the loop then
math_parser.eraseVariable(for_var.back());
for_starting_line.pop_back();
for_items.pop_back();
for_var.pop_back();
} else {
std::string value;
value = for_items.back().front();
for_items.back().pop_front();
DUMPFILE(Parser::fout, "inside of var loop " << for_var.back()
<< " now takes the value "
<< value);
// set the variable to the correct initial value
Real res;
math_parser.parse(for_var.back() + " = " + value, res);
// rewind the file to the correct line
rewindToLine(for_starting_line.back());
}
return true;
}
return false;
}
/* -------------------------------------------------------------------------- */
inline std::string Parser::getParserState() {
std::stringstream res;
// char cwd[512];
// std::fill(cwd, cwd + 512, 0);
std::string cwd = getcwd(nullptr, 0);
for (auto &&[file, line] : zip(opened_files, current_line)) {
res << cwd << "/" << file << ":" << line << ":" << std::endl;
}
return res.str();
}
/* -------------------------------------------------------------------------- */
std::map<std::string, double> &Parser::getAlgebraicVariables() {
return math_parser.getVariables();
}
/* -------------------------------------------------------------------------- */
UInt Parser::strNext(std::string &str, std::stringstream &line) {
UInt word_counter = 0;
line >> str;
if (line.fail())
throw UnableToParseWord();
++word_counter;
if (str[0] == '"') {
str = str.substr(1);
unsigned long found = str.find_first_of("\"");
while (found == std::string::npos) {
UInt pos = line.tellg();
if (pos < line.str().length()) {
std::string tmp_str;
line >> tmp_str;
if (line.fail())
LM_THROW("unable to parse word");
++word_counter;
str += " " + tmp_str;
found = str.find_first_of("\"");
} else
LM_FATAL("unterminated quoted sequence");
}
if (found != str.size() - 1)
LM_FATAL("quotes must be followed by a whitespace");
str = str.substr(0, found);
}
return word_counter;
}
/* -------------------------------------------------------------------------- */
void Parser::shiftLine(const ParseResult &parsed, std::stringstream &line) {
std::string buf;
for (UInt i = 0; i < parsed.nb_word_parsed; ++i) {
line >> buf;
if (line.fail())
LM_THROW("unable to shift " << parsed.nb_word_parsed << " words");
}
}
/* -------------------------------------------------------------------------- */
UInt _parse(Component &comp, std::stringstream &line, UInt) {
std::string buffer;
std::string component_name;
std::string output_name = "";
std::string input_name;
UInt nb = Parser::strNext(buffer, line);
auto &inputs = comp.getInputs();
auto pos = buffer.find("=");
if (pos != std::string::npos) {
input_name = buffer.substr(0, pos);
component_name = buffer.substr(pos + 1);
} else if (inputs.size() == 1) {
input_name = inputs.begin()->first;
component_name = buffer;
} else if (inputs.size() == 0) {
component_name = buffer;
LM_FATAL("has no input found while trying to connect " << component_name);
} else {
component_name = buffer;
std::string str = "Input connector was not specifically provided.\n";
str += "However " + component_name + " has several connectors:\n";
for (auto i : inputs) {
str += i.first + "\n";
}
LM_FATAL(str);
}
pos = component_name.find(".");
if (pos != std::string::npos) {
output_name = component_name.substr(pos + 1);
component_name = component_name.substr(0, pos);
}
DUMP(input_name << " " << component_name << " " << output_name, DBG_DETAIL);
auto &input_component = getRegisteredComponent(component_name);
if (&input_component == &comp)
LM_FATAL("cannot connect a component to himself " << comp.getID());
comp.connect(input_name, input_component, output_name);
return nb;
}
/* -------------------------------------------------------------------------- */
/// static instanciation
/* -------------------------------------------------------------------------- */
UnitsConverter Parser::units_converter;
std::vector<UnitSystem> Parser::section_units;
AlgebraicExpressionParser Parser::math_parser;
std::ofstream Parser::fout("log.parser", std::ios_base::out);
std::vector<std::string> Parser::opened_files;
std::vector<UInt> Parser::current_line;
std::vector<std::ifstream *> Parser::opened_ifstreams;
std::vector<UInt> Parser::for_starting_line;
std::vector<std::list<std::string>> Parser::for_items;
std::vector<std::string> Parser::for_var;
__END_LIBMULTISCALE__

Event Timeline