ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4UIcommand.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4UIcommand.cc
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 // Author: Makoto Asai (SLAC)
27 // --------------------------------------------------------------------
28 
29 #include "G4UIcommand.hh"
30 #include "G4UImessenger.hh"
31 #include "G4UImanager.hh"
32 #include "G4UIcommandStatus.hh"
33 #include "G4StateManager.hh"
34 #include "G4UnitsTable.hh"
35 #include "G4Tokenizer.hh"
36 #include "G4ios.hh"
37 #include <sstream>
38 #include <iomanip>
39 
40 #include "G4UItokenNum.hh"
41 using namespace G4UItokenNum;
42 
44  : messenger(0), toBeBroadcasted(false), toBeFlushed(false), workerThreadOnly(false),
45  commandFailureCode(0), failureDescription(""),
46  bp(0), token(IDENTIFIER),paramERR(0)
47 {
48 }
49 
50 G4UIcommand::G4UIcommand(const char * theCommandPath,
51  G4UImessenger * theMessenger, G4bool tBB)
52 :messenger(theMessenger),toBeBroadcasted(tBB),toBeFlushed(false), workerThreadOnly(false),
53  commandFailureCode(0), failureDescription(""),
54  bp(0), token(IDENTIFIER),paramERR(0)
55 {
56  G4String comStr = theCommandPath;
57  if(!theMessenger)
58  { // this must be a directory
59  if(comStr(comStr.length()-1)!='/')
60  {
61  G4cerr << "G4UIcommand Warning : " << G4endl;
62  G4cerr << " <" << theCommandPath << "> must be a directory." << G4endl;
63  G4cerr << " '/' is appended." << G4endl;
64  comStr += "/";
65  }
66  }
68  G4String nullString;
69  availabelStateList.clear();
76 }
77 
78 #ifdef G4MULTITHREADED
79 #include "G4Threading.hh"
80 #endif
81 
83 (const char * theCommandPath)
84 {
85  commandPath = theCommandPath;
86  commandName = theCommandPath;
87  G4int commandNameIndex = commandName.last('/');
88  commandName.remove(0,commandNameIndex+1);
89 #ifdef G4MULTITHREADED
90  if(messenger && messenger->CommandsShouldBeInMaster()
92  {
93  toBeBroadcasted = false;
95  }
96  else
98 #else
100 #endif
101 }
102 
104 {
105  G4UImanager* fUImanager = G4UImanager::GetUIpointer();
106  if(fUImanager) fUImanager->RemoveCommand(this);
107 
108  G4int n_parameterEntry = parameter.size();
109  for( G4int i_thParameter=0; i_thParameter < n_parameterEntry; i_thParameter++ )
110  { delete parameter[i_thParameter]; }
111  parameter.clear();
112 }
113 
115 {
116  return ( commandPath == right.GetCommandPath() );
117 }
118 
120 {
121  return ( commandPath != right.GetCommandPath() );
122 }
123 
124 #include "G4Threading.hh"
125 
127 {
128  G4String correctParameters;
129  G4int n_parameterEntry = parameter.size();
130  if( n_parameterEntry != 0 )
131  {
132  G4String aToken;
133  G4String correctToken;
134  G4Tokenizer parameterToken( parameterList );
135  for( G4int i_thParameter=0; i_thParameter<n_parameterEntry; i_thParameter++ )
136  {
137  if(i_thParameter > 0)
138  {
139  correctParameters.append(" ");
140  }
141  aToken = parameterToken();
142  if( aToken.length()>0 && aToken(0)=='"' )
143  {
144  while( aToken(aToken.length()-1) != '"'
145  || ( aToken.length()==1 && aToken(0)=='"' ))
146  {
147  G4String additionalToken = parameterToken();
148  if( additionalToken.isNull() )
149  { return fParameterUnreadable+i_thParameter; }
150  aToken += " ";
151  aToken += additionalToken;
152  }
153  }
154  else if(i_thParameter==n_parameterEntry-1 && parameter[i_thParameter]->GetParameterType()=='s')
155  {
156  G4String anotherToken;
157  while(!((anotherToken=parameterToken()).isNull()))
158  {
159  G4int idxs = anotherToken.index("#");
160  if(idxs==G4int(std::string::npos))
161  {
162  aToken += " ";
163  aToken += anotherToken;
164  }
165  else if(idxs>0)
166  {
167  aToken += " ";
168  aToken += anotherToken(0,idxs);
169  break;
170  }
171  else
172  { break; }
173  }
174  }
175 
176  if( aToken.isNull() || aToken == "!" )
177  {
178  if(parameter[i_thParameter]->IsOmittable())
179  {
180  if(parameter[i_thParameter]->GetCurrentAsDefault())
181  {
183  G4String parVal;
184  for(G4int ii=0;ii<i_thParameter;ii++)
185  {
186  parVal = cvSt();
187  if (parVal(0)=='"')
188  {
189  while( parVal(parVal.length()-1) != '"' )
190  {
191  G4String additionalToken = cvSt();
192  if( additionalToken.isNull() )
193  { return fParameterUnreadable+i_thParameter; }
194  parVal += " ";
195  parVal += additionalToken;
196  }
197  }
198  }
199  G4String aCVToken = cvSt();
200  if (aCVToken(0)=='"')
201  {
202  while( aCVToken(aCVToken.length()-1) != '"' )
203  {
204  G4String additionalToken = cvSt();
205  if( additionalToken.isNull() )
206  { return fParameterUnreadable+i_thParameter; }
207  aCVToken += " ";
208  aCVToken += additionalToken;
209  }
210  // aCVToken.strip(G4String::both,'"');
211  }
212  correctParameters.append(aCVToken);
213  }
214  else
215  { correctParameters.append(parameter[i_thParameter]->GetDefaultValue()); }
216  }
217  else
218  { return fParameterUnreadable+i_thParameter; }
219  }
220  else
221  {
222  G4int stat = parameter[i_thParameter]->CheckNewValue( aToken );
223  if(stat) return stat+i_thParameter;
224  correctParameters.append(aToken);
225  }
226  }
227  }
228 
229  if(CheckNewValue( correctParameters ))
230  { return fParameterOutOfRange+99; }
231 
233 
234  messenger->SetNewValue( this, correctParameters );
235  return 0;
236 }
237 
239 {
240  return messenger->GetCurrentValue(this);
241 }
242 
244 {
245  availabelStateList.clear();
246  availabelStateList.push_back(s1);
247 }
248 
251 {
252  availabelStateList.clear();
253  availabelStateList.push_back(s1);
254  availabelStateList.push_back(s2);
255 }
256 
260 {
261  availabelStateList.clear();
262  availabelStateList.push_back(s1);
263  availabelStateList.push_back(s2);
264  availabelStateList.push_back(s3);
265 }
266 
271 {
272  availabelStateList.clear();
273  availabelStateList.push_back(s1);
274  availabelStateList.push_back(s2);
275  availabelStateList.push_back(s3);
276  availabelStateList.push_back(s4);
277 }
278 
284 {
285  availabelStateList.clear();
286  availabelStateList.push_back(s1);
287  availabelStateList.push_back(s2);
288  availabelStateList.push_back(s3);
289  availabelStateList.push_back(s4);
290  availabelStateList.push_back(s5);
291 }
292 
294 {
295  G4bool av = false;
296  G4ApplicationState currentState
298 
299  G4int nState = availabelStateList.size();
300  for(G4int i=0;i<nState;i++)
301  {
302  if(availabelStateList[i]==currentState)
303  {
304  av = true;
305  break;
306  }
307  }
308 
309  return av;
310 }
311 
312 G4double G4UIcommand::ValueOf(const char* unitName)
313 {
314  G4double value = 0.;
315  value = G4UnitDefinition::GetValueOf(unitName);
316  return value;
317 }
318 
319 G4String G4UIcommand::CategoryOf(const char* unitName)
320 {
321  return G4UnitDefinition::GetCategory(unitName);
322 }
323 
324 G4String G4UIcommand::UnitsList(const char* unitCategory)
325 {
326  G4String retStr;
328  size_t i;
329  for(i=0;i<UTbl.size();i++)
330  { if(UTbl[i]->GetName()==unitCategory) break; }
331  if(i==UTbl.size())
332  {
333  G4cerr << "Unit category <" << unitCategory << "> is not defined." << G4endl;
334  return retStr;
335  }
336  G4UnitsContainer& UCnt = UTbl[i]->GetUnitsList();
337  retStr = UCnt[0]->GetSymbol();
338  G4int je = UCnt.size();
339  for(G4int j=1;j<je;j++)
340  {
341  retStr += " ";
342  retStr += UCnt[j]->GetSymbol();
343  }
344  for(G4int k=0;k<je;k++)
345  {
346  retStr += " ";
347  retStr += UCnt[k]->GetName();
348  }
349  return retStr;
350 }
351 
353 {
354  G4cout << G4endl;
355  G4cout << G4endl;
356  if(commandPath(commandPath.length()-1)!='/')
357  { G4cout << "Command " << commandPath << G4endl; }
358  if(workerThreadOnly)
359  { G4cout << " ---- available only in worker thread" << G4endl; }
360  G4cout << "Guidance :" << G4endl;
361  G4int n_guidanceEntry = commandGuidance.size();
362  for( G4int i_thGuidance=0; i_thGuidance < n_guidanceEntry; i_thGuidance++ )
363  { G4cout << commandGuidance[i_thGuidance] << G4endl; }
364  if( ! rangeString.isNull() )
365  { G4cout << " Range of parameters : " << rangeString << G4endl; }
366  G4int n_parameterEntry = parameter.size();
367  if( n_parameterEntry > 0 )
368  {
369  for( G4int i_thParameter=0; i_thParameter<n_parameterEntry; i_thParameter++ )
370  { parameter[i_thParameter]->List(); }
371  }
372  G4cout << G4endl;
373 }
374 
376 {
377  G4String vl = "0";
378  if(boolVal) vl = "1";
379  return vl;
380 }
381 
383 {
384  std::ostringstream os;
385  os << intValue;
386  G4String vl = os.str();
387  return vl;
388 }
389 
391 {
392  std::ostringstream os;
394  { os << std::setprecision(17) << doubleValue; }
395  else
396  { os << doubleValue; }
397  G4String vl = os.str();
398  return vl;
399 }
400 
401 G4String G4UIcommand::ConvertToString(G4double doubleValue,const char* unitName)
402 {
403  G4String unt = unitName;
404  G4double uv = ValueOf(unitName);
405 
406  std::ostringstream os;
408  { os << std::setprecision(17) << doubleValue/uv << " " << unitName; }
409  else
410  { os << doubleValue/uv << " " << unitName; }
411  G4String vl = os.str();
412  return vl;
413 }
414 
416 {
417  std::ostringstream os;
419  { os << std::setprecision(17) << vec.x() << " " << vec.y() << " " << vec.z(); }
420  else
421  { os << vec.x() << " " << vec.y() << " " << vec.z(); }
422  G4String vl = os.str();
423  return vl;
424 }
425 
427 {
428  G4String unt = unitName;
429  G4double uv = ValueOf(unitName);
430 
431  std::ostringstream os;
433  { os << std::setprecision(17) << vec.x()/uv << " " << vec.y()/uv << " " << vec.z()/uv << " " << unitName; }
434  else
435  { os << vec.x()/uv << " " << vec.y()/uv << " " << vec.z()/uv << " " << unitName; }
436  G4String vl = os.str();
437  return vl;
438 }
439 
441 {
442  G4String v = st;
443  v.toUpper();
444  G4bool vl = false;
445  if( v=="Y" || v=="YES" || v=="1" || v=="T" || v=="TRUE" )
446  { vl = true; }
447  return vl;
448 }
449 
451 {
452  G4int vl;
453  std::istringstream is(st);
454  is >> vl;
455  return vl;
456 }
457 
459 {
460  G4double vl;
461  std::istringstream is(st);
462  is >> vl;
463  return vl;
464 }
465 
467 {
468  G4double vl;
469  char unts[30];
470 
471  std::istringstream is(st);
472  is >> vl >> unts;
473  G4String unt = unts;
474 
475  return (vl*ValueOf(unt));
476 }
477 
479 {
480  G4double vx;
481  G4double vy;
482  G4double vz;
483  std::istringstream is(st);
484  is >> vx >> vy >> vz;
485  return G4ThreeVector(vx,vy,vz);
486 }
487 
489 {
490  G4double vx;
491  G4double vy;
492  G4double vz;
493  char unts[30];
494  std::istringstream is(st);
495  is >> vx >> vy >> vz >> unts;
496  G4String unt = unts;
497  G4double uv = ValueOf(unt);
498  return G4ThreeVector(vx*uv,vy*uv,vz*uv);
499 }
500 
501 
502 // ----- the following is used by CheckNewValue() ------------
503 
504 
505 #include <ctype.h> // isalpha(), toupper()
506 
507 //#include "checkNewValue_debug.icc"
508 //#define DEBUG 1
509 
511 CheckNewValue(const char * newValue)
512 {
513  yystype result;
514  // if( TypeCheck(newValue) == 0 ) return 1;
515  if( ! rangeString.isNull() )
516  { if( RangeCheck(newValue) == 0 ) return fParameterOutOfRange; }
517  return 0; // succeeded
518 }
519 
520 // ------------------ type check routines -------------------
521 
523 TypeCheck(const char * t)
524 {
525  G4String aNewValue;
526  char type;
527  std::istringstream is(t);
528  for (unsigned i=0; i< parameter.size(); i++) {
529  is >> aNewValue;
530  type = toupper(parameter[i]->GetParameterType());
531  switch ( type ) {
532  case 'D':
533  if( IsDouble(aNewValue)==0 ){
534  G4cerr << aNewValue << ": double value expected."
535  << G4endl;
536  return 0;
537  } break;
538  case 'I':
539  if( IsInt(aNewValue,20)==0 ){
540  G4cerr <<aNewValue<<": integer expected."
541  <<G4endl;
542  return 0;
543  } break;
544  case 'S':
545  break;
546  case 'B':
547  aNewValue.toUpper();
548  if (aNewValue == "Y" || aNewValue == "N"
549  ||aNewValue == "YES" || aNewValue == "NO"
550  ||aNewValue == "1" || aNewValue == "0"
551  ||aNewValue == "T" || aNewValue == "F"
552  ||aNewValue == "TRUE" || aNewValue == "FALSE")
553  return 1;
554  else return 0;
555  break;
556  default: ;
557  }
558  }
559  return 1;
560 }
561 
562 
564 IsInt(const char* buf, short maxDigits)
565 {
566  const char* p= buf;
567  G4int length=0;
568  if( *p == '+' || *p == '-') { ++p; }
569  if( isdigit( (G4int)(*p) )) {
570  while( isdigit( (G4int)(*p) )) { ++p; ++length; }
571  if( *p == '\0' ) {
572  if( length > maxDigits) {
573  G4cerr <<"digit length exceeds"<<G4endl;
574  return 0;
575  }
576  return 1;
577  } else {
578  // G4cerr <<"illegal character after int:"<<buf<<G4endl;
579  }
580  } else {
581  // G4cerr <<"illegal int:"<<buf<<G4endl;
582  }
583  return 0;
584 }
585 
586 
588 ExpectExponent(const char* str) // used only by IsDouble()
589 {
590  G4int maxExplength;
591  if( IsInt( str, maxExplength=7 )) return 1;
592  else return 0;
593 }
594 
595 
597 IsDouble(const char* buf)
598 {
599  const char* p= buf;
600  switch( *p) {
601  case '+': case '-': ++p;
602  if( isdigit(*p) ) {
603  while( isdigit( (G4int)(*p) )) { ++p; }
604  switch ( *p ) {
605  case '\0': return 1;
606  // break;
607  case 'E': case 'e':
608  return ExpectExponent(++p );
609  // break;
610  case '.': ++p;
611  if( *p == '\0' ) return 1;
612  if( *p == 'e' || *p =='E' ) return ExpectExponent(++p );
613  if( isdigit(*p) ) {
614  while( isdigit( (G4int)(*p) )) { ++p; }
615  if( *p == '\0' ) return 1;
616  if( *p == 'e' || *p =='E') return ExpectExponent(++p);
617  } else return 0; break;
618  default: return 0;
619  }
620  }
621  if( *p == '.' ) { ++p;
622  if( isdigit(*p) ) {
623  while( isdigit( (G4int)(*p) )) { ++p; }
624  if( *p == '\0' ) return 1;
625  if( *p == 'e' || *p =='E') return ExpectExponent(++p);
626  }
627  }
628  break;
629  case '.': ++p;
630  if( isdigit(*p) ) {
631  while( isdigit( (G4int)(*p) )) { ++p; }
632  if( *p == '\0' ) return 1;
633  if( *p == 'e' || *p =='E' ) return ExpectExponent(++p);
634  } break;
635  default: // digit is expected
636  if( isdigit(*p) ) {
637  while( isdigit( (G4int)(*p) )) { ++p; }
638  if( *p == '\0' ) return 1;
639  if( *p == 'e' || *p =='E') return ExpectExponent(++p);
640  if( *p == '.' ) { ++p;
641  if( *p == '\0' ) return 1;
642  if( *p == 'e' || *p =='E') return ExpectExponent(++p);
643  if( isdigit(*p) ) {
644  while( isdigit( (G4int)(*p) )) { ++p; }
645  if( *p == '\0' ) return 1;
646  if( *p == 'e' || *p =='E') return ExpectExponent(++p);
647  }
648  }
649  }
650  }
651  return 0;
652 }
653 
654 
655 // ------------------ range Check routines -------------------
657 RangeCheck(const char* t) {
658  yystype result;
659  char type;
660  bp = 0; // reset buffer pointer for G4UIpGetc()
661  std::istringstream is(t);
662  for (unsigned i=0; i< parameter.size(); i++) {
663  type= toupper(parameter[i]->GetParameterType());
664  switch ( type ) {
665  case 'D': is >> newVal[i].D; break;
666  case 'I': is >> newVal[i].I; break;
667  case 'S': is >> newVal[i].S; break;
668  case 'B': is >> newVal[i].C; break;
669  default: ;
670  }
671  }
672  // PrintToken(); // Print tokens (consumes all tokens)
673  token= Yylex();
674  result = Expression();
675 
676  if( paramERR == 1 ) return 0;
677  if( result.type != CONSTINT) {
678  G4cerr << "Illegal Expression in parameter range." << G4endl;
679  return 0;
680  }
681  if ( result.I ) return 1;
682  G4cerr << "parameter out of range: "<< rangeString << G4endl;
683  return 0;
684 }
685 
686 // ------------------ syntax node functions ------------------
689 {
690  yystype result;
691  #ifdef DEBUG
692  G4cerr << " Expression()" << G4endl;
693  #endif
694  result = LogicalORExpression();
695  return result;
696 }
697 
700 {
701  yystype result;
702  yystype p;
703  p = LogicalANDExpression();
704  if( token != LOGICALOR) return p;
705  if( p.type == CONSTSTRING || p.type == IDENTIFIER ) {
706  G4cerr << "Parameter range: illegal type at '||'" << G4endl;
707  paramERR = 1;
708  }
709  result.I = p.I;
710  while (token == LOGICALOR)
711  {
712  token = Yylex();
713  p = LogicalANDExpression();
714  if( p.type == CONSTSTRING || p.type == IDENTIFIER ) {
715  G4cerr << "Parameter range: illegal type at '||'" <<G4endl;
716  paramERR = 1;
717  }
718  switch (p.type) {
719  case CONSTINT:
720  result.I += p.I;
721  result.type = CONSTINT; break;
722  case CONSTDOUBLE:
723  result.I += (p.D != 0.0);
724  result.type = CONSTINT; break;
725  default:
726  G4cerr << "Parameter range: unknown type"<<G4endl;
727  paramERR = 1;
728  }
729  }
730  return result;
731 }
732 
735 {
736  yystype result;
737  yystype p;
738  p = EqualityExpression();
739  if( token != LOGICALAND) return p;
740  if( p.type == CONSTSTRING || p.type == IDENTIFIER ) {
741  G4cerr << "Parameter range: illegal type at '&&'" << G4endl;
742  paramERR = 1;
743  }
744  result.I = p.I;
745  while (token == LOGICALAND)
746  {
747  token = Yylex();
748  p = EqualityExpression();
749  if( p.type == CONSTSTRING || p.type == IDENTIFIER ) {
750  G4cerr << "Parameter range: illegal type at '&&'" << G4endl;
751  paramERR = 1;
752  }
753  switch (p.type) {
754  case CONSTINT:
755  result.I *= p.I;
756  result.type = CONSTINT; break;
757  case CONSTDOUBLE:
758  result.I *= (p.D != 0.0);
759  result.type = CONSTINT; break;
760  default:
761  G4cerr << "Parameter range: unknown type."<< G4endl;
762  paramERR = 1;
763  }
764  }
765  return result;
766 }
767 
768 
771 {
772  yystype arg1, arg2;
773  G4int operat;
774  yystype result;
775  #ifdef DEBUG
776  G4cerr << " EqualityExpression()" <<G4endl;
777  #endif
778  result = RelationalExpression();
779  if( token==EQ || token==NE ) {
780  operat = token;
781  token = Yylex();
782  arg1 = result;
783  arg2 = RelationalExpression();
784  result.I = Eval2( arg1, operat, arg2 ); // semantic action
785  result.type = CONSTINT;
786  #ifdef DEBUG
787  G4cerr << " return code of Eval2(): " << result.I <<G4endl;
788  #endif
789  } else {
790  if (result.type != CONSTINT && result.type != CONSTDOUBLE) {
791  G4cerr << "Parameter range: error at EqualityExpression"
792  << G4endl;
793  paramERR = 1;
794  }
795  }
796  return result;
797 }
798 
799 
802 {
803  yystype arg1, arg2;
804  G4int operat;
805  yystype result;
806  #ifdef DEBUG
807  G4cerr << " RelationalExpression()" <<G4endl;
808  #endif
809 
810  arg1 = AdditiveExpression();
811  if( token==GT || token==GE || token==LT || token==LE ) {
812  operat = token;
813  token = Yylex();
814  arg2 = AdditiveExpression();
815  result.I = Eval2( arg1, operat, arg2 ); // semantic action
816  result.type = CONSTINT;
817  #ifdef DEBUG
818  G4cerr << " return code of Eval2(): " << result.I << G4endl;
819  #endif
820  } else {
821  result = arg1;
822  }
823  #ifdef DEBUG
824  G4cerr <<" return RelationalExpression()"<< G4endl;
825  #endif
826  return result;
827 }
828 
831 { yystype result;
832  result = MultiplicativeExpression();
833  if( token != '+' && token != '-' ) return result;
834  G4cerr << "Parameter range: operator "
835  << (char)token
836  << " is not supported." << G4endl;
837  paramERR = 1;
838  return result;
839 }
840 
843 { yystype result;
844  result = UnaryExpression();
845  if( token != '*' && token != '/' && token != '%' ) return result;
846  G4cerr << "Parameter range: operator "
847  << (char)token
848  << " is not supported." << G4endl;
849  paramERR = 1;
850  return result;
851 }
852 
855 {
856  yystype result;
857  yystype p;
858  #ifdef DEBUG
859  G4cerr <<" UnaryExpression"<< G4endl;
860  #endif
861  switch(token) {
862  case '-':
863  token = Yylex();
864  p = UnaryExpression();
865  if (p.type == CONSTINT) {
866  result.I = - p.I;
867  result.type = CONSTINT;
868  }
869  if (p.type == CONSTDOUBLE) {
870  result.D = - p.D;
871  result.type = CONSTDOUBLE;
872  } break;
873  case '+':
874  token = Yylex();
875  result = UnaryExpression(); break;
876  case '!':
877  token = Yylex();
878  G4cerr << "Parameter range error: "
879  << "operator '!' is not supported (sorry)."
880  << G4endl;
881  paramERR = 1;
882  result = UnaryExpression(); break;
883  default:
884  result = PrimaryExpression();
885  }
886  return result;
887 }
888 
889 
892 {
893  yystype result;
894  #ifdef DEBUG
895  G4cerr <<" primary_exp"<<G4endl;
896  #endif
897  switch (token) {
898  case IDENTIFIER:
899  result.S = yylval.S;
900  result.type = token;
901  token = Yylex(); break;
902  case CONSTINT:
903  result.I = yylval.I;
904  result.type = token;
905  token= Yylex(); break;
906  case CONSTDOUBLE:
907  result.D = yylval.D;
908  result.type = token;
909  token = Yylex(); break;
910  case '(' :
911  token= Yylex();
912  result = Expression();
913  if( token != ')' ) {
914  G4cerr << " ')' expected" << G4endl;
915  paramERR = 1;
916  }
917  token = Yylex();
918  break;
919  default:
920  return result;
921  }
922  return result; // never executed
923 }
924 
925 //---------------- semantic routines ---------------------------------
926 
928 Eval2(yystype arg1, G4int op, yystype arg2)
929 {
930  char newValtype;
931  if( (arg1.type != IDENTIFIER) && (arg2.type != IDENTIFIER)) {
933  << ": meaningless comparison"
934  << G4endl;
935  paramERR = 1;
936  }
937 
938  if( arg1.type == IDENTIFIER) {
939  unsigned i = IndexOf( arg1.S );
940  newValtype = toupper(parameter[i]->GetParameterType());
941  switch ( newValtype ) {
942  case 'I':
943  if( arg2.type == CONSTINT ) {
944  return CompareInt( newVal[i].I, op, arg2.I );
945 //===================================================================
946 // MA - 2018.07.23
947  } else if( arg2.type == IDENTIFIER ) {
948  unsigned iii = IndexOf( arg2.S );
949  char newValtype2 = toupper(parameter[iii]->GetParameterType());
950  if( newValtype2 == 'I' ) {
951  return CompareInt( newVal[i].I, op, newVal[iii].I );
952  } else if( newValtype2 == 'D' ) {
953  G4cerr << "Warning : Integer is compared with double : "
954  << rangeString << G4endl;
955  return CompareDouble( newVal[i].I, op, newVal[iii].D );
956  }
957 //===================================================================
958  } else {
959  G4cerr << "integer operand expected for "
960  << rangeString
961  << '.' << G4endl;
962  } break;
963  case 'D':
964  if( arg2.type == CONSTDOUBLE ) {
965  return CompareDouble( newVal[i].D, op, arg2.D );
966  } else if ( arg2.type == CONSTINT ) { // integral promotion
967  return CompareDouble( newVal[i].D, op, arg2.I );
968 //===================================================================
969 // MA - 2018.07.23
970  } else if( arg2.type == IDENTIFIER ) {
971  unsigned iii = IndexOf( arg2.S );
972  char newValtype2 = toupper(parameter[iii]->GetParameterType());
973  if( newValtype2 == 'I' ) {
974  return CompareDouble( newVal[i].D, op, newVal[iii].I );
975  } else if( newValtype2 == 'D' ) {
976  return CompareDouble( newVal[i].D, op, newVal[iii].D );
977  }
978 //===================================================================
979  } break;
980  default: ;
981  }
982  }
983  if( arg2.type == IDENTIFIER) {
984  unsigned i = IndexOf( arg2.S );
985  newValtype = toupper(parameter[i]->GetParameterType());
986  switch ( newValtype ) {
987  case 'I':
988  if( arg1.type == CONSTINT ) {
989  return CompareInt( arg1.I, op, newVal[i].I );
990  } else {
991  G4cerr << "integer operand expected for "
992  << rangeString
993  << '.' << G4endl;
994  } break;
995  case 'D':
996  if( arg1.type == CONSTDOUBLE ) {
997  return CompareDouble( arg1.D, op, newVal[i].D );
998  } else
999  if ( arg1.type == CONSTINT ) { // integral promotion
1000  return CompareDouble( arg1.I, op, newVal[i].D );
1001  } break;
1002  default: ;
1003  }
1004  }
1005  return 0;
1006 }
1007 
1009 CompareInt(G4int arg1, G4int op, G4int arg2)
1010 {
1011  G4int result=-1;
1012  G4String opr;
1013  switch (op) {
1014  case GT: result = ( arg1 > arg2); opr= ">" ; break;
1015  case GE: result = ( arg1 >= arg2); opr= ">="; break;
1016  case LT: result = ( arg1 < arg2); opr= "<" ; break;
1017  case LE: result = ( arg1 <= arg2); opr= "<="; break;
1018  case EQ: result = ( arg1 == arg2); opr= "=="; break;
1019  case NE: result = ( arg1 != arg2); opr= "!="; break;
1020  default:
1021  G4cerr << "Parameter range: error at CompareInt" << G4endl;
1022  paramERR = 1;
1023  }
1024  #ifdef DEBUG
1025  G4cerr << "CompareInt "
1026  << arg1 << " " << opr << arg2
1027  << " result: " << result
1028  << G4endl;
1029  #endif
1030  return result;
1031 }
1032 
1035 {
1036  G4int result=-1;
1037  G4String opr;
1038  switch (op) {
1039  case GT: result = ( arg1 > arg2); opr= ">"; break;
1040  case GE: result = ( arg1 >= arg2); opr= ">="; break;
1041  case LT: result = ( arg1 < arg2); opr= "<"; break;
1042  case LE: result = ( arg1 <= arg2); opr= "<="; break;
1043  case EQ: result = ( arg1 == arg2); opr= "=="; break;
1044  case NE: result = ( arg1 != arg2); opr= "!="; break;
1045  default:
1046  G4cerr << "Parameter range: error at CompareDouble"
1047  << G4endl;
1048  paramERR = 1;
1049  }
1050  #ifdef DEBUG
1051  G4cerr << "CompareDouble "
1052  << arg1 <<" " << opr << " "<< arg2
1053  << " result: " << result
1054  << G4endl;
1055  #endif
1056  return result;
1057 }
1058 
1059 unsigned G4UIcommand::
1060 IndexOf(const char* nam)
1061 {
1062  unsigned i;
1063  G4String pname;
1064  for( i=0; i<parameter.size(); i++)
1065  {
1066  pname = parameter[i]-> GetParameterName();
1067  if( pname == nam ) {
1068  return i;
1069  }
1070  }
1071  paramERR = 1;
1072  G4cerr << "parameter name:"<<nam<<" not found."<< G4endl;
1073  return 0;
1074 }
1075 
1076 
1077 unsigned G4UIcommand::
1078 IsParameter(const char* nam)
1079 {
1080  G4String pname;
1081  for(unsigned i=0; i<parameter.size(); i++)
1082  {
1083  pname = parameter[i]-> GetParameterName();
1084  if( pname == nam ) return 1;
1085  }
1086  return 0;
1087 }
1088 
1089 
1090 // --------------------- utility functions --------------------------
1091 
1093 Yylex() // reads input and returns token number, KR486
1094 { // (returns EOF)
1095  G4int c;
1096  G4String buf;
1097 
1098  while(( c= G4UIpGetc())==' '|| c=='\t' || c== '\n' )
1099  ;
1100  if (c== EOF)
1101  return (tokenNum)EOF; // KR488
1102  buf= "";
1103  if (isdigit(c) || c== '.') { // I or D
1104  do {
1105  buf += G4String((unsigned char)c);
1106  c=G4UIpGetc();
1107  } while (c=='.' || isdigit(c) ||
1108  c=='e' || c=='E' || c=='+' || c=='-');
1109  G4UIpUngetc(c);
1110  const char* t = buf;
1111  std::istringstream is(t);
1112  if ( IsInt(buf.data(),20) ) {
1113  is >> yylval.I;
1114  return CONSTINT;
1115  } else
1116  if ( IsDouble(buf.data()) ) {
1117  is >> yylval.D;
1118  return CONSTDOUBLE;
1119  } else {
1120  G4cerr << buf<<": numeric format error."<<G4endl;
1121  }
1122  }
1123  buf="";
1124  if (isalpha(c)|| c=='_') { // IDENTIFIER
1125  do {
1126  buf += G4String((unsigned char)c);
1127  } while ((c=G4UIpGetc()) != EOF && (isalnum(c) || c=='_'));
1128  G4UIpUngetc(c);
1129  if( IsParameter(buf) ) {
1130  yylval.S =buf;
1131  return IDENTIFIER;
1132  } else {
1133  G4cerr << buf << " is not a parameter name."<< G4endl;
1134  paramERR = 1;
1135  }
1136  }
1137  switch (c) {
1138  case '>': return (tokenNum) Follow('=', GE, GT);
1139  case '<': return (tokenNum) Follow('=', LE, LT);
1140  case '=': return (tokenNum) Follow('=', EQ, '=');
1141  case '!': return (tokenNum) Follow('=', NE, '!');
1142  case '|': return (tokenNum) Follow('|', LOGICALOR, '|');
1143  case '&': return (tokenNum) Follow('&', LOGICALAND, '&');
1144  default:
1145  return (tokenNum) c;
1146  }
1147 }
1148 
1149 
1151 Follow(G4int expect, G4int ifyes, G4int ifno)
1152 {
1153  G4int c = G4UIpGetc();
1154  if ( c== expect)
1155  return ifyes;
1156  G4UIpUngetc(c);
1157  return ifno;
1158 }
1159 
1160 //------------------ low level routines -----------------------------
1162 G4UIpGetc() { // emulation of getc()
1163  G4int length = rangeString.length();
1164  if( bp < length)
1165  return rangeString(bp++);
1166  else
1167  return EOF;
1168 }
1170 G4UIpUngetc(G4int c) { // emulation of ungetc()
1171  if (c<0) return -1;
1172  if (bp >0 && c == rangeString(bp-1)) {
1173  --bp;
1174  } else {
1175  G4cerr << "G4UIpUngetc() failed." << G4endl;
1176  G4cerr << "bp="<<bp <<" c="<<c
1177  << " pR(bp-1)=" << rangeString(bp-1)
1178  << G4endl;
1179  paramERR = 1;
1180  return -1;
1181  }
1182  return 0;
1183 }