00001
00002
00003
00004 #include <iostream>
00005
00006
00007
00008 #include <boost/foreach.hpp>
00009 #include <boost/lexical_cast.hpp>
00010 #include <boost/format.hpp>
00011 #include <boost/shared_ptr.hpp>
00012
00013 #include "Analyzer.h"
00014 #include "Parser.h"
00015 #include "Messages.h"
00016 #include "Catalog.h"
00017 #include "Units.h"
00018 #include "PragmaOptions.h"
00019 #include "Node.h"
00020 #include "IncludedFiles.h"
00021 #include "PropertyName.h"
00022 #include "PropertyValue.h"
00023
00024 #include "GaudiKernel/Environment.h"
00025
00026 namespace gp = Gaudi::Parsers;
00027
00028 static bool IncludeNode(gp::Node* node,
00029 const std::string& search_path,
00030 gp::IncludedFiles* included, gp::Messages* messages) {
00031 gp::Node include_root;
00032 bool status = gp::Parse(node->position, node->value, search_path, included,
00033 messages, &include_root);
00034 if (status) {
00035 node->value = include_root.value;
00036 BOOST_FOREACH(const gp::Node& child, include_root.children) {
00037 node->children.push_back(child);
00038 }
00039 } else {
00040 return false;
00041 }
00042 return true;
00043 }
00044
00045 static bool UnitsNode(gp::Node* node,
00046 const std::string& search_path,
00047 gp::IncludedFiles* included, gp::Messages* messages) {
00048 gp::Node units_root;
00049 bool status = gp::ParseUnits(node->position, node->value, search_path,
00050 included, messages, &units_root);
00051 if (status) {
00052 node->value = units_root.value;
00053 BOOST_FOREACH(const gp::Node& child, units_root.children) {
00054 node->children.push_back(child);
00055 }
00056 } else {
00057 return false;
00058 }
00059 return true;
00060 }
00061
00062 static void GetPropertyName(const gp::Node* node,
00063 gp::PropertyName::ScopedPtr& property_name) {
00064 if (node->children.size() == 1) {
00065 property_name.reset(new gp::PropertyName(node->children[0].value,
00066 node->position));
00067 }else {
00068 std::string delim="";
00069 std::string client="";
00070 for(unsigned int i=0; i < (node->children.size() - 1); i++) {
00071 client += delim+node->children[i].value;
00072 delim = '.';
00073 }
00074 property_name.reset(new gp::PropertyName(client,
00075 node->children[node->children.size() - 1].value, node->position));
00076 }
00077 }
00078
00079 static void GetPropertyValue(const gp::Node* node,
00080 gp::PropertyValue::ScopedPtr& value, gp::Catalog* catalog,
00081 gp::Units* units) {
00082 switch (node->type) {
00083
00084 case gp::Node::kReal: {
00085
00086
00087
00088
00089
00090 if (node->children.size() == 1) {
00091
00092 std::string unit_name = node->children[0].value;
00093 double unit_value = 0;
00094 if (units->Find(unit_name, unit_value)) {
00095
00096 double val = boost::lexical_cast<double>(node->value);
00097 std::string store =
00098 boost::lexical_cast<std::string>(val * unit_value);
00099 value.reset(new gp::PropertyValue(store));
00100 }else {
00101
00102 throw
00103 gp::PositionalPropertyValueException::CouldNotFindUnit(
00104 node->children[0].position, unit_name);
00105 }
00106 }else {
00107 value.reset(new gp::PropertyValue(node->value));
00108 }
00109 break;
00110 }
00111
00112 case gp::Node::kString: {
00113 value.reset(new gp::PropertyValue('"'+node->value+'"'));
00114 break;
00115 }
00116
00117 case gp::Node::kBool: {
00118 value.reset(new gp::PropertyValue(node->value));
00119 break;
00120 }
00121
00122 case gp::Node::kVector: {
00123 std::vector<std::string> result;
00124 BOOST_FOREACH(const gp::Node& child, node->children) {
00125 gp::PropertyValue::ScopedPtr vvalue;
00126 GetPropertyValue(&child, vvalue, catalog, units);
00127 result.push_back(vvalue->ToString());
00128 }
00129 value.reset(new gp::PropertyValue(result));
00130 break;
00131 }
00132
00133 case gp::Node::kMap: {
00134 std::map<std::string, std::string> result;
00135 BOOST_FOREACH(const gp::Node& child, node->children) {
00136 gp::PropertyValue::ScopedPtr kvalue;
00137 gp::PropertyValue::ScopedPtr vvalue;
00138 GetPropertyValue(&child.children[0], kvalue, catalog, units);
00139 GetPropertyValue(&child.children[1], vvalue, catalog, units);
00140 result.insert(
00141 std::pair<std::string, std::string>(
00142 kvalue->ToString(),
00143 vvalue->ToString()));
00144 }
00145 value.reset(new gp::PropertyValue(result));
00146 break;
00147 }
00148
00149 case gp::Node::kProperty: {
00150 gp::PropertyName::ScopedPtr property;
00151 GetPropertyName(node, property);
00152 gp::Property* exists = NULL;
00153 if (NULL != (exists = catalog->Find(property->client(),
00154 property->property()))) {
00155 value.reset(new gp::PropertyValue(exists->property_value()));
00156 }else {
00157 throw
00158 gp::PositionalPropertyValueException::CouldNotFindProperty(
00159 node->position,property->ToString());
00160 }
00161 break;
00162 }
00163 case gp::Node::kPropertyRef: {
00164 gp::PropertyName::ScopedPtr property;
00165 GetPropertyName(node, property);
00166
00167 std::vector<std::string> reference;
00168 reference.push_back(property->client());
00169 reference.push_back(property->property());
00170
00171 value.reset(new gp::PropertyValue(reference,property->position(),
00172 true));
00173 break;
00174 }
00175
00176 default: {
00177 assert(false);
00178 break;
00179 }
00180 }
00181 }
00182
00183
00184 static std::string SignString(gp::Node::NodeType type) {
00185 switch (type) {
00186 case gp::Node::kEqual : {
00187 return "=";
00188 }
00189
00190 case gp::Node::kPlusEqual : {
00191 return "+=";
00192 }
00193
00194 case gp::Node::kMinusEqual : {
00195 return "-=";
00196 }
00197 default: {
00198 assert(false);
00199 break;
00200 }
00201 }
00202 return "unknown";
00203
00204 }
00205
00206 static bool AssignNode(const gp::Node* node,
00207 gp::Messages* messages, gp::Catalog* catalog, gp::Units* units,
00208 bool is_print) {
00209
00210 gp::PropertyName::ScopedPtr property;
00211 gp::PropertyValue::ScopedPtr value;
00212
00213 GetPropertyName(&node->children[0], property);
00214 try {
00215 GetPropertyValue(&node->children[2], value, catalog, units);
00216 }catch(const gp::PositionalPropertyValueException& ex){
00217 messages->AddError(ex.position(), ex.what());
00218 return false;
00219 }
00220
00221 gp::Property* exists = NULL;
00222 bool reassign = false;
00223
00224 if (NULL != (exists = catalog->Find(property->client(),
00225 property->property()))) {
00226
00227
00228
00229 try {
00230 if (node->children[1].type == gp::Node::kEqual) {
00231 std::string message = str(boost::format("Reassignment of option '%1%' .")
00232 % property->FullName());
00233 if (exists->HasDefinedPosition()) {
00234 message += " Previously defined at " +
00235 exists->DefinedPosition().ToString() + ".";
00236 }
00237 reassign = true;
00238 messages->AddWarning(node->position, message);
00239 }else if (node->children[1].type == gp::Node::kPlusEqual) {
00240 *exists += *value;
00241 }else if (node->children[1].type == gp::Node::kMinusEqual) {
00242 *exists -= *value;
00243 }
00244 }catch(const gp::PropertyValueException& ex) {
00245 std::string message = ex.what();
00246 if (exists->HasDefinedPosition()) {
00247 message += " Previously defined at "+exists->DefinedPosition().
00248 ToString()+".";
00249 }
00250 messages->AddError(node->position, message);
00251 return false;
00252 }
00253 }
00254
00255 bool result = true;
00256 if ( (NULL == exists) || reassign) {
00257 result = catalog->Add(new gp::Property(*property, *value));
00258 }
00259
00260 if (result && is_print) {
00261 std::string message = str(boost::format("%1% %2% %3%")
00262 % property->FullName()
00263 % SignString(node->children[1].type)
00264 % value->ToString());
00265 messages->AddInfo(node->position, message);
00266 }
00267 return result;
00268 }
00269
00270 static bool UnitNode(const gp::Node* node,
00271 gp::Messages* messages, gp::Units* units, bool is_print) {
00272
00273 double left = boost::lexical_cast<double>(node->children[0].value);
00274 std::string name = node->children[1].value;
00275 double right = boost::lexical_cast<double>(node->children[2].value);
00276
00277 gp::Units::Container::mapped_type exists;
00278 if (units->Find(name, exists)) {
00279 std::string message =
00280 str(boost::format("Unit '%1%' already defined") % name);
00281 if (exists.second.Exists()) {
00282 message += " at "+exists.second.ToString();
00283 }
00284 messages->AddError(node->children[1].position, message);
00285 return false;
00286 }
00287
00288 bool result = units->Add(name, right / left, node->children[1].position);
00289 if (result && is_print) {
00290 std::string message = str(boost::format("%1% %2% = %3%")
00291 % left
00292 % name
00293 % right);
00294 messages->AddInfo(node->position, message);
00295 }
00296 return result;
00297 }
00298
00299 static bool ConditionNode(gp::Node* node,
00300 gp::Catalog* catalog, gp::Node** next) {
00301
00302 gp::PropertyName::ScopedPtr property_name;
00303 GetPropertyName(&node->children[0], property_name);
00304
00305 bool is_defined = (NULL != catalog->Find(property_name->client(),
00306 property_name->property()));
00307
00308 if ((is_defined && (node->children[1].type == gp::Node::kIfdef))
00309 || (!is_defined && (node->children[1].type == gp::Node::kIfndef))
00310 ) {
00311 *next = &node->children[1];
00312 }else if (node->children.size()>2){
00313 *next = &node->children[2];
00314 } else{
00315 *next = NULL;
00316 }
00317 return true;
00318 }
00319
00320 static bool Analyze(gp::Node* node,
00321 const std::string& search_path, gp::IncludedFiles* included,
00322 gp::Messages* messages, gp::Catalog* catalog, gp::Units* units,
00323 gp::PragmaOptions* pragma) {
00324
00325 bool result = true;
00326 bool local_result = true;
00327 bool skip_childs = true;
00328 gp::Node* next_root = node;
00329
00330 switch (node->type) {
00331
00332 case gp::Node::kRoot: {
00333 skip_childs = false;
00334 break;
00335 }
00336
00337 case gp::Node::kInclude: {
00338 local_result = IncludeNode(node, search_path, included, messages);
00339 skip_childs = false;
00340 break;
00341 }
00342
00343 case gp::Node::kUnits: {
00344 local_result = UnitsNode(node, search_path, included, messages);
00345 skip_childs = false;
00346 break;
00347 }
00348
00349 case gp::Node::kAssign: {
00350 local_result = AssignNode(node, messages, catalog, units,
00351 pragma->is_print());
00352 break;
00353 }
00354
00355 case gp::Node::kUnit: {
00356 local_result = UnitNode(node, messages, units, pragma->is_print());
00357 break;
00358 }
00359
00360 case gp::Node::kCondition: {
00361 local_result = ConditionNode(node, catalog, &next_root);
00362 skip_childs = false;
00363 break;
00364 }
00365
00366 case gp::Node::kPrintOptions: {
00367 pragma->setIsPrintOptions(true);
00368 break;
00369 }
00370
00371 case gp::Node::kPrintOn : {
00372 pragma->setIsPrint(true);
00373 break;
00374 }
00375
00376 case gp::Node::kPrintOff : {
00377 pragma->setIsPrint(false);
00378 break;
00379 }
00380
00381 case gp::Node::kPrintTree : {
00382 pragma->setIsPrintTree(true);
00383 break;
00384 }
00385
00386 case gp::Node::kDumpFile : {
00387 std::string file="";
00388 if(System::resolveEnv(node->value, file)) {
00389 pragma->setDumpFile(file);
00390 } else {
00391 pragma->setDumpFile(node->value);
00392 }
00393 break;
00394 }
00395
00396 default: {
00397 break;
00398 }
00399 }
00400 if (result) result = local_result;
00401
00402 if (!skip_childs && (next_root!=NULL)) {
00403 BOOST_FOREACH(gp::Node& child, next_root->children) {
00404 local_result =
00405 Analyze(&child, search_path, included, messages, catalog, units,
00406 pragma);
00407 if (result) result = local_result;
00408 }
00409 }
00410 return result;
00411 }
00412
00413 bool Unreference(gp::Catalog& catalog, gp::Messages* messages) {
00414 bool unreference_result = true;
00415 BOOST_FOREACH(gp::Catalog::value_type& client, catalog) {
00416 for (gp::Catalog::CatalogSet::mapped_type::iterator current
00417 = client.second.begin(); current != client.second.end();
00418 ++current) {
00419 if (current->IsReference()) {
00420 gp::PropertyValue& value = current->property_value();
00421 std::vector<std::string> names = value.Vector();
00422
00423 gp::Property* property = catalog.Find(names[0], names[1]);
00424 if (NULL == property) {
00425 messages->AddError(value.position(),
00426 "Could not unreference " + current->ValueAsString());
00427 unreference_result = false;
00428 }else{
00429 value = property->property_value();
00430 }
00431 }
00432 }
00433 }
00434 return unreference_result;
00435 }
00436
00437
00438 bool gp::ReadOptions(const std::string& filename,
00439 const std::string& search_path, Messages* messages, Catalog* catalog,
00440 Units* units, PragmaOptions* pragma, Node* root) {
00441
00442 IncludedFiles included;
00443 bool result = Parse(filename, search_path, &included, messages, root);
00444 if (!result) return false;
00445
00446 bool result1 = Analyze(root, search_path, &included, messages, catalog, units,
00447 pragma);
00448 bool result2 = Unreference(*catalog, messages);
00449 return result1 && result2;
00450 }
00451
00452