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