Geant4 Cross Reference |
1 // 1 2 // ******************************************* 3 // * License and Disclaimer 4 // * 5 // * The Geant4 software is copyright of th 6 // * the Geant4 Collaboration. It is provided 7 // * conditions of the Geant4 Software License 8 // * LICENSE and available at http://cern.ch/ 9 // * include a list of copyright holders. 10 // * 11 // * Neither the authors of this software syst 12 // * institutes,nor the agencies providing fin 13 // * work make any representation or warran 14 // * regarding this software system or assum 15 // * use. Please see the license in the file 16 // * for the full disclaimer and the limitatio 17 // * 18 // * This code implementation is the result 19 // * technical work of the GEANT4 collaboratio 20 // * By using, copying, modifying or distri 21 // * any work based on the software) you ag 22 // * use in resulting scientific publicati 23 // * acceptance of all terms of the Geant4 Sof 24 // ******************************************* 25 // 26 #include "G4UIparsing.hh" 27 28 #include "G4UIcommand.hh" 29 #include "G4UIparameter.hh" 30 #include "G4UItokenNum.hh" 31 32 using namespace G4UItokenNum; 33 34 namespace 35 { 36 class G4UIRangeChecker 37 { 38 public: 39 G4bool DoCheck(const G4UIparameter& p, con 40 G4bool DoCheck(const G4UIcommand& cmd, con 41 42 private: 43 G4bool RangeCheckImpl(const char* newValue 44 45 // returns the index of the var name 46 unsigned IndexOf(const char* nam); 47 48 // returns 1 or 0 49 unsigned IsParameter(const char* nam); 50 51 // --- the following is used by CheckNewVa 52 using yystype = G4UItokenNum::yystype; 53 using tokenNum = G4UItokenNum::tokenNum; 54 55 // syntax nodes 56 yystype Expression(); 57 yystype LogicalORExpression(); 58 yystype LogicalANDExpression(); 59 yystype EqualityExpression(); 60 yystype RelationalExpression(); 61 yystype AdditiveExpression(); 62 yystype MultiplicativeExpression(); 63 yystype UnaryExpression(); 64 yystype PrimaryExpression(); 65 // semantics routines 66 G4int Eval2(const yystype& arg1, G4int op, 67 // utility 68 tokenNum Yylex(); // returns next token 69 G4int G4UIpGetc(); // read one char from 70 G4int G4UIpUngetc(G4int c); // put back 71 G4int Follow(G4int expect, G4int ifyes, G4 72 73 private: 74 // Data from param/cmd 75 G4String rangeExpression; 76 G4String commandName; 77 std::vector<const G4UIparameter*> paramete 78 79 //------------ CheckNewValue() related dat 80 G4int bp = 0; // current index in rangeEx 81 tokenNum token = G4UItokenNum::NONE; 82 yystype yylval; 83 std::vector<yystype> newVal; 84 G4int paramERR = 0; 85 }; 86 87 // ------------------------------------------- 88 // INLINE DEFINITIONS 89 // ------------------------------------------- 90 inline G4bool G4UIRangeChecker::DoCheck(const 91 { 92 // Copy data needed from parameter 93 rangeExpression = p.GetParameterRange(); 94 95 commandName = p.GetParameterName(); 96 parameter.resize(1); 97 newVal.resize(1); 98 parameter[0] = &p; 99 100 return RangeCheckImpl(newValue); 101 } 102 103 inline G4bool G4UIRangeChecker::DoCheck(const 104 { 105 // Copy data needed from cmd 106 rangeExpression = cmd.GetRange(); 107 108 commandName = cmd.GetCommandName(); 109 parameter.resize(cmd.GetParameterEntries()); 110 newVal.resize(parameter.size()); 111 for (G4int i = 0; i < (G4int)parameter.size( 112 parameter[i] = cmd.GetParameter(i); 113 } 114 115 return RangeCheckImpl(newValue); 116 } 117 118 inline G4bool G4UIRangeChecker::RangeCheckImpl 119 { 120 if (rangeExpression.empty()) { 121 return true; 122 } 123 124 yystype result; 125 bp = 0; // reset buffer pointer for G4UIpGe 126 std::istringstream is(newValue); 127 for (unsigned i = 0; i < parameter.size(); + 128 char type = (char)std::toupper(parameter[i 129 switch (type) { 130 case 'D': 131 is >> newVal[i].D; 132 break; 133 case 'I': 134 is >> newVal[i].I; 135 break; 136 case 'L': 137 is >> newVal[i].L; 138 break; 139 case 'S': 140 is >> newVal[i].S; 141 break; 142 case 'B': 143 is >> newVal[i].C; 144 break; 145 default:; 146 } 147 } 148 token = Yylex(); 149 result = Expression(); 150 151 if (paramERR == 1) { 152 return false; 153 } 154 if (result.type != CONSTINT) { 155 G4cerr << "Illegal Expression in parameter 156 return false; 157 } 158 if (result.I != 0) { 159 return true; 160 } 161 G4cerr << "parameter out of range: " << rang 162 return false; 163 } 164 165 inline unsigned G4UIRangeChecker::IndexOf(cons 166 { 167 for (unsigned i = 0; i < parameter.size(); + 168 if (parameter[i]->GetParameterName() == na 169 return i; 170 } 171 } 172 paramERR = 1; 173 G4cerr << "parameter name:" << nam << " not 174 return 0; 175 } 176 177 inline unsigned G4UIRangeChecker::IsParameter( 178 { 179 for (auto& i : parameter) { 180 if (i->GetParameterName() == nam) { 181 return 1; 182 } 183 } 184 return 0; 185 } 186 187 // ------------------ syntax node functions - 188 189 inline yystype G4UIRangeChecker::Expression() 190 { 191 return LogicalORExpression(); 192 } 193 194 // ------------------------------------------- 195 inline yystype G4UIRangeChecker::LogicalORExpr 196 { 197 yystype result; 198 yystype p = LogicalANDExpression(); 199 if (token != LOGICALOR) { 200 return p; 201 } 202 if (p.type == CONSTSTRING || p.type == IDENT 203 G4cerr << "Parameter range: illegal type a 204 paramERR = 1; 205 } 206 result.I = p.I; 207 while (token == LOGICALOR) { 208 token = Yylex(); 209 p = LogicalANDExpression(); 210 if (p.type == CONSTSTRING || p.type == IDE 211 G4cerr << "Parameter range: illegal type 212 paramERR = 1; 213 } 214 switch (p.type) { 215 case CONSTINT: 216 result.I += p.I; 217 result.type = CONSTINT; 218 break; 219 case CONSTLONG: 220 result.I += static_cast<int>(p.L != 0L 221 result.type = CONSTINT; 222 break; 223 case CONSTDOUBLE: 224 result.I += static_cast<int>(p.D != 0. 225 result.type = CONSTINT; 226 break; 227 default: 228 G4cerr << "Parameter range: unknown ty 229 paramERR = 1; 230 } 231 } 232 return result; 233 } 234 235 // ------------------------------------------- 236 inline yystype G4UIRangeChecker::LogicalANDExp 237 { 238 yystype result; 239 yystype p = EqualityExpression(); 240 if (token != LOGICALAND) { 241 return p; 242 } 243 if (p.type == CONSTSTRING || p.type == IDENT 244 G4cerr << "Parameter range: illegal type a 245 paramERR = 1; 246 } 247 result.I = p.I; 248 while (token == LOGICALAND) { 249 token = Yylex(); 250 p = EqualityExpression(); 251 if (p.type == CONSTSTRING || p.type == IDE 252 G4cerr << "Parameter range: illegal type 253 paramERR = 1; 254 } 255 switch (p.type) { 256 case CONSTINT: 257 result.I *= p.I; 258 result.type = CONSTINT; 259 break; 260 case CONSTLONG: 261 result.I *= static_cast<int>(p.L != 0L 262 result.type = CONSTINT; 263 break; 264 case CONSTDOUBLE: 265 result.I *= static_cast<int>(p.D != 0. 266 result.type = CONSTINT; 267 break; 268 default: 269 G4cerr << "Parameter range: unknown ty 270 paramERR = 1; 271 } 272 } 273 return result; 274 } 275 276 // ------------------------------------------- 277 inline yystype G4UIRangeChecker::EqualityExpre 278 { 279 yystype arg1, arg2; 280 G4int operat; 281 yystype result = RelationalExpression(); 282 if (token == EQ || token == NE) { 283 operat = token; 284 token = Yylex(); 285 arg1 = result; 286 arg2 = RelationalExpression(); 287 result.I = Eval2(arg1, operat, arg2); // 288 result.type = CONSTINT; 289 } 290 else { 291 if (result.type != CONSTINT && result.type 292 G4cerr << "Parameter range: error at Equ 293 paramERR = 1; 294 } 295 } 296 return result; 297 } 298 299 // ------------------------------------------- 300 inline yystype G4UIRangeChecker::RelationalExp 301 { 302 yystype arg1, arg2; 303 G4int operat; 304 yystype result; 305 306 arg1 = AdditiveExpression(); 307 if (token == GT || token == GE || token == L 308 operat = token; 309 token = Yylex(); 310 arg2 = AdditiveExpression(); 311 result.I = Eval2(arg1, operat, arg2); // 312 result.type = CONSTINT; 313 } 314 else { 315 result = std::move(arg1); 316 } 317 return result; 318 } 319 320 // ------------------------------------------- 321 inline yystype G4UIRangeChecker::AdditiveExpre 322 { 323 yystype result = MultiplicativeExpression(); 324 if (token != '+' && token != '-') { 325 return result; 326 } 327 G4cerr << "Parameter range: operator " << (c 328 paramERR = 1; 329 return result; 330 } 331 332 // ------------------------------------------- 333 inline yystype G4UIRangeChecker::Multiplicativ 334 { 335 yystype result = UnaryExpression(); 336 if (token != '*' && token != '/' && token != 337 return result; 338 } 339 G4cerr << "Parameter range: operator " << (c 340 paramERR = 1; 341 return result; 342 } 343 344 // ------------------------------------------- 345 inline yystype G4UIRangeChecker::UnaryExpressi 346 { 347 yystype result; 348 yystype p; 349 switch (token) { 350 case '-': 351 token = Yylex(); 352 p = UnaryExpression(); 353 if (p.type == CONSTINT) { 354 result.I = -p.I; 355 result.type = CONSTINT; 356 } 357 if (p.type == CONSTLONG) { 358 result.L = -p.L; 359 result.type = CONSTLONG; 360 } 361 if (p.type == CONSTDOUBLE) { 362 result.D = -p.D; 363 result.type = CONSTDOUBLE; 364 } 365 break; 366 case '+': 367 token = Yylex(); 368 result = UnaryExpression(); 369 break; 370 case '!': 371 token = Yylex(); 372 G4cerr << "Parameter range error: " 373 << "operator '!' is not supported 374 paramERR = 1; 375 result = UnaryExpression(); 376 break; 377 default: 378 result = PrimaryExpression(); 379 } 380 return result; 381 } 382 383 // ------------------------------------------- 384 inline yystype G4UIRangeChecker::PrimaryExpres 385 { 386 yystype result; 387 switch (token) { 388 case IDENTIFIER: 389 result.S = yylval.S; 390 result.type = token; 391 token = Yylex(); 392 break; 393 case CONSTINT: 394 result.I = yylval.I; 395 result.type = token; 396 token = Yylex(); 397 break; 398 case CONSTLONG: 399 result.L = yylval.L; 400 result.type = token; 401 token = Yylex(); 402 break; 403 case CONSTDOUBLE: 404 result.D = yylval.D; 405 result.type = token; 406 token = Yylex(); 407 break; 408 case '(': 409 token = Yylex(); 410 result = Expression(); 411 if (token != ')') { 412 G4cerr << " ')' expected" << G4endl; 413 paramERR = 1; 414 } 415 token = Yylex(); 416 break; 417 default: 418 return result; 419 } 420 return result; // never executed 421 } 422 423 //---------------- semantic routines --------- 424 425 inline G4int G4UIRangeChecker::Eval2(const yys 426 { 427 if ((arg1.type != IDENTIFIER) && (arg2.type 428 G4cerr << commandName << ": meaningless co 429 << G4int(arg2.type) << G4endl; 430 paramERR = 1; 431 } 432 433 // Might want to also disallow comparison of 434 435 char newValtype; 436 if (arg1.type == IDENTIFIER) { 437 unsigned i = IndexOf(arg1.S); 438 newValtype = (char)std::toupper(parameter[ 439 switch (newValtype) { 440 case 'I': 441 if (arg2.type == CONSTINT) { 442 return G4UIparsing::CompareInt(newVa 443 //================================== 444 // MA - 2018.07.23 445 } 446 else if (arg2.type == IDENTIFIER) { 447 unsigned iii = IndexOf(arg2.S); 448 char newValtype2 = (char)std::touppe 449 if (newValtype2 == 'I') { 450 return G4UIparsing::CompareInt(new 451 } 452 if (newValtype2 == 'L') { 453 G4cerr << "Warning : Integer is co 454 return G4UIparsing::CompareLong(ne 455 } 456 if (newValtype2 == 'D') { 457 G4cerr << "Warning : Integer is co 458 return G4UIparsing::CompareDouble( 459 } 460 //================================== 461 } 462 else { 463 G4cerr << "integer operand expected 464 } 465 break; 466 case 'L': 467 if (arg2.type == CONSTINT) { 468 return G4UIparsing::CompareLong(newV 469 } 470 else if (arg2.type == CONSTLONG) { 471 return G4UIparsing::CompareLong(newV 472 } 473 else if (arg2.type == IDENTIFIER) { 474 unsigned iii = IndexOf(arg2.S); 475 char newValtype2 = (char)std::touppe 476 if (newValtype2 == 'I') { 477 return G4UIparsing::CompareLong(ne 478 } 479 if (newValtype2 == 'L') { 480 return G4UIparsing::CompareLong(ne 481 } 482 if (newValtype2 == 'D') { 483 G4cerr << "Warning : Long int is c 484 return G4UIparsing::CompareDouble( 485 } 486 //================================== 487 } 488 else { 489 G4cerr << "integer operand expected 490 } 491 break; 492 case 'D': 493 if (arg2.type == CONSTDOUBLE) { 494 return G4UIparsing::CompareDouble(ne 495 } 496 else if (arg2.type == CONSTINT) { // 497 return G4UIparsing::CompareDouble(ne 498 //================================== 499 // MA - 2018.07.23 500 } 501 else if (arg2.type == CONSTLONG) { 502 return G4UIparsing::CompareDouble(ne 503 } 504 else if (arg2.type == IDENTIFIER) { 505 unsigned iii = IndexOf(arg2.S); 506 char newValtype2 = (char)std::touppe 507 if (newValtype2 == 'I') { 508 return G4UIparsing::CompareDouble( 509 } 510 if (newValtype2 == 'L') { 511 return G4UIparsing::CompareDouble( 512 } 513 if (newValtype2 == 'D') { 514 return G4UIparsing::CompareDouble( 515 } 516 //================================== 517 } 518 break; 519 default:; 520 } 521 } 522 if (arg2.type == IDENTIFIER) { 523 unsigned i = IndexOf(arg2.S); 524 newValtype = (char)std::toupper(parameter[ 525 switch (newValtype) { 526 case 'I': 527 if (arg1.type == CONSTINT) { 528 return G4UIparsing::CompareInt(arg1. 529 } 530 else { 531 G4cerr << "integer operand expected 532 } 533 break; 534 case 'L': 535 if (arg1.type == CONSTLONG) { 536 return G4UIparsing::CompareLong(arg1 537 } 538 else { 539 G4cerr << "long int operand expected 540 } 541 break; 542 case 'D': 543 if (arg1.type == CONSTDOUBLE) { 544 return G4UIparsing::CompareDouble(ar 545 } 546 else if (arg1.type == CONSTINT) { // 547 return G4UIparsing::CompareDouble(ar 548 } 549 break; 550 default:; 551 } 552 } 553 return 0; 554 } 555 556 // --------------------- utility functions --- 557 558 inline tokenNum G4UIRangeChecker::Yylex() // 559 { // (returns EOF) 560 G4int c; 561 G4String buf; 562 563 while ((c = G4UIpGetc()) == ' ' || c == '\t' 564 ; 565 } 566 if (c == EOF) { 567 return (tokenNum)EOF; // KR488 568 } 569 buf = ""; 570 if ((isdigit(c) != 0) || c == '.') { // I o 571 do { 572 buf += (unsigned char)c; 573 c = G4UIpGetc(); 574 } while (c == '.' || (isdigit(c) != 0) || 575 G4UIpUngetc(c); 576 const char* t = buf; 577 std::istringstream is(t); 578 if (G4UIparsing::IsInt(buf.data(), 20)) { 579 is >> yylval.I; 580 return CONSTINT; 581 } 582 if (G4UIparsing::IsDouble(buf.data())) { 583 is >> yylval.D; 584 return CONSTDOUBLE; 585 } 586 587 G4cerr << buf << ": numeric format error." 588 } 589 buf = ""; 590 if ((isalpha(c) != 0) || c == '_') { // IDE 591 do { 592 buf += (unsigned char)c; 593 } while ((c = G4UIpGetc()) != EOF && ((isa 594 G4UIpUngetc(c); 595 if (IsParameter(buf) != 0u) { 596 yylval.S = std::move(buf); 597 return IDENTIFIER; 598 } 599 600 G4cerr << buf << " is not a parameter name 601 paramERR = 1; 602 } 603 switch (c) { 604 case '>': 605 return (tokenNum)Follow('=', GE, GT); 606 case '<': 607 return (tokenNum)Follow('=', LE, LT); 608 case '=': 609 return (tokenNum)Follow('=', EQ, '='); 610 case '!': 611 return (tokenNum)Follow('=', NE, '!'); 612 case '|': 613 return (tokenNum)Follow('|', LOGICALOR, 614 case '&': 615 return (tokenNum)Follow('&', LOGICALAND, 616 default: 617 return (tokenNum)c; 618 } 619 } 620 621 // ------------------------------------------- 622 inline G4int G4UIRangeChecker::Follow(G4int ex 623 { 624 G4int c = G4UIpGetc(); 625 if (c == expect) { 626 return ifyes; 627 } 628 G4UIpUngetc(c); 629 return ifno; 630 } 631 632 //------------------ low level routines ------ 633 634 inline G4int G4UIRangeChecker::G4UIpGetc() 635 { // emulation of getc() 636 std::size_t length = rangeExpression.length( 637 if (bp < (G4int)length) { 638 return rangeExpression[bp++]; 639 } 640 641 return EOF; 642 } 643 644 // ------------------------------------------- 645 inline G4int G4UIRangeChecker::G4UIpUngetc(G4i 646 { // emulation of ungetc() 647 if (c < 0) { 648 return -1; 649 } 650 if (bp > 0 && c == rangeExpression[bp - 1]) 651 --bp; 652 } 653 else { 654 paramERR = 1; 655 return -1; 656 } 657 return 0; 658 } 659 } // namespace 660 661 namespace G4UIparsing 662 { 663 G4bool RangeCheck(const G4UIparameter& p, cons 664 { 665 G4UIRangeChecker r; 666 return r.DoCheck(p, value); 667 } 668 669 G4bool RangeCheck(const G4UIcommand& p, const 670 { 671 G4UIRangeChecker r; 672 return r.DoCheck(p, value); 673 } 674 } // namespace G4UIRangeCheck 675