00001
00002
00003
00004 #include "cddefines.h"
00005 #include "parser.h"
00006 #include "called.h"
00007 #include "energy.h"
00008 #include "flux.h"
00009 #include "input.h"
00010 #include "elementnames.h"
00011
00012 #include <deque>
00013 class Token
00014 {
00015 public:
00016 enum symType { symNull, symNumber, symOp };
00017 string s;
00018 symType t;
00019 explicit Token(enum symType type) : s(""), t(type) {}
00020 explicit Token() : s(""), t(symNull) {}
00021 };
00022 STATIC bool ParseExpr(deque<Token> &chTokens, vector<double> &valstack);
00023
00024 const char *Parser::nWord(const char *chKey) const
00025 {
00026 return ::nWord(chKey, m_card);
00027 }
00028
00029
00030
00031 const char *nWord(const char *chKey,
00032 const char *chCard)
00033 {
00034 DEBUG_ENTRY( "nWord()" );
00035
00036
00037
00038 while (isspace(*chKey))
00039 {
00040 ++chKey;
00041 }
00042
00043 const long lenkey = strlen(chKey);
00044 ASSERT( lenkey > 0 );
00045
00046 bool atBoundary = true;
00047 for (const char *ptr = chCard; *ptr; ++ptr)
00048 {
00049 if ( atBoundary && strncmp( ptr, chKey, lenkey) == 0 )
00050 {
00051 return ptr;
00052 }
00053
00054 atBoundary = isBoundaryChar(*ptr);
00055 }
00056
00057 return NULL;
00058 }
00059
00060 bool isBoundaryChar(char c)
00061 {
00062 const bool lgAnyWhitespacePrecedesWord = false;
00063
00064 if (lgAnyWhitespacePrecedesWord)
00065 return isspace(c) ? true : false ;
00066 else
00067 return (! isalpha(c) ) && c != '_' && c != '-';
00068 }
00069
00070 bool Parser::isComment(void) const
00071 {
00072 return lgInputComment(m_card);
00073 }
00074 bool Parser::isCommandComment(void) const
00075 {
00076 return ( m_card[0]=='C' && (m_card[1]==' ' || m_card[1]== '\0')) ||
00077 isComment();
00078 }
00079
00080 void Parser::echo(void) const
00081 {
00082
00083 if( called.lgTalk && !::nMatch("HIDE",m_card) )
00084 fprintf( ioQQQ, "%23c* %-80s*\n", ' ', m_card_raw );
00085 }
00086
00087 NORETURN void Parser::CommandError(void) const
00088 {
00089 DEBUG_ENTRY(" Parser::CommandError()");
00090 fprintf( ioQQQ, " Unrecognized command. Key=\"%4.4s\". This is routine ParseCommands.\n",
00091 m_card );
00092 fprintf( ioQQQ, " The line image was\n");
00093 PrintLine(ioQQQ);
00094 fprintf( ioQQQ, " Sorry.\n" );
00095 cdEXIT(EXIT_FAILURE);
00096 }
00097 bool Parser::getline(void)
00098 {
00099 input.readarray(m_card_raw,&m_lgEOF);
00100 newlineProcess();
00101 if (m_lgEOF)
00102 return false;
00103 else
00104 return true;
00105 }
00106
00107 const char *Parser::StandardEnergyUnit(void) const
00108 {
00109 return ::StandardEnergyUnit(m_card);
00110 }
00111 string Parser::StandardFluxUnit(void) const
00112 {
00113 return ::StandardFluxUnit(m_card);
00114 }
00115 void Parser::help(FILE *fp) const
00116 {
00117 DEBUG_ENTRY("Parser::help()");
00118 fprintf(fp,"Available commands are:\n\n");
00119 long int i=0, l=0, len;
00120 while (1)
00121 {
00122 len = strlen(m_Commands[i].name);
00123 if (l+len+2 > 80)
00124 {
00125 fprintf(fp,"\n");
00126 l = 0;
00127 }
00128 l += len+2;
00129 fprintf(fp,"%s",m_Commands[i].name);
00130 ++i;
00131 if (m_Commands[i].name == NULL)
00132 break;
00133 fprintf(fp,", ");
00134 }
00135
00136 fprintf(fp,"\n\nSorry, no further help available yet -- try Hazy.\n\n");
00137 cdEXIT(EXIT_SUCCESS);
00138 }
00139
00140
00141
00142 long int Parser::GetElem(void ) const
00143 {
00144 int i;
00145
00146 DEBUG_ENTRY( "GetElem()" );
00147
00148
00149
00150
00151
00152
00153 for( i=0; i<(int)LIMELM; ++i )
00154 {
00155 if( nMatch( elementnames.chElementNameShort[i] ) )
00156 {
00157
00158 return i;
00159 }
00160 }
00161
00162 return (-1 );
00163 }
00164
00165
00166 NORETURN void Parser::NoNumb(const char * chDesc) const
00167 {
00168 DEBUG_ENTRY( "NoNumb()" );
00169
00170
00171 fprintf( ioQQQ, " There is a problem on the following command line:\n" );
00172 fprintf( ioQQQ, " %s\n", m_card_raw );
00173 fprintf( ioQQQ, " A value for %s should have been on this line.\n Sorry.\n",chDesc );
00174 cdEXIT(EXIT_FAILURE);
00175 }
00176
00177 double Parser::getWaveOpt()
00178 {
00179 double val = FFmtRead();
00180
00181 if( chPoint() == 'M' )
00182 {
00183
00184 val *= 1e4;
00185 }
00186 else if( chPoint() == 'C' )
00187 {
00188
00189 val *= 1e8;
00190 }
00191 return val;
00192 }
00193 double Parser::getWave()
00194 {
00195 double val = getWaveOpt();
00196 if( lgEOL() )
00197 {
00198 NoNumb("wavelength");
00199 }
00200 return val;
00201 }
00202 double Parser::getNumberPlain( const char * )
00203 {
00204 return FFmtRead();
00205 }
00206 double Parser::getNumberCheck( const char *chDesc )
00207 {
00208 double val = FFmtRead();
00209 if( lgEOL() )
00210 {
00211 NoNumb(chDesc);
00212 }
00213 return val;
00214 }
00215 double Parser::getNumberDefault( const char *, double fdef )
00216 {
00217 double val = FFmtRead();
00218 if( lgEOL() )
00219 {
00220 val = fdef;
00221 }
00222 return val;
00223 }
00224 double Parser::getNumberCheckLogLinNegImplLog( const char *chDesc )
00225 {
00226 double val = getNumberCheck(chDesc);
00227 if( nMatch(" LOG") )
00228 {
00229 val = pow(10.,val);
00230 }
00231 else if(! nMatch("LINE") )
00232 {
00233
00234 if( val <= 0. )
00235 {
00236 val = pow(10.,val);
00237 }
00238 }
00239 return val;
00240 }
00241 double Parser::getNumberCheckAlwaysLog( const char *chDesc )
00242 {
00243 double val = getNumberCheck(chDesc);
00244 val = pow(10., val);
00245 return val;
00246 }
00247 double Parser::getNumberCheckAlwaysLogLim( const char *chDesc, double flim )
00248 {
00249 double val = getNumberCheck(chDesc);
00250 if ( val > flim )
00251 {
00252 fprintf(ioQQQ,"WARNING - the log of %s is too "
00253 "large, I shall probably crash. The value was %.2e\n",
00254 chDesc, val );
00255 fflush(ioQQQ);
00256 }
00257 val = pow(10., val);
00258 return val;
00259 }
00260 double Parser::getNumberDefaultAlwaysLog( const char *, double fdef )
00261 {
00262 double val = pow(10.,FFmtRead());
00263 if ( lgEOL() )
00264 {
00265 val = fdef;
00266 }
00267 return val;
00268 }
00269 double Parser::getNumberDefaultNegImplLog( const char *, double fdef )
00270 {
00271 double val = FFmtRead();
00272 if ( lgEOL() )
00273 {
00274 val = fdef;
00275 }
00276 if (val < 0.0)
00277 {
00278 val = pow(10.,val);
00279 }
00280 return val;
00281 }
00282
00283
00284
00285
00286 double Parser::FFmtRead(void)
00287 {
00288
00289 DEBUG_ENTRY( "Parser::FFmtRead()" );
00290
00291 char chr = '\0';
00292
00293 const char * const eol_ptr = m_card+m_len;
00294
00295
00296 while( m_ptr < eol_ptr && ( chr = *m_ptr++ ) != '\0' )
00297 {
00298 const char *lptr = m_ptr;
00299 char lchr = chr;
00300 if( lchr == '-' || lchr == '+' )
00301 lchr = *lptr++;
00302 if( lchr == '.' )
00303 lchr = *lptr;
00304 if( isdigit(lchr) )
00305 break;
00306 }
00307
00308 if( m_ptr == eol_ptr || chr == '\0' )
00309 {
00310 m_lgEOL = true;
00311 return 0.;
00312 }
00313
00314
00315 deque<Token> chTokens(0);
00316 bool lgCommaFound = false, lgLastComma = false;
00317 do
00318 {
00319 lgCommaFound = lgLastComma;
00320 if( chr != ',' )
00321 {
00322 if (chr != '^' && chr != '*')
00323 {
00324 if (chTokens.size() == 0 || chTokens.back().t != Token::symNumber)
00325 chTokens.push_back(Token(Token::symNumber));
00326 chTokens.back().s += chr;
00327 }
00328 else
00329 {
00330 chTokens.push_back(Token(Token::symOp));
00331 chTokens.back().s += chr;
00332 }
00333 }
00334 else
00335 {
00336
00337
00338 lgLastComma = true;
00339
00340 }
00341 if( m_ptr == eol_ptr )
00342 break;
00343 chr = *m_ptr++;
00344 }
00345 while( isdigit(chr) || chr == '.' || chr == '-' || chr == '+' || chr == ',' || chr == 'e' || chr == 'E' || chr == '^' || chr == '*' );
00346
00347 if( lgCommaFound )
00348 {
00349 fprintf( ioQQQ, " PROBLEM - a comma was found embedded in a number, this is deprecated.\n" );
00350 fprintf(ioQQQ, "== %-80s ==\n",m_card);
00351 }
00352
00353
00354 vector<double> valstack;
00355 const bool lgParseOK = ParseExpr(chTokens, valstack);
00356 if (!lgParseOK || 1 != valstack.size())
00357 {
00358 fprintf(ioQQQ," PROBLEM - syntax error in number\n");
00359 fprintf(ioQQQ, "== %-80s ==\n",m_card);
00360 }
00361
00362 double value = valstack[0];
00363
00364 m_lgEOL = false;
00365 m_ptr--;
00366
00367 return value;
00368 }
00369
00370 STATIC bool ParseNumber(deque<Token> &chTokens, vector<double> &valstack)
00371 {
00372 if ( chTokens.size() < 1 ||
00373 Token::symNumber != chTokens[0].t)
00374 return false;
00375
00376 valstack.push_back(atof(chTokens[0].s.c_str()));
00377 chTokens.pop_front();
00378 return true;
00379 }
00380
00381 STATIC bool doop(vector<double> &valstack, const string &op)
00382 {
00383 const double v2 = valstack.back();
00384 valstack.pop_back();
00385 const double v1 = valstack.back();
00386 valstack.pop_back();
00387 double result;
00388 if (op == "^")
00389 {
00390 result = pow(v1,v2);
00391 }
00392 else if (op == "*")
00393 {
00394 result = v1*v2;
00395 }
00396 else
00397 {
00398 fprintf(ioQQQ,"Unknown operator '%s'\n",op.c_str());
00399 return false;
00400 }
00401 valstack.push_back(result);
00402 return true;
00403 }
00404
00405 STATIC bool ParseExp(deque<Token> &chTokens, vector<double> &valstack)
00406 {
00407 if (!ParseNumber(chTokens, valstack))
00408 return false;
00409
00410 if ( chTokens.size() == 0 )
00411 return true;
00412
00413 if ( chTokens.size() < 2 )
00414 return false;
00415 if ( Token::symOp != chTokens[0].t || "^" != chTokens[0].s )
00416 return true;
00417
00418 string op = chTokens[0].s;
00419 chTokens.pop_front();
00420
00421 if (!ParseExp(chTokens, valstack))
00422 return false;
00423
00424 return doop(valstack, op);
00425 }
00426
00427 STATIC bool ParseProduct(deque<Token> &chTokens, vector<double> &valstack)
00428 {
00429 if (!ParseExp(chTokens, valstack))
00430 return false;
00431
00432 if ( chTokens.size() == 0 )
00433 return true;
00434
00435 if ( chTokens.size() < 2 )
00436 return false;
00437
00438 if ( Token::symOp != chTokens[0].t || "*" != chTokens[0].s )
00439 return true;
00440
00441 string op = chTokens[0].s;
00442 chTokens.pop_front();
00443
00444 if (!ParseProduct(chTokens, valstack))
00445 return false;
00446
00447 return doop(valstack, op);
00448 }
00449
00450 STATIC bool ParseExpr(deque<Token> &chTokens, vector<double> &valstack)
00451 {
00452 if (ParseProduct(chTokens, valstack))
00453 return true;
00454 return false;
00455 }