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 namespace
00014 {
00015 class Token
00016 {
00017 public:
00018 enum symType { symNull, symNumber, symOp, symVar };
00019 string s;
00020 symType t;
00021 explicit Token(enum symType type) : s(""), t(type) {}
00022 explicit Token() : s(""), t(symNull) {}
00023 };
00024 }
00025
00026 typedef std::map<string,double> symtab;
00027 STATIC bool ParseExpr(deque<Token> &chTokens, vector<double> &valstack,
00028 const symtab &tab);
00029
00030 const char *Parser::nWord(const char *chKey) const
00031 {
00032 return ::nWord(chKey, m_card);
00033 }
00034
00035
00036
00037 const char *nWord(const char *chKey,
00038 const char *chCard)
00039 {
00040 DEBUG_ENTRY( "nWord()" );
00041
00042
00043
00044 while (isspace(*chKey))
00045 {
00046 ++chKey;
00047 }
00048
00049 const long lenkey = strlen(chKey);
00050 ASSERT( lenkey > 0 );
00051
00052 bool atBoundary = true;
00053 for (const char *ptr = chCard; *ptr; ++ptr)
00054 {
00055 if ( atBoundary && strncmp( ptr, chKey, lenkey) == 0 )
00056 {
00057 return ptr;
00058 }
00059
00060 atBoundary = isBoundaryChar(*ptr);
00061 }
00062
00063 return NULL;
00064 }
00065
00066 bool isBoundaryChar(char c)
00067 {
00068 const bool lgAnyWhitespacePrecedesWord = false;
00069
00070 if (lgAnyWhitespacePrecedesWord)
00071 return isspace(c) ? true : false ;
00072 else
00073 return (! isalpha(c) ) && c != '_';
00074 }
00075
00076 bool Parser::isComment(void) const
00077 {
00078 return lgInputComment(m_card);
00079 }
00080 bool Parser::isCommandComment(void) const
00081 {
00082 return ( m_card[0]=='C' && (m_card[1]==' ' || m_card[1]== '\0')) ||
00083 isComment();
00084 }
00085 bool Parser::isVar(void) const
00086 {
00087 return ( *m_ptr=='$' );
00088 }
00089 std::string Parser::getVarName(void)
00090 {
00091 std::string name("");
00092 while (*m_ptr)
00093 {
00094 char c = *m_ptr;
00095 if (!(isalnum(c) || c == '_'))
00096 break;
00097 name += c;
00098 ++m_ptr;
00099 }
00100 return name;
00101 }
00102 void Parser::doSetVar(void)
00103 {
00104 DEBUG_ENTRY(" Parser::doSetVar()");
00105 char c='\0';
00106 ++m_ptr;
00107 std::string name = getVarName();
00108 while (*m_ptr)
00109 {
00110 c = *m_ptr;
00111 ++m_ptr;
00112 if (c == '=')
00113 break;
00114 }
00115 if (! *m_ptr)
00116 {
00117 fprintf(ioQQQ,"Expected '=' in variable definition\n");
00118 cdEXIT(EXIT_FAILURE);
00119 }
00120 while (*m_ptr)
00121 {
00122 c = *m_ptr;
00123 if (c != ' ')
00124 break;
00125 ++m_ptr;
00126 }
00127 m_symtab[name] = FFmtRead();
00128 }
00129
00130 void Parser::echo(void) const
00131 {
00132
00133 if( called.lgTalk && !::nMatch("HIDE",m_card) )
00134 fprintf( ioQQQ, "%23c* %-80s*\n", ' ', m_card_raw );
00135 }
00136
00137 NORETURN void Parser::CommandError(void) const
00138 {
00139 DEBUG_ENTRY(" Parser::CommandError()");
00140 fprintf( ioQQQ, " Unrecognized command. Key=\"%4.4s\". This is routine ParseCommands.\n",
00141 m_card );
00142 fprintf( ioQQQ, " The line image was\n");
00143 PrintLine(ioQQQ);
00144 fprintf( ioQQQ, " Sorry.\n" );
00145 cdEXIT(EXIT_FAILURE);
00146 }
00147 bool Parser::getline(void)
00148 {
00149 input.readarray(m_card_raw,&m_lgEOF);
00150 newlineProcess();
00151 if (m_lgEOF)
00152 return false;
00153 else
00154 return true;
00155 }
00156
00157 const char *Parser::StandardEnergyUnit(void) const
00158 {
00159 return ::StandardEnergyUnit(m_card);
00160 }
00161 string Parser::StandardFluxUnit(void) const
00162 {
00163 return ::StandardFluxUnit(m_card);
00164 }
00165 void Parser::help(FILE *fp) const
00166 {
00167 DEBUG_ENTRY("Parser::help()");
00168 fprintf(fp,"Available commands are:\n\n");
00169 long int i=0, l=0, len;
00170 while (1)
00171 {
00172 len = strlen(m_Commands[i].name);
00173 if (l+len+2 > 80)
00174 {
00175 fprintf(fp,"\n");
00176 l = 0;
00177 }
00178 l += len+2;
00179 fprintf(fp,"%s",m_Commands[i].name);
00180 ++i;
00181 if (m_Commands[i].name == NULL)
00182 break;
00183 fprintf(fp,", ");
00184 }
00185
00186 fprintf(fp,"\n\nSorry, no further help available yet -- try Hazy.\n\n");
00187 cdEXIT(EXIT_SUCCESS);
00188 }
00189
00190
00191
00192 long int Parser::GetElem(void ) const
00193 {
00194 int i;
00195
00196 DEBUG_ENTRY( "GetElem()" );
00197
00198
00199
00200
00201
00202
00203 for( i=0; i<(int)LIMELM; ++i )
00204 {
00205 if( nMatch( elementnames.chElementNameShort[i] ) )
00206 {
00207
00208 return i;
00209 }
00210 }
00211
00212 return (-1 );
00213 }
00214
00215
00216 NORETURN void Parser::NoNumb(const char * chDesc) const
00217 {
00218 DEBUG_ENTRY( "NoNumb()" );
00219
00220
00221 fprintf( ioQQQ, " There is a problem on the following command line:\n" );
00222 fprintf( ioQQQ, " %s\n", m_card_raw );
00223 fprintf( ioQQQ, " A value for %s should have been on this line.\n Sorry.\n",chDesc );
00224 cdEXIT(EXIT_FAILURE);
00225 }
00226
00227 double Parser::getWaveOpt()
00228 {
00229 double val = FFmtRead();
00230
00231 if( chPoint() == 'M' )
00232 {
00233
00234 val *= 1e4;
00235 }
00236 else if( chPoint() == 'C' )
00237 {
00238
00239 val *= 1e8;
00240 }
00241 return val;
00242 }
00243 double Parser::getWave()
00244 {
00245 double val = getWaveOpt();
00246 if( lgEOL() )
00247 {
00248 NoNumb("wavelength");
00249 }
00250 return val;
00251 }
00252 double Parser::getNumberPlain( const char * )
00253 {
00254 return FFmtRead();
00255 }
00256 double Parser::getNumberCheck( const char *chDesc )
00257 {
00258 double val = FFmtRead();
00259 if( lgEOL() )
00260 {
00261 NoNumb(chDesc);
00262 }
00263 return val;
00264 }
00265 double Parser::getNumberDefault( const char *, double fdef )
00266 {
00267 double val = FFmtRead();
00268 if( lgEOL() )
00269 {
00270 val = fdef;
00271 }
00272 return val;
00273 }
00274 double Parser::getNumberCheckLogLinNegImplLog( const char *chDesc )
00275 {
00276 double val = getNumberCheck(chDesc);
00277 if( nMatch(" LOG") )
00278 {
00279 val = pow(10.,val);
00280 }
00281 else if(! nMatch("LINE") )
00282 {
00283
00284 if( val <= 0. )
00285 {
00286 val = pow(10.,val);
00287 }
00288 }
00289 return val;
00290 }
00291 double Parser::getNumberCheckAlwaysLog( const char *chDesc )
00292 {
00293 double val = getNumberCheck(chDesc);
00294 val = pow(10., val);
00295 return val;
00296 }
00297 double Parser::getNumberCheckAlwaysLogLim( const char *chDesc, double flim )
00298 {
00299 double val = getNumberCheck(chDesc);
00300 if ( val > flim )
00301 {
00302 fprintf(ioQQQ,"WARNING - the log of %s is too "
00303 "large, I shall probably crash. The value was %.2e\n",
00304 chDesc, val );
00305 fflush(ioQQQ);
00306 }
00307 val = pow(10., val);
00308 return val;
00309 }
00310 double Parser::getNumberDefaultAlwaysLog( const char *, double fdef )
00311 {
00312 double val = pow(10.,FFmtRead());
00313 if ( lgEOL() )
00314 {
00315 val = fdef;
00316 }
00317 return val;
00318 }
00319 double Parser::getNumberDefaultNegImplLog( const char *, double fdef )
00320 {
00321 double val = FFmtRead();
00322 if ( lgEOL() )
00323 {
00324 val = fdef;
00325 }
00326 if (val < 0.0)
00327 {
00328 val = pow(10.,val);
00329 }
00330 return val;
00331 }
00332
00333
00334
00335
00336 double Parser::FFmtRead(void)
00337 {
00338
00339 DEBUG_ENTRY( "Parser::FFmtRead()" );
00340
00341 char chr = '\0';
00342
00343 const char * const eol_ptr = m_card+m_len;
00344
00345
00346 while( m_ptr < eol_ptr && ( chr = *m_ptr++ ) != '\0' )
00347 {
00348 if ( chr == '$')
00349 break;
00350 const char *lptr = m_ptr;
00351 char lchr = chr;
00352 if( lchr == '-' || lchr == '+' )
00353 lchr = *lptr++;
00354 if( lchr == '.' )
00355 lchr = *lptr;
00356 if( isdigit(lchr) )
00357 break;
00358 }
00359
00360 if( m_ptr == eol_ptr || chr == '\0' )
00361 {
00362 m_lgEOL = true;
00363 return 0.;
00364 }
00365
00366
00367 deque<Token> chTokens(0);
00368 bool lgCommaFound = false, lgLastComma = false;
00369 do
00370 {
00371 lgCommaFound = lgLastComma;
00372 if( chr != ',' )
00373 {
00374 if (chr == '^' || chr == '*' || chr == '/' )
00375 {
00376 chTokens.push_back(Token(Token::symOp));
00377 chTokens.back().s += chr;
00378 }
00379 else if (chr == '$')
00380 {
00381 chTokens.push_back(Token(Token::symVar));
00382 chTokens.back().s += getVarName();
00383 }
00384 else
00385 {
00386 if (chTokens.size() == 0 || chTokens.back().t != Token::symNumber)
00387 chTokens.push_back(Token(Token::symNumber));
00388 chTokens.back().s += chr;
00389 }
00390 }
00391 else
00392 {
00393
00394
00395 lgLastComma = true;
00396
00397 }
00398 if( m_ptr == eol_ptr )
00399 break;
00400 chr = *m_ptr++;
00401 }
00402 while( isdigit(chr) || chr == '.' || chr == '-' || chr == '+' || chr == ','
00403 || chr == 'e' || chr == 'E' || chr == '^' || chr == '*' || chr == '/'
00404 || chr == '$' );
00405
00406 if( lgCommaFound )
00407 {
00408 fprintf( ioQQQ, " PROBLEM - a comma was found embedded in a number, this is deprecated.\n" );
00409 fprintf(ioQQQ, "== %-80s ==\n",m_card);
00410 }
00411
00412
00413 vector<double> valstack;
00414 const bool lgParseOK = ParseExpr(chTokens, valstack, m_symtab);
00415 if (!lgParseOK || 1 != valstack.size())
00416 {
00417 fprintf(ioQQQ," PROBLEM - syntax error in number\n");
00418 fprintf(ioQQQ, "== %-80s ==\n",m_card);
00419 }
00420
00421 double value = valstack[0];
00422
00423 m_lgEOL = false;
00424 m_ptr--;
00425
00426 return value;
00427 }
00428
00429 void Parser::getLineID(char *LabelBuf, realnum *wave)
00430 {
00431
00432 strncpy( LabelBuf, getCommand(4).c_str() , 4 );
00433
00434
00435 LabelBuf[4] = 0;
00436
00437
00438 *wave = (realnum)getWaveOpt();
00439
00440 }
00441
00442
00443
00444
00445
00446
00447
00448
00449 STATIC bool ParseNumber(deque<Token> &chTokens, vector<double> &valstack,
00450 const symtab &tab)
00451 {
00452 DEBUG_ENTRY(" ParseNumber()");
00453 if ( chTokens.size() < 1)
00454 return false;
00455
00456 if (Token::symNumber == chTokens[0].t)
00457 {
00458 valstack.push_back(atof(chTokens[0].s.c_str()));
00459 chTokens.pop_front();
00460 return true;
00461 }
00462 if (Token::symVar == chTokens[0].t)
00463 {
00464 symtab::const_iterator var = tab.find(chTokens[0].s);
00465 if (var == tab.end())
00466 {
00467 fprintf(ioQQQ,"ERROR: No value found for variable $%s\n",
00468 chTokens[0].s.c_str());
00469 cdEXIT(EXIT_FAILURE);
00470 }
00471 valstack.push_back(var->second);
00472 chTokens.pop_front();
00473 return true;
00474 }
00475
00476 return false;
00477 }
00478
00479 STATIC bool doop(vector<double> &valstack, const string &op)
00480 {
00481 const double v2 = valstack.back();
00482 valstack.pop_back();
00483 const double v1 = valstack.back();
00484 valstack.pop_back();
00485 double result;
00486 if (op == "^")
00487 {
00488 result = pow(v1,v2);
00489 }
00490 else if (op == "*")
00491 {
00492 result = v1*v2;
00493 }
00494 else if (op == "/")
00495 {
00496 result = v1/v2;
00497 }
00498 else
00499 {
00500 fprintf(ioQQQ,"Unknown operator '%s'\n",op.c_str());
00501 return false;
00502 }
00503 valstack.push_back(result);
00504 return true;
00505 }
00506
00507 STATIC bool ParseExp(deque<Token> &chTokens, vector<double> &valstack,
00508 const symtab& tab)
00509 {
00510
00511 vector<string> opstack;
00512 if (!ParseNumber(chTokens, valstack, tab))
00513 return false;
00514
00515 while (1)
00516 {
00517 if ( chTokens.size() == 0 )
00518 break;
00519
00520 if ( chTokens.size() < 2 )
00521 return false;
00522
00523 if ( Token::symOp != chTokens[0].t || "^" != chTokens[0].s )
00524 break;
00525
00526 opstack.push_back(chTokens[0].s);
00527 chTokens.pop_front();
00528
00529 if (!ParseNumber(chTokens, valstack, tab))
00530 return false;
00531 }
00532
00533 while (!opstack.empty())
00534 {
00535 if (!doop(valstack, opstack.back()))
00536 return false;
00537 opstack.pop_back();
00538 }
00539 return true;
00540 }
00541
00542 STATIC bool ParseProduct(deque<Token> &chTokens, vector<double> &valstack,
00543 const symtab& tab)
00544 {
00545
00546 if (!ParseExp(chTokens, valstack, tab))
00547 return false;
00548
00549 while ( chTokens.size() > 0 &&
00550 Token::symOp == chTokens[0].t &&
00551 ( "*" == chTokens[0].s || "/" == chTokens[0].s ) )
00552 {
00553 string op = chTokens[0].s;
00554 chTokens.pop_front();
00555
00556 if (!ParseExp(chTokens, valstack, tab))
00557 return false;
00558
00559 if (!doop(valstack, op))
00560 return false;
00561 }
00562 return true;
00563 }
00564
00565 STATIC bool ParseExpr(deque<Token> &chTokens, vector<double> &valstack,
00566 const symtab& tab)
00567 {
00568 if (ParseProduct(chTokens, valstack,tab))
00569 return true;
00570 return false;
00571 }