cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
parser.cpp
Go to the documentation of this file.
1 /* This file is part of Cloudy and is copyright (C)1978-2017 by Gary J. Ferland and
2  * others. For conditions of distribution and use see copyright notice in license.txt */
3 
4 #include "cddefines.h"
5 #include "parser.h"
6 #include "called.h"
7 #include "flux.h"
8 #include "input.h"
9 #include "elementnames.h"
10 #include "service.h"
11 #include "depth_table.h"
12 #include "lines.h"
13 
14 #include <deque>
15 namespace
16 {
17  class Token
18  {
19  public:
20  enum symType { symNull, symNumber, symOp, symVar };
21  string s;
22  symType t;
23  explicit Token(enum symType type) : s(""), t(type) {}
24  explicit Token() : s(""), t(symNull) {}
25  };
26 }
27 
28 typedef std::map<string,double> symtab;
29 STATIC bool ParseExpr(deque<Token> &chTokens, vector<double> &valstack,
30  const symtab &tab);
31 
32 const char *Parser::nWord(const char *chKey) const
33 {
34  return ::nWord(chKey, m_card);
35 }
36 
37 bool Parser::at_end() const
38 {
39  return current() == '\0';
40 }
41 char Parser::current_raw() const
42 {
43  return m_card_raw[m_off];
44 }
46 {
48  // transform(m_card.begin(),m_card.end(),m_card.begin(),toupper);
49  ::caps(m_card);
50  m_len = strlen(m_card);
51  m_off = 0;
52  m_lgEOL = false;
53 }
54 
55 /*nWord determine whether match to a keyword occurs on command line,
56  * return value is 0 if no match, and position of match within string if hit */
57 const char *nWord(const char *chKey,
58  const char *chCard)
59 {
60  DEBUG_ENTRY( "nWord()" );
61 
62  // Ignore leading space in chKey -- logic below is designed
63  // to avoid the need to include this in the first place
64  while (isspace(*chKey))
65  {
66  ++chKey;
67  }
68 
69  const long lenkey = strlen(chKey);
70  ASSERT( lenkey > 0 );
71 
72  bool atBoundary = true, inQuote=false;
73  for (const char *ptr = chCard; *ptr; ++ptr)
74  {
75  if (!inQuote)
76  {
77  if (*ptr == '\"')
78  {
79  inQuote = true;
80  }
81  else
82  {
83  if ( atBoundary && strncmp( ptr, chKey, lenkey) == 0 )
84  {
85  return ptr;
86  }
87 
88  atBoundary = isBoundaryChar(*ptr);
89  }
90  }
91  else
92  {
93  if (*ptr == '\"')
94  {
95  inQuote = false;
96  }
97  }
98  }
99 
100  return NULL;
101 }
102 
103 bool isBoundaryChar(char c)
104 {
105  const bool lgAnyWhitespacePrecedesWord = false;
106 
107  if (lgAnyWhitespacePrecedesWord)
108  return isspace(c) ? true : false ;
109  else // Words are strings starting with A-Z, a-z or _
110  return (! isalpha(c) ) && c != '_';
111 }
112 
113 bool Parser::isComment(void) const
114 {
115  return lgInputComment(m_card);
116 }
117 bool Parser::isCommandComment(void) const
118 {
119  return ( m_card[0]=='C' && (m_card[1]==' ' || m_card[1]== '\0')) ||
120  isComment();
121 }
122 bool Parser::isVar(void) const
123 {
124  return ( current()=='$' );
125 }
126 std::string Parser::getVarName(void)
127 {
128  std::string name("");
129  while (!at_end())
130  {
131  char c = current();
132  if (!(isalnum(c) || c == '_'))
133  break;
134  name += c;
135  ++m_off;
136  }
137  return name;
138 }
140 {
141  DEBUG_ENTRY( "Parser::doSetVar()" );
142  char c='\0';
143  ++m_off;
144  std::string name = getVarName();
145  while (!at_end())
146  {
147  c = current();
148  ++m_off;
149  if (c == '=')
150  break;
151  }
152  if (at_end())
153  {
154  fprintf(ioQQQ,"Expected '=' in variable definition\n");
156  }
157  while (!at_end())
158  {
159  c = current();
160  if (c != ' ')
161  break;
162  ++m_off;
163  }
164  m_symtab[name] = FFmtRead();
165 }
166 
167 void Parser::echo(void) const
168 {
169  /* >>chng 04 jan 21, add HIDE option, mostly for print quiet command */
170  if( called.lgTalk && !::nMatch("HIDE",m_card) )
171  fprintf( ioQQQ, "%23c* %-80s*\n", ' ', m_card_raw );
172 }
173 
175 {
176  Error(
177  " A filename or label must be specified within double quotes, but no quotes were encountered on this command.\n"
178  " Name must be surrounded by exactly two double quotes, like \"name.txt\". \n"
179  );
180 }
181 
184 int Parser::GetQuote( string& chLabel )
185 {
186  DEBUG_ENTRY( "Parser::GetQuote()" );
187 
188  /* find first quote start of string, string begins and ends with quotes */
189  char *i0 = strchr_s( m_card_raw,'\"' );
190 
191  char *i1 = NULL;
192  if( i0 != NULL )
193  {
194  /* get pointer to next quote */
195  i1 = strchr_s( i0+1 ,'\"' );
196  }
197 
198  /* check that pointers were not NULL */
199  /* >>chng 00 apr 27, check for i0 and i1 equal not needed anymore, by PvH */
200  if( i0 == NULL || i1 == NULL )
201  {
202  /* this branch, ok if not present, return null string in that case */
203  chLabel = "";
204  /* return value of 1 indicates did not find double quotes */
205  return 1;
206  }
207 
208  /* now copy the text in between quotes */
209  chLabel = string(i0+1,i1);
210 
211  /* get pointer to first quote in local copy of line image in calling routine */ char *iLoc = strchr_s( m_card, '\"' );
212  if( iLoc == NULL )
213  TotalInsanity();
214 
215  // blank out label once finished, to not be picked up later
216  // erase quotes as well, so that we can find second label, by PvH
217  while( i0 <= i1 )
218  {
219  *i0 = ' ';
220  *iLoc = ' ';
221  ++i0;
222  ++iLoc;
223  }
224  /* return condition of 0 indicates success */
225  return 0;
226 }
227 
228 NORETURN void Parser::Error(const char* msg) const
229 {
230  DEBUG_ENTRY( "Parser::Error()" );
231  fprintf( ioQQQ, " Parser failure\n");
232  if (msg)
233  fprintf(ioQQQ,"%s",msg);
234  fprintf( ioQQQ, " The line image was\n");
235  PrintLine(ioQQQ);
236  fprintf( ioQQQ, " Sorry.\n" );
238 }
240 {
241  DEBUG_ENTRY( "Parser::CommandError()" );
242  fprintf( ioQQQ, " Unrecognized command. Key=\"%4.4s\". This is routine ParseCommands.\n",
243  m_card );
244  fprintf( ioQQQ, " The line image was\n");
245  PrintLine(ioQQQ);
246  fprintf( ioQQQ, " Sorry.\n" );
248 }
249 bool Parser::getline(void)
250 {
252  newlineProcess();
253  if (m_lgEOF)
254  return false;
255  else
256  return true;
257 }
258 
259 const char *Parser::StandardEnergyUnit(void) const
260 {
262 }
263 string Parser::StandardFluxUnit(void) const
264 {
266 }
267 void Parser::help(FILE *fp) const
268 {
269  DEBUG_ENTRY( "Parser::help()" );
270  fprintf(fp,"Available commands are:\n\n");
271  long int i=0, l=0, len;
272  while (1)
273  {
274  len = strlen(m_Commands[i].name);
275  if (l+len+2 > 80)
276  {
277  fprintf(fp,"\n");
278  l = 0;
279  }
280  l += len+2;
281  fprintf(fp,"%s",m_Commands[i].name);
282  ++i;
283  if (m_Commands[i].name == NULL)
284  break;
285  fprintf(fp,", ");
286  }
287 
288  fprintf(fp,"\n\nSorry, no further help available yet -- try Hazy.\n\n");
290 }
291 
292 /*GetElem scans line image, finds element. returns atomic number j,
293  * on C scale, -1 if no hit. chCARD_CAPS must be in CAPS to hit element */
294 long int Parser::GetElem(void ) const
295 {
296  int i;
297 
298  DEBUG_ENTRY( "Parser::GetElem()" );
299 
300  /* find which element */
301 
302  /* >>>chng 99 apr 17, lower limit to loop had been 1, so search started with helium,
303  * change to 0 so we can pick up hydrogen. needed for parseasserts command */
304  /* find match with element name, start with helium */
305  for( i=0; i<(int)LIMELM; ++i )
306  {
308  {
309  /* return value is in C counting, hydrogen would be 0*/
310  return i;
311  }
312  }
313  /* fall through, did not hit, return -1 as error condition */
314  return (-1 );
315 }
316 
317 /*NoNumb general error handler for no numbers on input line */
318 NORETURN void Parser::NoNumb(const char * chDesc) const
319 {
320  DEBUG_ENTRY( "Parser::NoNumb()" );
321 
322  /* general catch-all for no number when there should have been */
323  fprintf( ioQQQ, " There is a problem on the following command line:\n" );
324  fprintf( ioQQQ, " %s\n", m_card_raw );
325  fprintf( ioQQQ, " A value for %s should have been on this line.\n Sorry.\n",chDesc );
327  }
328 
330 {
331  double val = FFmtRead();
332  /* check for optional micron or cm units, else interpret as Angstroms */
333  if( current() == 'M' )
334  {
335  /* microns */
336  val *= 1e4;
337  }
338  else if( current() == 'C' )
339  {
340  /* centimeters */
341  val *= 1e8;
342  }
343  return val;
344 }
346 {
347  double val = getWaveOpt();
348  if( lgEOL() )
349  {
350  NoNumb("wavelength");
351  }
352  return val;
353 }
354 double Parser::getNumberPlain( const char * )
355 {
356  return FFmtRead();
357 }
358 double Parser::getNumberCheck( const char *chDesc )
359 {
360  double val = FFmtRead();
361  if( lgEOL() )
362  {
363  NoNumb(chDesc);
364  }
365  return val;
366 }
367 double Parser::getNumberDefault( const char *, double fdef )
368 {
369  double val = FFmtRead();
370  if( lgEOL() )
371  {
372  val = fdef;
373  }
374  return val;
375 }
376 double Parser::getNumberCheckLogLinNegImplLog( const char *chDesc )
377 {
378  double val = getNumberCheck(chDesc);
379  if( nMatch(" LOG") )
380  {
381  val = exp10(val);
382  }
383  else if(! nMatch("LINE") )
384  {
385  /* log, linear not specified, neg so log */
386  if( val <= 0. )
387  {
388  val = exp10(val);
389  }
390  }
391  return val;
392 }
393 double Parser::getNumberCheckAlwaysLog( const char *chDesc )
394 {
395  double val = getNumberCheck(chDesc);
396  val = exp10( val);
397  return val;
398 }
399 double Parser::getNumberCheckAlwaysLogLim( const char *chDesc, double flim )
400 {
401  double val = getNumberCheck(chDesc);
402  if ( val > flim )
403  {
404  fprintf(ioQQQ,"WARNING - the log of %s is too "
405  "large, I shall probably crash. The value was %.2e\n",
406  chDesc, val );
407  fflush(ioQQQ);
408  }
409  val = exp10( val);
410  return val;
411 }
412 double Parser::getNumberDefaultAlwaysLog( const char *, double fdef )
413 {
414  double val = exp10(FFmtRead());
415  if ( lgEOL() )
416  {
417  val = fdef;
418  }
419  return val;
420 }
421 double Parser::getNumberDefaultNegImplLog( const char *, double fdef )
422 {
423  double val = FFmtRead();
424  if ( lgEOL() )
425  {
426  val = fdef;
427  }
428  if (val < 0.0)
429  {
430  val = exp10(val);
431  }
432  return val;
433 }
434 
435 /*FFmtRead scan input line for free format number */
436 
437 
438 double Parser::FFmtRead(void)
439 {
440 
441  DEBUG_ENTRY( "Parser::FFmtRead()" );
442 
443  // Look for start of next expression
444  while( m_off < m_len)
445  {
446  if ( current() == '$' )
447  break;
448  int loff = m_off;
449  char lchr = current();
450  if( lchr == '-' || lchr == '+' )
451  {
452  ++loff;
453  lchr = m_card[loff];
454  }
455  if( lchr == '.' )
456  {
457  ++loff;
458  lchr = m_card[loff];
459  }
460  if( isdigit(lchr) )
461  break;
462  ++m_off;
463  }
464 
465  if( m_off == m_len )
466  {
467  m_lgEOL = true;
468  return 0.;
469  }
470 
471  // Lexer for expression
472  deque<Token> chTokens(0);
473  for(char chr = current();
474  m_off < m_len &&
475  (isdigit(chr) || chr == '.' || chr == '-' || chr == '+'
476  || chr == 'e' || chr == 'E' || chr == '^' || chr == '*' || chr == '/'
477  || chr == '$')
478  ; chr = current())
479  {
480  if (chr == '^' || chr == '*' || chr == '/' )
481  {
482  chTokens.push_back(Token(Token::symOp));
483  chTokens.back().s += chr;
484  ++m_off;
485  }
486  else if (chr == '$')
487  {
488  chTokens.push_back(Token(Token::symVar));
489  ++m_off;
490  chTokens.back().s += getVarName();
491  }
492  else
493  {
494  if (chTokens.size() == 0 || chTokens.back().t != Token::symNumber)
495  chTokens.push_back(Token(Token::symNumber));
496  chTokens.back().s += chr;
497  ++m_off;
498  }
499  }
500 
501  ASSERT (chTokens.size() != 0);
502 
503  // Parse tokens
504  vector<double> valstack;
505  const bool lgParseOK = ParseExpr(chTokens, valstack, m_symtab);
506  if (!lgParseOK || 1 != valstack.size())
507  {
508  fprintf(ioQQQ," PROBLEM - syntax error in number or expression on line\n");
509  fprintf(ioQQQ, "== %-80s ==\n",m_card);
510  m_lgEOL = true;
511  return 0.;
512  }
513 
514  double value = valstack[0];
515 
516  m_lgEOL = false;
517  return value;
518 }
519 
520 string Parser::getFirstChunk(long nchar)
521 {
522  DEBUG_ENTRY( "Parser::getFirstChunk()" );
523  if (m_len < nchar)
524  {
525  fprintf(ioQQQ,
526  "PROBLEM --"
527  " input line too short to provide %ld character label\n"
528  "== %-80s ==\n", nchar,m_card);
530  }
531  m_off = nchar;
532  return string(m_card).substr(0,nchar);
533 }
534 
536 {
537  DEBUG_ENTRY( "Parser::getLineID()" );
538  LineID line;
539  if( GetQuote( line.chLabel )==0 )
540  {
542  }
543  else
544  {
545  /* order on line is label (col 1-4), wavelength */
546  line.chLabel = getFirstChunk(4);
547  }
548 
549  // Normalize common error "H 1 " or "H 1" for "H 1"
550  if ( line.chLabel.size() == 3 || line.chLabel.size() == 4 )
551  {
552  if ( line.chLabel[1] == ' ' &&
553  ( line.chLabel.size() == 3 || line.chLabel[3] == ' ') )
554  {
555  fprintf(ioQQQ,"WARNING: read \"%s\" as spectrum\n",line.chLabel.c_str());
556  if (line.chLabel.size() == 3)
557  line.chLabel += line.chLabel[2];
558  else
559  line.chLabel[3] = line.chLabel[2];
560  line.chLabel[2] = ' ';
561  fprintf(ioQQQ,"Assuming required spectrum is \"%s\"\n",line.chLabel.c_str());
562  }
563  }
564 
565  /* now get wavelength */
566  line.wave = (realnum)getWaveOpt();
567  return line;
568 }
569 
570 // Simple recursive descent parser for expressions
571 //
572 // for discussion, see e.g. http://www.ddj.com/architect/184406384
573 //
574 // for a possibly more efficient alternative, see
575 // http://eli.thegreenplace.net/2010/01/02/top-down-operator-precedence-parsing/
576 
577 STATIC bool ParseNumber(deque<Token> &chTokens, vector<double> &valstack,
578  const symtab &tab)
579 {
580  DEBUG_ENTRY( "ParseNumber()" );
581  if ( chTokens.size() < 1)
582  return false;
583 
584  if (Token::symNumber == chTokens[0].t)
585  {
586  valstack.push_back(atof(chTokens[0].s.c_str()));
587  chTokens.pop_front();
588  return true;
589  }
590  if (Token::symVar == chTokens[0].t)
591  {
592  symtab::const_iterator var = tab.find(chTokens[0].s);
593  if (var == tab.end())
594  {
595  fprintf(ioQQQ,"ERROR: No value found for variable $%s\n",
596  chTokens[0].s.c_str());
598  }
599  valstack.push_back(var->second);
600  chTokens.pop_front();
601  return true;
602  }
603 
604  return false;
605 }
606 
607 STATIC bool doop(vector<double> &valstack, const string &op)
608 {
609  DEBUG_ENTRY( "doop()" );
610  const double v2 = valstack.back();
611  valstack.pop_back();
612  const double v1 = valstack.back();
613  valstack.pop_back();
614  double result;
615  if (op == "^")
616  {
617  result = pow(v1,v2);
618  }
619  else if (op == "*")
620  {
621  result = v1*v2;
622  }
623  else if (op == "/")
624  {
625  result = v1/v2;
626  }
627  else
628  {
629  fprintf(ioQQQ,"Unknown operator '%s'\n",op.c_str());
630  return false;
631  }
632  valstack.push_back(result);
633  return true;
634 }
635 
636 STATIC bool ParseExp(deque<Token> &chTokens, vector<double> &valstack,
637  const symtab& tab)
638 {
639  DEBUG_ENTRY( "ParseExp()" );
640  // Right-associative -- need to buffer into stack
641  vector<string> opstack;
642  if (!ParseNumber(chTokens, valstack, tab))
643  return false;
644 
645  while (1)
646  {
647  if ( chTokens.size() == 0 )
648  break;
649 
650  if ( chTokens.size() < 2 )
651  return false;
652 
653  if ( Token::symOp != chTokens[0].t || "^" != chTokens[0].s )
654  break;
655 
656  opstack.push_back(chTokens[0].s);
657  chTokens.pop_front();
658 
659  if (!ParseNumber(chTokens, valstack, tab))
660  return false;
661  }
662 
663  while (!opstack.empty())
664  {
665  if (!doop(valstack, opstack.back()))
666  return false;
667  opstack.pop_back();
668  }
669  return true;
670 }
671 
672 STATIC bool ParseProduct(deque<Token> &chTokens, vector<double> &valstack,
673  const symtab& tab)
674 {
675  DEBUG_ENTRY( "ParseProduct()" );
676  // Left-associative
677  if (!ParseExp(chTokens, valstack, tab))
678  return false;
679 
680  while ( chTokens.size() > 0 &&
681  Token::symOp == chTokens[0].t &&
682  ( "*" == chTokens[0].s || "/" == chTokens[0].s ) )
683  {
684  string op = chTokens[0].s;
685  chTokens.pop_front();
686 
687  if (!ParseExp(chTokens, valstack, tab))
688  return false;
689 
690  if (!doop(valstack, op))
691  return false;
692  }
693  return true;
694 }
695 
696 STATIC bool ParseExpr(deque<Token> &chTokens, vector<double> &valstack,
697  const symtab& tab)
698 {
699  DEBUG_ENTRY( "ParseExpr()" );
700  if (ParseProduct(chTokens, valstack,tab))
701  return true;
702  return false;
703 }
704 
705 bool Parser::hasCommand(const char *s2)
706 {
707  DEBUG_ENTRY( "Parser::hasCommand()" );
708  size_t len = strlen(s2);
709  if (::strncmp(m_card, s2, len) != 0)
710  return false;
711 
712  while (isspace(m_card[len-1]))
713  {
714  --len;
715  }
716 
717  // Fast forward over any tail to command, i.e. ignore non-space
718  // characters after len but before next space
719  m_off = len;
720  while (!at_end() && (isalnum(current()) || current() == '_'))
721  ++m_off;
722  while (!at_end() && isspace(current()))
723  ++m_off;
724 
725  return true;
726 }
727 
728 void Parser::getPairs(vector<double>& a, vector<double> & b)
729 {
730  DEBUG_ENTRY( "Parser::getPairs()" );
731  a.resize(0);
732  b.resize(0);
733  for(;;)
734  {
735  getline();
736 
737  if( m_lgEOF )
738  {
739  fprintf( ioQQQ, " Hit EOF while reading element list; use END to end list.\n" );
741  }
742 
743  if( isComment())
744  continue;
745 
746  /* this would be a line starting with END to say end on list */
747  if( hasCommand("END") )
748  {
749  return;
750  }
751  a.push_back(FFmtRead());
752  if( lgEOL() )
753  {
754  fprintf( ioQQQ, " There must be a two numbers on this line, or END.\n" );
755  fprintf( ioQQQ, " Sorry.\n" );
757  }
758  b.push_back(FFmtRead());
759  if( lgEOL() )
760  {
761  fprintf( ioQQQ, " There must be a two numbers on this line, or END.\n" );
762  fprintf( ioQQQ, " Sorry.\n" );
764  }
765  }
766 }
767 
768 
769 inline Symbol maybeNumber(bool numOK, const Symbol &s)
770 {
771  DEBUG_ENTRY( "maybeNumber()" );
772  if (numOK)
773  {
774  return s;
775  }
776  else
777  {
778  fprintf(ioQQQ,"Parser error, incomplete number"
779  " at end of input term, error after '%s'\n",s.value.c_str());
780  return Symbol(Symbol::ERROR,s.value);
781  }
782 }
783 
785 {
786  DEBUG_ENTRY( "Parser::getSymbol()" );
787  // Eat leading space
788  while (!at_end())
789  {
790  char c = current();
791  if (c != ' ' && c != '\t')
792  break;
793  ++m_off;
794  }
795 
796  if ( at_end() || current() == '\n')
797  return Symbol(Symbol::EOSTAT,"");
798 
799  if (isdigit(current()) || current() == '-' || current() == '.')
800  {
801  Symbol s(Symbol::NUMBER,"");
802  bool numOK=false;
803  if (current() == '-')
804  {
805  s.value += current();
806  ++m_off;
807  if (at_end())
808  return maybeNumber(numOK,s);
809  }
810  if (isdigit(current()))
811  {
812  numOK = true;
813  do
814  {
815  s.value += current();
816  ++m_off;
817  }
818  while (!at_end() && isdigit(current()));
819  if (at_end() )
820  return maybeNumber(numOK,s);
821  }
822  if (current() == '.')
823  {
824  s.value += current();
825  ++m_off;
826  }
827  while (!at_end() && isdigit(current()))
828  {
829  numOK = true;
830  s.value += current();
831  ++m_off;
832  }
833  if ( at_end() || current() != 'E' || !numOK)
834  {
835  return maybeNumber(numOK,s);
836  }
837  s.value += current();
838  ++m_off;
839  numOK = false;
840  if (current() == '-' || current() == '+')
841  {
842  s.value += current();
843  ++m_off;
844  if (at_end())
845  return maybeNumber(numOK,s);
846  }
847  while (!at_end() && isdigit(current()))
848  {
849  numOK = true;
850  s.value += current();
851  ++m_off;
852  }
853  return maybeNumber(numOK,s);
854  }
855 
856  if (isalpha(current()))
857  {
858  Symbol s(Symbol::NAME,"");
859  do
860  {
861  s.value += current();
862  ++m_off;
863  }
864  while (!at_end() && (isalnum(current()) || current() == '_'));
865  return s;
866  }
867 
868  if ( current() == '"' )
869  {
870  Symbol s(Symbol::STRING,"");
871  ++m_off;
872  while (!at_end() && current() != '\"')
873  {
874  if (current() == '\\')
875  {
876  ++m_off;
877  if (at_end())
878  {
879  fprintf(ioQQQ,"Parser error, escape character '\\'"
880  " at end of input term\n");
881  return Symbol(Symbol::ERROR,s.value);
882  }
883  }
884  s.value += current_raw();
885  ++m_off;
886  }
887 
888  if (at_end())
889  {
890  fprintf(ioQQQ,"Parser error, unterminated string\n");
891  return Symbol(Symbol::ERROR,s.value);
892  }
893  ++m_off;
894  return s;
895  }
896 
897  if ( current() == ',' || current() == '(' || current() == ')' || current() == '=' )
898  {
899  Symbol s(Symbol::OPERATOR,"");
900  s.value += current();
901  ++m_off;
902  return s;
903  }
904 
905  fprintf(ioQQQ,"Parser error, character not recognized '%c'\n",
906  current());
907  return Symbol(Symbol::ERROR,"");
908 }
909 void Parser::readList(vector<string>& list, const char* chName)
910 {
911  DEBUG_ENTRY( "Parser::readList()" );
912  list.clear();
913  while( 1 )
914  {
915  getline();
916  if( m_lgEOF )
917  {
918  fprintf( ioQQQ,
919  " Save %s hit EOF while reading list; use END to end list.\n" ,chName);
920  fprintf( ioQQQ,
921  " This command requires either a species within quotes or the keyword ALL.\n" );
923  }
924  if( isComment())
925  continue;
926  if (hasCommand("END" ))
927  break;
928  string chTerm;
929  if (!GetQuote(chTerm))
930  list.push_back(chTerm);
931  else
932  list.push_back(m_card_raw);
933  }
934 }
935 
937 {
938  DEBUG_ENTRY( "Parser::readLaw()" );
939  if( nMatch("DEPT") )
940  {
941  table.lgDepth = true;
942  }
943  else
944  {
945  table.lgDepth = false;
946  }
947  if (table.nvals != 0)
948  {
949  fprintf( ioQQQ, " Warning: over-writing existing table\n" );
950  table.clear();
951  }
952 
953  getline();
954  table.dist.push_back(FFmtRead());
955  table.val.push_back(FFmtRead());
956  if( lgEOL() )
957  {
958  fprintf( ioQQQ, " No pairs entered - can\'t interpolate.\n Sorry.\n" );
960  }
961 
962  table.nvals = 2;
963  bool lgEnd = false;
964 
965  /* read pairs of numbers until we find line starting with END */
966  /* >>chng 04 jan 27, loop to LIMTABDLAW from LIMTABD, as per
967  * var definitions, caught by Will Henney */
968  while( !lgEnd )
969  {
970  getline();
971  lgEnd = m_lgEOF;
972  if( !lgEnd )
973  {
974  lgEnd = hasCommand("END");
975  }
976 
977  if( !lgEnd )
978  {
979  double dist = FFmtRead();
980  double val = FFmtRead();
981  if (lgEOL())
982  NoNumb("radius, value pair on each line");
983  table.dist.push_back( dist );
984  table.val.push_back( val );
985  table.nvals += 1;
986  }
987  }
988  --table.nvals;
989 
990  for( long i=1; i < table.nvals; i++ )
991  {
992  /* the radius values are assumed to be strictly increasing */
993  if( table.dist[i] <= table.dist[i-1] )
994  {
995  fprintf( ioQQQ, " Radii must be in increasing order. Sorry.\n" );
997  }
998  }
999 }
bool nMatch(const char *chKey) const
Definition: parser.h:140
long int nvals
Definition: depth_table.h:17
bool hasCommand(const char *s2)
Definition: parser.cpp:705
Symbol maybeNumber(bool numOK, const Symbol &s)
Definition: parser.cpp:769
void echo(void) const
Definition: parser.cpp:167
realnum wave
Definition: lines.h:18
double FFmtRead(void)
Definition: parser.cpp:438
double exp10(double x)
Definition: cddefines.h:1383
#define NORETURN
Definition: cpu.h:451
NORETURN void TotalInsanity(void)
Definition: service.cpp:1067
t_input input
Definition: input.cpp:12
double getNumberCheckLogLinNegImplLog(const char *chDesc)
Definition: parser.cpp:376
bool m_lgEOL
Definition: parser.h:48
STATIC bool ParseProduct(deque< Token > &chTokens, vector< double > &valstack, const symtab &tab)
Definition: parser.cpp:672
void readList(vector< string > &list, const char *chName)
Definition: parser.cpp:909
int GetQuote(string &chLabel)
Definition: parser.cpp:184
char m_card[INPUT_LINE_LENGTH]
Definition: parser.h:44
bool at_end() const
Definition: parser.cpp:37
bool isCommandComment(void) const
Definition: parser.cpp:117
void newlineProcess()
Definition: parser.cpp:45
double getNumberDefaultAlwaysLog(const char *chDesc, double fdef)
Definition: parser.cpp:412
STATIC bool ParseExpr(deque< Token > &chTokens, vector< double > &valstack, const symtab &tab)
Definition: parser.cpp:696
long int m_off
Definition: parser.h:47
Definition: lines.h:14
FILE * ioQQQ
Definition: cddefines.cpp:7
string chLabel
Definition: lines.h:17
double getWave()
Definition: parser.cpp:345
bool lgTalk
Definition: called.h:12
bool isBoundaryChar(char c)
Definition: parser.cpp:103
Symbol getSymbol()
Definition: parser.cpp:784
STATIC bool doop(vector< double > &valstack, const string &op)
Definition: parser.cpp:607
void trimTrailingWhiteSpace(string &str)
Definition: service.cpp:155
NORETURN void StringError() const
Definition: parser.cpp:174
double getNumberPlain(const char *chDesc)
Definition: parser.cpp:354
char m_card_raw[INPUT_LINE_LENGTH]
Definition: parser.h:44
t_elementnames elementnames
Definition: elementnames.cpp:5
LineID getLineID()
Definition: parser.cpp:535
bool lgDepth
Definition: depth_table.h:11
string StandardFluxUnit(void) const
Definition: parser.cpp:263
#define STATIC
Definition: cddefines.h:118
float realnum
Definition: cddefines.h:124
const char * StandardEnergyUnit(void) const
Definition: parser.cpp:259
#define EXIT_FAILURE
Definition: cddefines.h:168
const int INPUT_LINE_LENGTH
Definition: cddefines.h:301
void clear()
Definition: depth_table.h:24
#define cdEXIT(FAIL)
Definition: cddefines.h:484
NORETURN void NoNumb(const char *chDesc) const
Definition: parser.cpp:318
STATIC bool ParseExp(deque< Token > &chTokens, vector< double > &valstack, const symtab &tab)
Definition: parser.cpp:636
const char * strchr_s(const char *s, int c)
Definition: cddefines.h:1325
long int GetElem(void) const
Definition: parser.cpp:294
const char * nWord(const char *chKey) const
Definition: parser.cpp:32
string getFirstChunk(long i)
Definition: parser.cpp:520
string StandardFluxUnit(const char *chCard)
Definition: flux.cpp:205
char chElementNameShort[LIMELM][CHARS_ELEMENT_NAME_SHORT]
Definition: elementnames.h:21
bool isVar(void) const
Definition: parser.cpp:122
const char * nWord(const char *chKey, const char *chCard)
Definition: parser.cpp:57
STATIC double dist(long, realnum[], realnum[])
long int m_len
Definition: parser.h:46
vector< double > dist
Definition: depth_table.h:13
void readarray(char *chCard, bool *lgEOF)
Definition: input.cpp:127
double getNumberCheckAlwaysLogLim(const char *chDesc, double flim)
Definition: parser.cpp:399
void help(FILE *fp) const
Definition: parser.cpp:267
#define ASSERT(exp)
Definition: cddefines.h:617
const char * StandardEnergyUnit(const char *chCard)
Definition: energy.cpp:44
bool getline()
Definition: parser.cpp:249
const int LIMELM
Definition: cddefines.h:307
NORETURN void Error(const char *msg) const
Definition: parser.cpp:228
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:729
vector< double > val
Definition: depth_table.h:14
STATIC bool ParseNumber(deque< Token > &chTokens, vector< double > &valstack, const symtab &tab)
Definition: parser.cpp:577
double getNumberCheckAlwaysLog(const char *chDesc)
Definition: parser.cpp:393
const CloudyCommand *const m_Commands
Definition: parser.h:49
double getNumberDefault(const char *chDesc, double fdef)
Definition: parser.cpp:367
char current(void) const
Definition: parser.h:72
std::map< string, double > symtab
Definition: parser.cpp:28
bool lgEOL(void) const
Definition: parser.h:103
string value
Definition: parser.h:37
int fprintf(const Output &stream, const char *format,...)
Definition: service.cpp:1217
NORETURN void CommandError(void) const
Definition: parser.cpp:239
void getPairs(vector< double > &a, vector< double > &b)
Definition: parser.cpp:728
bool lgInputComment(const char *chLine)
Definition: input.cpp:31
double pow(double x, int i)
Definition: cddefines.h:782
char current_raw() const
Definition: parser.cpp:41
int PrintLine(FILE *fp) const
Definition: parser.h:200
std::string getVarName(void)
Definition: parser.cpp:126
void caps(char *chCard)
Definition: service.cpp:304
bool m_lgEOF
Definition: parser.h:53
Definition: parser.h:33
void readLaw(DepthTable &table)
Definition: parser.cpp:936
void doSetVar(void)
Definition: parser.cpp:139
double getNumberDefaultNegImplLog(const char *chDesc, double fdef)
Definition: parser.cpp:421
double getWaveOpt()
Definition: parser.cpp:329
std::map< string, double > m_symtab
Definition: parser.h:50
t_called called
Definition: called.cpp:4
bool isComment(void) const
Definition: parser.cpp:113
#define EXIT_SUCCESS
Definition: cddefines.h:166
double getNumberCheck(const char *chDesc)
Definition: parser.cpp:358