ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4UIparameter.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4UIparameter.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 //
27 //
28 
29 #include "G4UIparameter.hh"
30 #include "G4UIcommandStatus.hh"
31 #include "G4Tokenizer.hh"
32 #include "G4ios.hh"
33 #include <sstream>
34 
35 #include "G4UItokenNum.hh"
36 using namespace G4UItokenNum;
37 
39 {
40  G4String nullString;
41  parameterName = nullString;
42  parameterType = '\0';
43  omittable = false;
44  parameterGuidance = nullString;
45  defaultValue = nullString;
46  parameterRange = nullString;
47  currentAsDefaultFlag = false;
48  parameterCandidate = nullString;
49  widget = 0;
50  bp = 0;
51  token = NONE;
52 }
53 
54 G4UIparameter::G4UIparameter(char theType):paramERR(0)
55 {
56  G4String nullString;
57  parameterName = nullString;
58  parameterType = theType;
59  omittable = false;
60  parameterGuidance = nullString;
61  defaultValue = nullString;
62  parameterRange = nullString;
63  currentAsDefaultFlag = false;
64  parameterCandidate = nullString;
65  widget = 0;
66  bp = 0;
67  token = NONE;
68 }
69 
70 G4UIparameter::G4UIparameter(const char * theName, char theType, G4bool theOmittable):paramERR(0)
71 {
72  parameterName = theName;
73  parameterType = theType;
74  omittable = theOmittable;
75  G4String nullString;
76  parameterGuidance = nullString;
77  defaultValue = nullString;
78  parameterRange = nullString;
79  currentAsDefaultFlag = false;
80  parameterCandidate = nullString;
81  widget = 0;
82  bp = 0;
83  token = NONE;
84 }
85 
87 { }
88 
90 {
91  return ( this == &right );
92 }
93 
95 {
96  return ( this != &right );
97 }
98 
100 {
101  G4cout << G4endl << "Parameter : " << parameterName << G4endl;
102  if( ! parameterGuidance.isNull() )
103  G4cout << parameterGuidance << G4endl ;
104  G4cout << " Parameter type : " << parameterType << G4endl;
105  if(omittable)
106  { G4cout << " Omittable : True" << G4endl; }
107  else
108  { G4cout << " Omittable : False" << G4endl; }
110  { G4cout << " Default value : taken from the current value" << G4endl; }
111  else if( ! defaultValue.isNull() )
112  { G4cout << " Default value : " << defaultValue << G4endl; }
113  if( ! parameterRange.isNull() )
114  G4cout << " Parameter range : " << parameterRange << G4endl;
115  if( ! parameterCandidate.isNull() )
116  G4cout << " Candidates : " << parameterCandidate << G4endl;
117 }
118 
120 {
121  std::ostringstream os;
122  os << theDefaultValue;
123  defaultValue = os.str();
124 }
125 
127 {
128  std::ostringstream os;
129  os << theDefaultValue;
130  defaultValue = os.str();
131 }
132 
133 #include "G4UIcommand.hh"
134 void G4UIparameter::SetDefaultUnit(const char * theDefaultUnit)
135 {
136  char type = toupper( parameterType );
137  if( type != 'S' )
138  {
140  ed << "This method can be used only for a string-type parameter that is used to specify a unit.\n"
141  << "This parameter <" << parameterName << "> is defined as ";
142  switch(type) {
143  case 'D': ed <<"double."; break;
144  case 'I': ed <<"integer."; break;
145  case 'B': ed <<"bool."; break;
146  default: ed <<"undefined.";
147  }
148  G4Exception("G4UIparameter::SetDefaultUnit","INTERCOM2010",FatalException,ed);
149  }
150  SetDefaultValue(theDefaultUnit);
152 }
153 
154 // ---------- CheckNewValue() related routines -----------
155 #include <ctype.h>
156 #include "G4UItokenNum.hh"
157 
158 //#include "checkNewValue_debug.icc"
159 //#define DEBUG 1
160 
162 CheckNewValue(const char* newValue ) {
163  if( TypeCheck(newValue) == 0) return fParameterUnreadable;
164  if( ! parameterRange.isNull() )
165  { if( RangeCheck(newValue) == 0 ) return fParameterOutOfRange; }
166  if( ! parameterCandidate.isNull() )
167  { if( CandidateCheck(newValue) == 0 ) return fParameterOutOfCandidates; }
168  return 0; // succeeded
169 }
170 
172 CandidateCheck(const char* newValue) {
173  G4Tokenizer candidateTokenizer(parameterCandidate);
174  G4String aToken;
175  G4int iToken = 0;
176  while( ! (aToken=candidateTokenizer()).isNull() )
177  {
178  iToken++;
179  if(aToken==newValue) return iToken;
180  }
181  G4cerr << "parameter value (" << newValue
182  << ") is not listed in the candidate List." << G4endl;
183  return 0;
184 }
185 
187 RangeCheck(const char* newValue) {
188  yystype result;
189  bp = 0; // reset buffer pointer for G4UIpGetc()
190  std::istringstream is(newValue);
191  char type = toupper( parameterType );
192  switch (type) {
193  case 'D': { is >> newVal.D; } break;
194  case 'I': { is >> newVal.I; } break;
195  default: ;
196  }
197  // PrintToken(); // Print tokens (consumes all tokens)
198  token= Yylex();
199  result = Expression();
200  if( paramERR == 1 ) return 0;
201  if( result.type != CONSTINT) {
202  G4cerr << "Illegal Expression in parameter range." << G4endl;
203  return 0;
204  }
205  if ( result.I ) return 1;
206  G4cerr << "parameter out of range: "<< parameterRange << G4endl;
207  return 0;
208 }
209 
210 
212 TypeCheck(const char* newValue)
213 {
214  G4String newValueString(newValue);
215  char type = toupper( parameterType );
216  switch(type) {
217  case 'D':
218  if( IsDouble(newValueString.data())== 0) {
219  G4cerr<<newValue<<": double value expected."
220  << G4endl;
221  return 0;
222  } break;
223  case 'I':
224  if( IsInt(newValueString.data(),20)== 0) {
225  G4cerr<<newValue<<": integer expected."
226  << G4endl;
227  return 0;
228  } break;
229  case 'S': break;
230  case 'B':
231  newValueString.toUpper();
232  if ( newValueString == "Y" || newValueString == "N"
233  ||newValueString == "YES" || newValueString == "NO"
234  ||newValueString == "1" || newValueString == "0"
235  ||newValueString == "T" || newValueString == "F"
236  ||newValueString == "TRUE" || newValueString == "FALSE")
237  return 1;
238  else {
239  G4cerr<<newValue<<": bool expected." << G4endl;
240  return 0;
241  }
242  default: ;
243  }
244  return 1;
245 }
246 
247 
249 IsInt(const char* buf, short maxDigits) // do not allow any std::ws
250 {
251  const char* p= buf;
252  G4int length=0;
253  if( *p == '+' || *p == '-') { ++p; }
254  if( isdigit( (G4int)(*p) )) {
255  while( isdigit( (G4int)(*p) )) { ++p; ++length; }
256  if( *p == '\0' ) {
257  if( length > maxDigits) {
258  G4cerr <<"digit length exceeds"<<G4endl;
259  return 0;
260  }
261  return 1;
262  } else {
263  // G4cerr <<"illegal character after int:"<<buf<<G4endl;
264  }
265  } else {
266  // G4cerr <<"illegal int:"<<buf<<G4endl;
267  }
268  return 0;
269 }
270 
271 
273 ExpectExponent(const char* str) // used only by IsDouble()
274 {
275  G4int maxExplength;
276  if( IsInt( str, maxExplength=7 )) return 1;
277  else return 0;
278 }
279 
281 IsDouble(const char* buf) // see state diagram for this spec.
282 {
283  const char* p= buf;
284  switch( *p) {
285  case '+': case '-': ++p;
286  if( isdigit(*p) ) {
287  while( isdigit( (G4int)(*p) )) { ++p; }
288  switch ( *p ) {
289  case '\0': return 1; //break;
290  case 'E': case 'e':
291  return ExpectExponent(++p ); //break;
292  case '.': ++p;
293  if( *p == '\0' ) return 1;
294  if( *p == 'e' || *p =='E' ) return ExpectExponent(++p );
295  if( isdigit(*p) ) {
296  while( isdigit( (G4int)(*p) )) { ++p; }
297  if( *p == '\0' ) return 1;
298  if( *p == 'e' || *p =='E') return ExpectExponent(++p);
299  } else return 0; break;
300  default: return 0;
301  }
302  }
303  if( *p == '.' ) { ++p;
304  if( isdigit(*p) ) {
305  while( isdigit( (G4int)(*p) )) { ++p; }
306  if( *p == '\0' ) return 1;
307  if( *p == 'e' || *p =='E') return ExpectExponent(++p);
308  }
309  }
310  break;
311  case '.': ++p;
312  if( isdigit(*p) ) {
313  while( isdigit( (G4int)(*p) )) { ++p; }
314  if( *p == '\0' ) return 1;
315  if( *p == 'e' || *p =='E' ) return ExpectExponent(++p);
316  } break;
317  default: // digit is expected
318  if( isdigit(*p) ) {
319  while( isdigit( (G4int)(*p) )) { ++p; }
320  if( *p == '\0' ) return 1;
321  if( *p == 'e' || *p =='E') return ExpectExponent(++p);
322  if( *p == '.' ) { ++p;
323  if( *p == '\0' ) return 1;
324  if( *p == 'e' || *p =='E') return ExpectExponent(++p);
325  if( isdigit(*p) ) {
326  while( isdigit( (G4int)(*p) )) { ++p; }
327  if( *p == '\0' ) return 1;
328  if( *p == 'e' || *p =='E') return ExpectExponent(++p);
329  }
330  }
331  }
332  }
333  return 0;
334 }
335 
336 
337 // ------------------ syntax node functions ------------------
338 
341 {
342  yystype result;
343  #ifdef DEBUG
344  G4cerr << " Expression()" << G4endl;
345  #endif
346  result = LogicalORExpression();
347  return result;
348 }
349 
352 {
353  yystype result;
354  yystype p;
355  p = LogicalANDExpression();
356  if( token != LOGICALOR) return p;
357  if( p.type == CONSTSTRING || p.type == IDENTIFIER ) {
358  G4cerr << "Parameter range: illegal type at '||'" << G4endl;
359  paramERR = 1;
360  }
361  result.I = p.I;
362  while (token == LOGICALOR)
363  {
364  token = Yylex();
365  p = LogicalANDExpression();
366  if( p.type == CONSTSTRING || p.type == IDENTIFIER ) {
367  G4cerr << "Parameter range: illegal type at '||'" <<G4endl;
368  paramERR = 1;
369  }
370  switch (p.type) {
371  case CONSTINT:
372  result.I += p.I;
373  result.type = CONSTINT; break;
374  case CONSTDOUBLE:
375  result.I += (p.D != 0.0);
376  result.type = CONSTINT; break;
377  default:
378  G4cerr << "Parameter range: unknown type"<<G4endl;
379  paramERR = 1;
380  }
381  }
382  return result;
383 }
384 
387 {
388  yystype result;
389  yystype p;
390  p = EqualityExpression();
391  if( token != LOGICALAND) return p;
392  if( p.type == CONSTSTRING || p.type == IDENTIFIER ) {
393  G4cerr << "Parameter range: illegal type at '&&'" << G4endl;
394  paramERR = 1;
395  }
396  result.I = p.I;
397  while (token == LOGICALAND)
398  {
399  token = Yylex();
400  p = EqualityExpression();
401  if( p.type == CONSTSTRING || p.type == IDENTIFIER ) {
402  G4cerr << "Parameter range: illegal type at '&&'" << G4endl;
403  paramERR = 1;
404  }
405  switch (p.type) {
406  case CONSTINT:
407  result.I *= p.I;
408  result.type = CONSTINT; break;
409  case CONSTDOUBLE:
410  result.I *= (p.D != 0.0);
411  result.type = CONSTINT; break;
412  default:
413  G4cerr << "Parameter range: unknown type."<< G4endl;
414  paramERR = 1;
415  }
416  }
417  return result;
418 }
419 
420 
423 {
424  yystype arg1, arg2;
425  G4int operat;
426  yystype result;
427  #ifdef DEBUG
428  G4cerr << " EqualityExpression()" <<G4endl;
429  #endif
430  result = RelationalExpression();
431  if( token==EQ || token==NE ) {
432  operat = token;
433  token = Yylex();
434  arg1 = result;
435  arg2 = RelationalExpression();
436  result.I = Eval2( arg1, operat, arg2 ); // semantic action
437  result.type = CONSTINT;
438  #ifdef DEBUG
439  G4cerr << " return code of Eval2(): " << result.I <<G4endl;
440  #endif
441  } else {
442  if (result.type != CONSTINT && result.type != CONSTDOUBLE) {
443  G4cerr << "Parameter range: error at EqualityExpression"
444  << G4endl;
445  paramERR = 1;
446  }
447  }
448  return result;
449 }
450 
451 
454 {
455  yystype arg1, arg2;
456  G4int operat;
457  yystype result;
458  #ifdef DEBUG
459  G4cerr << " RelationalExpression()" <<G4endl;
460  #endif
461 
462  arg1 = AdditiveExpression();
463  if( token==GT || token==GE || token==LT || token==LE ) {
464  operat = token;
465  token = Yylex();
466  arg2 = AdditiveExpression();
467  result.I = Eval2( arg1, operat, arg2 ); // semantic action
468  result.type = CONSTINT;
469  #ifdef DEBUG
470  G4cerr << " return Eval2(): " << G4endl;
471  #endif
472  } else {
473  result = arg1;
474  }
475  #ifdef DEBUG
476  G4cerr <<" return RelationalExpression()" <<G4endl;
477  #endif
478  return result;
479 }
480 
483 { yystype result;
484  result = MultiplicativeExpression();
485  if( token != '+' && token != '-' ) return result;
486  G4cerr << "Parameter range: operator "
487  << (char)token
488  << " is not supported." << G4endl;
489  paramERR = 1;
490  return result;
491 }
492 
495 { yystype result;
496  result = UnaryExpression();
497  if( token != '*' && token != '/' && token != '%' ) return result;
498  G4cerr << "Parameter range: operator "
499  << (char)token
500  << " is not supported." << G4endl;
501  paramERR = 1;
502  return result;
503 }
504 
507 {
508  yystype result;
509  yystype p;
510  #ifdef DEBUG
511  G4cerr <<" UnaryExpression"<< G4endl;
512  #endif
513  switch(token) {
514  case '-':
515  token = Yylex();
516  p = UnaryExpression();
517  if (p.type == CONSTINT) {
518  result.I = - p.I;
519  result.type = CONSTINT;
520  }
521  if (p.type == CONSTDOUBLE) {
522  result.D = - p.D;
523  result.type = CONSTDOUBLE;
524  } break;
525  case '+':
526  token = Yylex();
527  result = UnaryExpression(); break;
528  case '!':
529  token = Yylex();
530  G4cerr << "Parameter range error: "
531  << "operator '!' is not supported (sorry)."
532  << G4endl;
533  paramERR = 1;
534  result = UnaryExpression(); break;
535  default:
536  result = PrimaryExpression();
537  }
538  return result;
539 }
540 
541 
544 {
545  yystype result;
546  #ifdef DEBUG
547  G4cerr <<" PrimaryExpression" << G4endl;
548  #endif
549  switch (token) {
550  case IDENTIFIER:
551  result.S = yylval.S;
552  result.type = token;
553  token = Yylex(); break;
554  case CONSTINT:
555  result.I = yylval.I;
556  result.type = token;
557  token= Yylex(); break;
558  case CONSTDOUBLE:
559  result.D = yylval.D;
560  result.type = token;
561  token = Yylex(); break;
562  case '(' :
563  token= Yylex();
564  result = Expression();
565  if( token != ')' ) {
566  G4cerr << " ')' expected" << G4endl;
567  paramERR = 1;
568  }
569  token = Yylex();
570  break;
571  default:
572  return result;
573  }
574  return result; // never executed
575 }
576 
577 //---------------- semantic routines ---------------------------------
578 
580 Eval2(yystype arg1, G4int op, yystype arg2)
581 {
582  if( (arg1.type != IDENTIFIER) && (arg2.type != IDENTIFIER)) {
584  << ": meaningless comparison "
585  << G4int(arg1.type) << " " << G4int(arg2.type) << G4endl;
586  paramERR = 1;
587  }
588  char type = toupper( parameterType );
589  if( arg1.type == IDENTIFIER) {
590  switch (type) {
591  case 'I':
592  if ( arg2.type == CONSTINT ) {
593  return CompareInt( newVal.I, op, arg2.I );
594  } else {
595  G4cerr << "integer operand expected for "
596  << parameterRange << '.'
597  << G4endl;
598  }
599  break;
600  case 'D':
601  if ( arg2.type == CONSTDOUBLE ) {
602  return CompareDouble( newVal.D, op, arg2.D );
603  } else
604  if ( arg2.type == CONSTINT ) { // integral promotion
605  return CompareDouble( newVal.D, op, arg2.I );
606  } break;
607  default: ;
608  }
609  }
610  if( arg2.type == IDENTIFIER) {
611  switch (type) {
612  case 'I':
613  if ( arg1.type == CONSTINT ) {
614  return CompareInt( arg1.I, op, newVal.I );
615  } else {
616  G4cerr << "integer operand expected for "
617  << parameterRange << '.'
618  << G4endl;
619  }
620  break;
621  case 'D':
622  if ( arg1.type == CONSTDOUBLE ) {
623  return CompareDouble( arg1.D, op, newVal.D );
624  } else
625  if ( arg1.type == CONSTINT ) { // integral promotion
626  return CompareDouble( arg1.I, op, newVal.D );
627  } break;
628  default: ;
629  }
630  }
631  G4cerr << "no param name is specified at the param range."<<G4endl;
632  return 0;
633 }
634 
636 CompareInt(G4int arg1, G4int op, G4int arg2)
637 {
638  G4int result=-1;
639  G4String opr;
640  switch (op) {
641  case GT: result = ( arg1 > arg2); opr= ">" ; break;
642  case GE: result = ( arg1 >= arg2); opr= ">="; break;
643  case LT: result = ( arg1 < arg2); opr= "<" ; break;
644  case LE: result = ( arg1 <= arg2); opr= "<="; break;
645  case EQ: result = ( arg1 == arg2); opr= "=="; break;
646  case NE: result = ( arg1 != arg2); opr= "!="; break;
647  default:
648  G4cerr << "Parameter range: error at CompareInt" << G4endl;
649  paramERR = 1;
650  }
651  #ifdef DEBUG
652  G4cerr << "CompareInt "
653  << arg1 << " " << opr << arg2
654  << " result: " << result
655  << G4endl;
656  #endif
657  return result;
658 }
659 
662 {
663  G4int result=-1;
664  G4String opr;
665  switch (op) {
666  case GT: result = ( arg1 > arg2); opr= ">"; break;
667  case GE: result = ( arg1 >= arg2); opr= ">="; break;
668  case LT: result = ( arg1 < arg2); opr= "<"; break;
669  case LE: result = ( arg1 <= arg2); opr= "<="; break;
670  case EQ: result = ( arg1 == arg2); opr= "=="; break;
671  case NE: result = ( arg1 != arg2); opr= "!="; break;
672  default:
673  G4cerr << "Parameter range: error at CompareDouble" << G4endl;
674  paramERR = 1;
675  }
676  #ifdef DEBUG
677  G4cerr << "CompareDouble "
678  << arg1 <<" " << opr << " "<< arg2
679  << " result: " << result
680  << G4endl;
681  #endif
682  return result;
683 }
684 
685 // --------------------- utility functions --------------------------
686 
688 Yylex() // reads input and returns token number KR486
689 { // (returns EOF)
690  G4int c;
691  G4String buf;
692 
693  while(( c= G4UIpGetc())==' '|| c=='\t' || c== '\n' )
694  ;
695  if (c== EOF)
696  return (tokenNum)EOF; // KR488
697  buf= "";
698  if (isdigit(c) || c== '.') { // I or D
699  do {
700  buf += G4String((unsigned char)c);
701  c=G4UIpGetc();
702  } while (c=='.' || isdigit(c) ||
703  c=='e' || c=='E' || c=='+' || c=='-');
704  G4UIpUngetc(c);
705  const char* t = buf;
706  std::istringstream is(t);
707  if ( IsInt(buf.data(),20) ) {
708  is >> yylval.I;
709  return CONSTINT;
710  } else
711  if ( IsDouble(buf.data()) ) {
712  is >> yylval.D;
713  return CONSTDOUBLE;
714  } else {
715  G4cerr << buf<<": numeric format error."<<G4endl;
716  }
717  }
718  buf="";
719  if (isalpha(c)|| c=='_') { // IDENTIFIER
720  do {
721  buf += G4String((unsigned char)c);
722  } while ((c=G4UIpGetc()) != EOF && (isalnum(c) || c=='_'));
723  G4UIpUngetc(c);
724  if( buf == parameterName ) {
725  yylval.S =buf;
726  return IDENTIFIER;
727  } else {
728  G4cerr << buf << " is not a parameter name."<< G4endl;
729  paramERR = 1;
730  }
731  }
732  switch (c) {
733  case '>': return (tokenNum) Follow('=', GE, GT);
734  case '<': return (tokenNum) Follow('=', LE, LT);
735  case '=': return (tokenNum) Follow('=', EQ, '=');
736  case '!': return (tokenNum) Follow('=', NE, '!');
737  case '|': return (tokenNum) Follow('|', LOGICALOR, '|');
738  case '&': return (tokenNum) Follow('&', LOGICALAND, '&');
739  default:
740  return (tokenNum) c;
741  }
742 }
743 
744 
746 Follow(G4int expect, G4int ifyes, G4int ifno)
747 {
748  G4int c = G4UIpGetc();
749  if ( c== expect)
750  return ifyes;
751  G4UIpUngetc(c);
752  return ifno;
753 }
754 
755 //------------------ low level routines -----------------------------
757 G4UIpGetc() { // emulation of getc()
758  G4int length = parameterRange.length();
759  if( bp < length)
760  return parameterRange(bp++);
761  else
762  return EOF;
763 }
765 G4UIpUngetc(G4int c) { // emulation of ungetc()
766  if (c<0) return -1;
767  if (bp >0 && c == parameterRange(bp-1)) {
768  --bp;
769  } else {
770  G4cerr << "G4UIpUngetc() failed." << G4endl;
771  G4cerr << "bp="<<bp <<" c="<<c
772  << " pR(bp-1)=" << parameterRange(bp-1)
773  << G4endl;
774  paramERR = 1;
775  return -1;
776  }
777  return 0;
778 }
779 // ***** end of CheckNewValue() related code ******
780