Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1525 lines
30 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: bnparse.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. //
  11. // BNPARSE.CPP
  12. //
  13. #include <windows.h>
  14. #include <stdarg.h>
  15. #include <assert.h>
  16. #include "bnparse.h"
  17. #include "bnreg.h"
  18. DSCPARSER :: DSCPARSER (
  19. MBNET & mbnet,
  20. PARSIN & flpIn,
  21. PARSOUT & _flpOut )
  22. : _flpIn( flpIn ),
  23. _flpOut( _flpOut ),
  24. _mbnet(mbnet),
  25. _cchToken(0),
  26. _iLine(1),
  27. _cError(0),
  28. _cWarning(0),
  29. _bUngetToken(false),
  30. _cerrorNode(0),
  31. _pnode(NULL),
  32. _bCI(false),
  33. _edist(BNDIST::ED_NONE),
  34. _bDefault(false),
  35. _idpi(0),
  36. _cdpi(0),
  37. _idpiLast(-1),
  38. _chCur(' '),
  39. _chUnget(0),
  40. _tokenCur(tokenNil),
  41. _bPropDefs(false),
  42. _cNode(0),
  43. _eBlk(EBLKNONE),
  44. _ppropMgr(NULL),
  45. _elbl(ESTDLBL_other),
  46. _ilimNext(-1)
  47. {
  48. ResetParser();
  49. }
  50. DSCPARSER :: ~ DSCPARSER ()
  51. {
  52. ResetParser();
  53. }
  54. bool DSCPARSER :: BInitOpen( SZC szcFile )
  55. {
  56. return _flpIn.Open( szcFile, "rt" );
  57. }
  58. // Clear the string references from the parser. Since our
  59. // definition of YYSTYPE contains a ZSREF, we must reset the
  60. // contents of all such structures so that the MBNET's symbol
  61. // table can be destroyed at any time.
  62. void DSCPARSER :: ResetParser ()
  63. {
  64. _vchToken.resize( _cchTokenMax + 1 );
  65. // Clear all ZSREF information maintained by the parser token ensemble
  66. yyval.zsr.Clear();
  67. yylval.zsr.Clear();
  68. for ( int i = 0; i < YYMAXDEPTH; )
  69. {
  70. yyv[i++].zsr.Clear();
  71. }
  72. // Do normal member variable clearing
  73. _chUnget = 0;
  74. _bUngetToken = false;
  75. delete _ppropMgr;
  76. _ppropMgr = NULL;
  77. }
  78. bool DSCPARSER :: BParse ( UINT & cError, UINT & cWarning )
  79. {
  80. bool bResult = YaccParse() == 0 && _cError == 0;
  81. cError = _cError;
  82. cWarning = _cWarning;
  83. // Mark the model as having topology
  84. Mbnet().BSetBFlag( EIBF_Topology );
  85. ResetParser();
  86. _flpOut.Flush();
  87. return bResult;
  88. }
  89. GOBJMBN * DSCPARSER :: PbnobjFind ( SZC szcName )
  90. {
  91. return Mpsymtbl().find(szcName);
  92. }
  93. GNODEMBND * DSCPARSER::PgndbnFind (SZC szc)
  94. {
  95. GOBJMBN * pbnobj = PbnobjFind(szc);
  96. if ( pbnobj == NULL )
  97. return NULL;
  98. INT ebno = pbnobj->EType() ;
  99. if ( ebno != GOBJMBN::EBNO_NODE )
  100. return NULL;
  101. GNODEMBND * pgndd;
  102. DynCastThrow(pbnobj,pgndd);
  103. return pgndd;
  104. }
  105. bool DSCPARSER :: BChNext()
  106. {
  107. if ( _chUnget > 0 )
  108. {
  109. _chCur = _chUnget;
  110. _chUnget = 0;
  111. }
  112. else
  113. {
  114. _chCur = (char)_flpIn.Getch();
  115. }
  116. if ( _chCur == '\n')
  117. _iLine++;
  118. return bool(_chCur != EOF);
  119. }
  120. void DSCPARSER :: SkipWS() // skip white space
  121. {
  122. while (isspace(_chCur) && BChNext());
  123. }
  124. void DSCPARSER :: SkipToEOL()
  125. {
  126. while (_chCur != '\n' && BChNext());
  127. }
  128. //
  129. // Add a character to a normal token; if overlength, truncate.
  130. //
  131. void DSCPARSER :: AddChar ( TCHAR tch )
  132. {
  133. int cch = _vchToken.size() - 2;
  134. if ( _cchToken < cch )
  135. {
  136. _vchToken[_cchToken] = tch ? tch : _chCur;
  137. _vchToken[_cchToken+1] = 0;
  138. }
  139. // Add to scanned length to report overlength token
  140. _cchToken++;
  141. }
  142. //
  143. // Add a character to a string token; do not truncate.
  144. //
  145. void DSCPARSER :: AddCharStr ( TCHAR tch )
  146. {
  147. int cch = _vchToken.size() - 2;
  148. if ( _cchToken >= cch )
  149. {
  150. _vchToken.resize( 2 * _vchToken.size() );
  151. }
  152. _vchToken[_cchToken] = tch ? tch : _chCur;
  153. _vchToken[_cchToken+1] = 0;
  154. _cchToken++;
  155. }
  156. char DSCPARSER :: ChEscape()
  157. {
  158. BChNext();
  159. switch (_chCur)
  160. {
  161. case 'n':
  162. return '\n';
  163. case 't':
  164. return '\t';
  165. case 'v':
  166. return '\v';
  167. case 'b':
  168. return '\b';
  169. case 'r':
  170. return '\r';
  171. case 'f':
  172. return '\f';
  173. case 'a':
  174. return '\a';
  175. default:
  176. return _chCur;
  177. }
  178. }
  179. void DSCPARSER :: CloseIdentifier()
  180. {
  181. if ( ! MBNET::BSzLegal( SzcToken() ) )
  182. Error("identifier \'%s\' is not legal", SzcToken() );
  183. CloseToken("identifier");
  184. }
  185. void DSCPARSER :: CloseToken(SZC szcTokenType)
  186. {
  187. if (_cchToken >= _cchTokenMax)
  188. {
  189. Warning("%s of length %u exceeded maximum length %u",
  190. szcTokenType, _cchToken, _cchTokenMax);
  191. }
  192. }
  193. TOKEN DSCPARSER :: TokenKeyword()
  194. {
  195. // See if the captured token is a keyword
  196. TOKEN token = MBNETDSC::TokenFind( SzcToken() );
  197. if ( token != tokenNil )
  198. return token;
  199. // Intern the symbol
  200. yylval.zsr = Mpsymtbl().intern( SzcToken() );
  201. // See if it's a property type
  202. GOBJMBN * pbnobj = PbnobjFind(yylval.zsr);
  203. if ( pbnobj && pbnobj->EType() == GOBJMBN::EBNO_PROP_TYPE )
  204. return tokenPropIdent;
  205. // It's an identifier
  206. return tokenIdent;
  207. }
  208. void DSCPARSER::ErrorWarn ( bool bErr, SZC szcFormat, va_list & valist )
  209. {
  210. SZC szcType = bErr
  211. ? "error"
  212. : "warning" ;
  213. if ( bErr )
  214. _cError++;
  215. else
  216. _cWarning++;
  217. int iLine = _chCur != '\n'
  218. ? _iLine
  219. : _iLine - 1;
  220. _flpOut.Fprint("\n%s(%u) %s: ", _flpIn.ZsFn().Szc(), iLine, szcType);
  221. _flpOut.Vsprint(szcFormat, valist);
  222. _flpOut.ErrWarn( bErr, iLine );
  223. _flpOut.Flush();
  224. }
  225. void DSCPARSER::ErrorWarn( bool bErr, SZC szcFormat, ...)
  226. {
  227. va_list valist;
  228. va_start(valist, szcFormat);
  229. ErrorWarn(bErr,szcFormat,valist);
  230. va_end(valist);
  231. }
  232. void DSCPARSER::Error( SZC szcFormat, ...)
  233. {
  234. va_list valist;
  235. va_start(valist, szcFormat);
  236. ErrorWarn(true,szcFormat,valist);
  237. va_end(valist);
  238. }
  239. void DSCPARSER::Warning(SZC szcFormat, ...)
  240. {
  241. va_list valist;
  242. va_start(valist, szcFormat);
  243. ErrorWarn(false,szcFormat,valist);
  244. va_end(valist);
  245. }
  246. void DSCPARSER::ErrorWarnNode(bool bErr, SZC szcFormat, ...)
  247. {
  248. // If this node has already been deleted, other errors supercede
  249. if (!_pnode)
  250. return;
  251. // Report the error
  252. ErrorWarn(bErr, "node %s: ", _pnode->ZsrefName().Szc());
  253. va_list valist;
  254. va_start(valist, szcFormat);
  255. _flpOut.Vsprint(szcFormat, valist);
  256. va_end(valist);
  257. if (++_cerrorNode == 5 || bErr)
  258. _pnode = NULL;
  259. }
  260. void DSCPARSER::WarningSkip ( ZSREF zsrBlockName )
  261. {
  262. Warning("unrecognized block name \'%s\' skipped entirely",
  263. zsrBlockName.Szc());
  264. }
  265. void DSCPARSER :: ReportNYI (SZC szcWhich)
  266. {
  267. ErrorWarn(true,"** UNIMPLEMENTED FUNCTION: \'%s\' **", szcWhich);
  268. }
  269. TOKEN DSCPARSER::TokenNextBasic()
  270. {
  271. for (;;)
  272. {
  273. // skip over white space and comments
  274. SkipWS();
  275. if (_chCur != '/')
  276. break;
  277. BChNext();
  278. if (_chCur == '/')
  279. {
  280. // it's a line comment
  281. SkipToEOL();
  282. BChNext(); // discard '\n'
  283. }
  284. else
  285. if (_chCur == '*')
  286. {
  287. // it's a block comment
  288. bool fFoundEnd = false;
  289. BChNext();
  290. for (char chPrev = _chCur; BChNext(); chPrev = _chCur)
  291. {
  292. if (_chCur == '/' && chPrev == '*')
  293. {
  294. fFoundEnd = true;
  295. break;
  296. }
  297. }
  298. if (fFoundEnd)
  299. BChNext(); // discard terminating '/'
  300. else
  301. {
  302. ErrorWarn(true,"end of file reached in block comment");
  303. return tokenEOF;
  304. }
  305. }
  306. else
  307. {
  308. // not a comment, return '/'
  309. _vchToken[1] = '\0';
  310. return TOKEN(_vchToken[0] = '/');
  311. }
  312. }
  313. if (_chCur == EOF)
  314. return tokenEOF;
  315. _cchToken = 0;
  316. if ( MBNET::BChLegal( _chCur, MBNET::ECHNM_First ) )
  317. {
  318. AddChar();
  319. char chLast = _chCur;
  320. while (BChNext() && MBNET::BChLegal( _chCur, MBNET::ECHNM_Middle ))
  321. {
  322. // Check for the "range" operator ".."
  323. if ( _chCur == chLast && _chCur == '.' )
  324. break;
  325. chLast = _chCur;
  326. AddChar();
  327. }
  328. CloseIdentifier();
  329. return TokenKeyword();
  330. }
  331. else
  332. if (isdigit(_chCur) || _chCur == '.')
  333. {
  334. TOKEN token = _chCur == '.'
  335. ? tokenReal
  336. : tokenInteger;
  337. AddChar();
  338. while ( BChNext() && isdigit(_chCur) )
  339. AddChar();
  340. // Check for the "range" operator ".."
  341. if ( token == tokenReal && _chCur == '.' && _cchToken == 1 )
  342. {
  343. AddChar();
  344. BChNext();
  345. CloseToken("rangeop");
  346. return tokenRangeOp;
  347. }
  348. if (_cchToken == 1 && _vchToken[0] == '.')
  349. {
  350. CloseToken("punctuation");
  351. return TOKEN('.');
  352. }
  353. if (_chCur == '.' && token == tokenInteger)
  354. {
  355. AddChar();
  356. token = tokenReal;
  357. UINT cchOld = _cchToken;
  358. while (BChNext() && isdigit(_chCur))
  359. AddChar();
  360. // Check for the "range" operator ".."
  361. if ( _chCur == '.' && cchOld == _cchToken )
  362. {
  363. _vchToken[ -- _cchToken] = 0;
  364. _chUnget = '.';
  365. token = tokenInteger;
  366. }
  367. // Note that check for [eE] below will fail
  368. }
  369. if (_chCur == 'e' || _chCur == 'E')
  370. {
  371. AddChar();
  372. BChNext();
  373. token = tokenReal;
  374. if (_chCur == '-' || _chCur == '+')
  375. {
  376. AddChar();
  377. BChNext();
  378. }
  379. if (isdigit(_chCur))
  380. {
  381. AddChar();
  382. while (BChNext() && isdigit(_chCur))
  383. AddChar();
  384. }
  385. }
  386. CloseToken("integer/real");
  387. if (token == tokenInteger)
  388. yylval.ui = UINT(::atol(SzcToken()));
  389. else
  390. yylval.real = ::atof(SzcToken());
  391. return token;
  392. }
  393. else
  394. if (_chCur == '"')
  395. {
  396. while (BChNext() && _chCur != '\n' && _chCur != '"')
  397. {
  398. if (_chCur == '\\')
  399. _chCur = ChEscape();
  400. AddCharStr();
  401. }
  402. if (_chCur == '"')
  403. {
  404. BChNext();
  405. CloseToken("string");
  406. yylval.zsr = Mpsymtbl().intern( SzcToken() );
  407. return tokenString;
  408. }
  409. ErrorWarn(true, _chCur == '\n' ? "new line in string" : "end of file in string");
  410. return tokenError;
  411. }
  412. AddChar();
  413. BChNext();
  414. CloseToken(NULL);
  415. return TOKEN(_vchToken[0]);
  416. }
  417. TOKEN DSCPARSER::TokenNext()
  418. {
  419. // we need this to be able to skip tokens
  420. if (!_bUngetToken)
  421. _tokenCur = TokenNextBasic();
  422. else
  423. _bUngetToken = false;
  424. return _tokenCur;
  425. }
  426. void DSCPARSER::SkipUntil ( SZC szcStop, bool bDidLookAhead )
  427. {
  428. UINT cparen = 0;
  429. UINT cbrace = 0;
  430. for (; _tokenCur != tokenEOF; TokenNext())
  431. {
  432. if (_tokenCur == '}')
  433. {
  434. if (cbrace > 0)
  435. cbrace--;
  436. else
  437. break;
  438. }
  439. else
  440. if (_tokenCur == ')')
  441. {
  442. if (cparen > 0)
  443. cparen--;
  444. else
  445. break;
  446. }
  447. if (cparen == 0 && cbrace == 0)
  448. {
  449. if (_tokenCur < 256 && ::strchr(szcStop, _tokenCur))
  450. break;
  451. }
  452. if (_tokenCur == '{')
  453. cbrace++;
  454. else
  455. if (_tokenCur == '(')
  456. cparen++;
  457. bDidLookAhead = false;
  458. }
  459. if (!bDidLookAhead)
  460. _bUngetToken = true;
  461. }
  462. void DSCPARSER::SyntaxError ( SZC szcMessage )
  463. {
  464. static char szTemp[256];
  465. static char szFile[256];
  466. SZC szcError = "";
  467. switch (_tokenCur)
  468. {
  469. case tokenIdent:
  470. szcError = ": unexpected identifier '%s'";
  471. break;
  472. case tokenEOF:
  473. szcError = ": unexpected end-of-file";
  474. break;
  475. case tokenError:
  476. return;
  477. default:
  478. szcError = ": unexpected token '%s'";
  479. break;
  480. }
  481. sprintf(szTemp, "%s%s\n", szcMessage, szcError);
  482. ErrorWarn(true, szTemp, SzcToken());
  483. }
  484. GNODEMBND * DSCPARSER::PgndbnAdd(ZSREF zsr)
  485. {
  486. GOBJMBN * pbnobj = PbnobjFind(zsr);
  487. assert( pbnobj == NULL );
  488. if ( ! Mbnet().BAddElem( zsr, _pnode = new GNODEMBND ) )
  489. {
  490. delete _pnode;
  491. _pnode = NULL;
  492. }
  493. return _pnode;
  494. }
  495. void DSCPARSER::AddSymb(ZSREF zsr)
  496. {
  497. _vzsr.push_back(zsr);
  498. }
  499. void DSCPARSER::AddStr(ZSREF zsr)
  500. {
  501. Mpsymtbl().intern(zsr);
  502. AddSymb(zsr);
  503. }
  504. void DSCPARSER::AddPv ( PROPVAR & pv )
  505. {
  506. _vpv.push_back(pv);
  507. }
  508. void DSCPARSER::AddPropVar (ZSREF zsr)
  509. {
  510. AddPv( PROPVAR(zsr) );
  511. }
  512. void DSCPARSER::AddPropVar (REAL & r)
  513. {
  514. AddPv( PROPVAR(r) );
  515. }
  516. void DSCPARSER::AddUi(UINT ui)
  517. {
  518. _vui.push_back(ui);
  519. }
  520. void DSCPARSER::AddReal(REAL real)
  521. {
  522. _vreal.push_back(real);
  523. }
  524. UINT DSCPARSER::UiDpi(ZSREF zsr)
  525. {
  526. if (!_pnode || _vui.size() >= _vzsrParent.size())
  527. return 0;
  528. GNODEMBND * pParent = PgndbnFind(_vzsrParent[_vui.size()]);
  529. assert( pParent );
  530. for ( UINT is = 0; is < pParent->CState(); is++ )
  531. {
  532. if ( zsr == pParent->VzsrStates()[is] )
  533. return is;
  534. }
  535. ErrorWarnNode(true, "parent \'%s\' doesn\'t have a state named \'%s\'",
  536. pParent->ZsrefName().Szc(),
  537. zsr.Szc());
  538. return 0;
  539. }
  540. UINT DSCPARSER::UiDpi(UINT ui)
  541. {
  542. if (!_pnode || _vui.size() >= _vzsrParent.size())
  543. return 0;
  544. GNODEMBND * pParent = PgndbnFind(_vzsrParent[_vui.size()]);
  545. assert( pParent );
  546. if ( ui < pParent->CState() )
  547. return ui;
  548. ErrorWarnNode(true, "parent \'%s\' doesn\'t have a state %d",
  549. pParent->ZsrefName().Szc(),
  550. ui) ;
  551. return 0;
  552. }
  553. void DSCPARSER::SetCreator(ZSREF zsr)
  554. {
  555. Mbnet().ZsCreator() = zsr;
  556. }
  557. void DSCPARSER::SetFormat(ZSREF zsr)
  558. {
  559. Mbnet().ZsFormat() = zsr;
  560. }
  561. void DSCPARSER::SetVersion(REAL r)
  562. {
  563. Mbnet().RVersion() = r;
  564. }
  565. void DSCPARSER::SetStates ()
  566. {
  567. UINT cstr = _vzsr.size();
  568. if (_pnode)
  569. {
  570. if ( cstr != _pnode->CState() )
  571. {
  572. ErrorWarnNode(true, "wrong number of state labels, %d != %d",
  573. cstr, _pnode->CState() );
  574. return;
  575. }
  576. _pnode->SetStates(_vzsr);
  577. }
  578. }
  579. void DSCPARSER::SetNetworkSymb(ZSREF zsr)
  580. {
  581. Mbnet().ZsNetworkID() = zsr;
  582. }
  583. void DSCPARSER::ClearNodeInfo()
  584. {
  585. _pnode = NULL;
  586. _elbl = ESTDLBL_other;
  587. RefBndist().Deref();
  588. _cerrorNode = 0;
  589. _idpi = -1;
  590. _idpiLast = -1;
  591. _cdpi = 0;
  592. _bDefault = false;
  593. _bCI = false;
  594. ClearCstr();
  595. ClearVpv();
  596. _vimdDim.clear();
  597. _vui.clear();
  598. _vreal.clear();
  599. _vsdpi.clear();
  600. _vzsrParent.clear();
  601. _edist = BNDIST::ED_SPARSE;
  602. }
  603. void DSCPARSER :: StartNodeDecl ( ZSREF zsr )
  604. {
  605. ClearNodeInfo();
  606. SetNodeSymb(zsr, true);
  607. // If this is the first node we've seen and no property declarations
  608. // were seen, import the standard properties from the Registry.
  609. if ( _cNode++ == 0 )
  610. {
  611. if ( ! _bPropDefs )
  612. ImportPropStandard();
  613. }
  614. }
  615. void DSCPARSER::SetNodeSymb(ZSREF zsr, bool bNew)
  616. {
  617. _pnode = PgndbnFind(zsr);
  618. if ( bNew && _pnode == NULL )
  619. {
  620. PgndbnAdd(zsr);
  621. ASSERT_THROW( _pnode != NULL, EC_INTERNAL_ERROR, "undetected duplicate name" );
  622. }
  623. if ( _pnode == NULL )
  624. {
  625. ErrorWarn(true, "identifier '%s' has %s been defined",
  626. zsr.Szc(),
  627. bNew ? "already" : "not");
  628. }
  629. else
  630. {
  631. assert( _ppropMgr );
  632. // Find the standard label for this node, if any.
  633. PROPMBN * pprop = _ppropMgr->PFind( *_pnode, ESTDP_label );
  634. _elbl = pprop
  635. ? (ESTDLBL) _ppropMgr->IUserToLbl( pprop->Real() )
  636. : ESTDLBL_other;
  637. }
  638. }
  639. void DSCPARSER::SetNodeFullName(ZSREF zsr)
  640. {
  641. assert(_pnode);
  642. _pnode->ZsFullName() = zsr;
  643. }
  644. void DSCPARSER::SetNodePosition( int x, int y )
  645. {
  646. assert(_pnode);
  647. _pnode->PtPos()._x = x;
  648. _pnode->PtPos()._y = y;
  649. }
  650. void DSCPARSER::CheckNodeInfo()
  651. {
  652. if ( ! _pnode )
  653. return;
  654. if ( ! _pnode->LtProp().Uniqify() )
  655. {
  656. ErrorWarnNode(false,"some properties defined more than once");
  657. }
  658. if ( _pnode->CState() == 0 )
  659. {
  660. ErrorWarnNode(true,"no states defined");
  661. }
  662. }
  663. void DSCPARSER::SetNodeCstate(UINT cstate)
  664. {
  665. if ( ! _pnode )
  666. return;
  667. _pnode->_vzsrState.resize( cstate );
  668. }
  669. void DSCPARSER::ClearCstr()
  670. {
  671. _vzsr.clear();
  672. }
  673. void DSCPARSER::ClearVpv()
  674. {
  675. _vpv.clear();
  676. }
  677. void DSCPARSER::AddPropType(ZSREF zsrName, UINT fType, ZSREF zsrComment)
  678. {
  679. GOBJMBN * pbnobj = PbnobjFind(zsrName);
  680. if ( pbnobj )
  681. {
  682. Error("symbol name \'%s\' has already been defined",
  683. zsrName.Szc() );
  684. }
  685. else
  686. {
  687. GOBJPROPTYPE * pbnpt = new GOBJPROPTYPE;
  688. pbnpt->_fType = fType;
  689. pbnpt->_zsrComment = zsrComment;
  690. if ( fType & fPropChoice )
  691. {
  692. for ( UINT ichoice = 0 ; ichoice < _vzsr.size(); ichoice )
  693. {
  694. pbnpt->_vzsrChoice.push_back(_vzsr[ichoice++]);
  695. }
  696. }
  697. bool bOk = Mbnet().BAddElem( zsrName, pbnpt );
  698. assert( bOk ); // shouldn't happen; we've already checked for duplicates above
  699. }
  700. }
  701. void DSCPARSER::StartProperties()
  702. {
  703. _eBlk = EBLKPROP;
  704. _bPropDefs = true;
  705. }
  706. void DSCPARSER::EndProperties()
  707. {
  708. _eBlk = EBLKNONE;
  709. delete _ppropMgr;
  710. _ppropMgr = new PROPMGR( Mbnet() );
  711. }
  712. void DSCPARSER::CheckProperty( ZSREF zsrName )
  713. {
  714. GOBJMBN * pbnobj = PbnobjFind(zsrName);
  715. if ( pbnobj == NULL || pbnobj->EType() != GOBJMBN::EBNO_PROP_TYPE )
  716. {
  717. Error("\'%s\' is not a valid property name",
  718. zsrName.Szc() );
  719. return;
  720. }
  721. GOBJPROPTYPE * pbnpt = (GOBJPROPTYPE*) pbnobj;
  722. UINT fType = pbnpt->FPropType();
  723. bool bArray = (fType & fPropArray) == fPropArray;
  724. bool bStr = (fType & fPropString) == fPropString;
  725. bool bOK = true;
  726. UINT cpv = _vpv.size();
  727. // Check the context; that is, what kind of block are we parsing?
  728. LTBNPROP * pLtProp = NULL;
  729. switch ( _eBlk )
  730. {
  731. case EBLKNODE: // We're in a node block
  732. if ( _pnode )
  733. pLtProp = & _pnode->LtProp();
  734. break;
  735. case EBLKPROP: // We're in the properties block
  736. pLtProp = & _mbnet.LtProp();
  737. break;
  738. default: // How did the parser let this happen?
  739. SyntaxError("unexpected property declaration");
  740. return;
  741. break;
  742. }
  743. if ( cpv > 1 && ! bArray )
  744. {
  745. Error("property \'%s\' is not an array property",
  746. zsrName.Szc() );
  747. bOK = false;
  748. }
  749. else
  750. if ( pLtProp )
  751. {
  752. pLtProp->push_back( PROPMBN() );
  753. PROPMBN & bnp = pLtProp->back();
  754. bnp.Init( *pbnpt );
  755. for ( UINT ip = 0; ip < cpv ; ip++ )
  756. {
  757. REAL r = -1.0;
  758. ZSREF zsr;
  759. switch ( _vpv[ip]._eType )
  760. {
  761. case PROPVAR::ETPV_STR:
  762. if ( bStr)
  763. {
  764. zsr = _vpv[ip]._zsref;
  765. break;
  766. }
  767. if ( bOK = (fType & fPropChoice) > 0 )
  768. {
  769. UINT cChoice = pbnpt->VzsrChoice().size();
  770. ZSREF zsrChoice = _vpv[ip]._zsref;
  771. // find the property choice in the array
  772. for ( UINT ic = 0 ; ic < cChoice; ic++ )
  773. {
  774. ZSREF zsr = pbnpt->VzsrChoice()[ic];
  775. if ( zsrChoice == zsr )
  776. break;
  777. }
  778. if ( ic == cChoice )
  779. {
  780. Error("property \'%s\' does not have a choice of \'%s\'",
  781. zsrName.Szc(),
  782. zsrChoice.Szc()) ;
  783. bOK = false;
  784. }
  785. else
  786. {
  787. r = ic;
  788. }
  789. }
  790. break;
  791. case PROPVAR::ETPV_REAL:
  792. bOK = (fType & (fPropChoice | fPropString)) == 0 ;
  793. if ( bOK )
  794. {
  795. r = _vpv[ip]._r;
  796. }
  797. break;
  798. default:
  799. break;
  800. }
  801. if ( ! bOK )
  802. break;
  803. if ( bArray && bStr )
  804. bnp.Add( zsr );
  805. else
  806. if ( bArray )
  807. bnp.Add( r );
  808. else
  809. if ( bStr )
  810. bnp.Set( zsr );
  811. else
  812. bnp.Set( r );
  813. }
  814. if ( ! bOK )
  815. {
  816. Error("item number %d is invalid for this property", ip );
  817. }
  818. }
  819. }
  820. // Import the standard properties from the Registry
  821. void DSCPARSER::ImportPropStandard()
  822. {
  823. BNREG bnreg;
  824. try
  825. {
  826. bnreg.LoadPropertyTypes( _mbnet, true );
  827. }
  828. catch ( GMException & exbn )
  829. {
  830. if ( exbn.Ec() != EC_REGISTRY_ACCESS )
  831. throw exbn;
  832. Error( "standard properties failed to load, error '%s'",
  833. (SZC) exbn.what() );
  834. }
  835. }
  836. // Import a specific named property from the Registry
  837. void DSCPARSER :: ImportProp ( ZSREF zsrName )
  838. {
  839. if ( PbnobjFind(zsrName) != NULL )
  840. {
  841. Error("symbol name \'%s\' has already been defined",
  842. zsrName.Szc() );
  843. return;
  844. }
  845. BNREG bnreg;
  846. try
  847. {
  848. bnreg.LoadPropertyType( _mbnet, zsrName );
  849. }
  850. catch ( GMException & exbn )
  851. {
  852. if ( exbn.Ec() != EC_REGISTRY_ACCESS )
  853. throw exbn;
  854. Error( "imported property \'%s\' failed to load, error '%s'",
  855. zsrName.Szc(),
  856. (SZC) exbn.what() );
  857. }
  858. }
  859. void DSCPARSER::CheckCIFunc(ZSREF zsr)
  860. {
  861. if ( _pnode == NULL )
  862. return;
  863. ZSREF zsrMax = Mpsymtbl().intern("max");
  864. ZSREF zsrPlus = Mpsymtbl().intern("plus");
  865. if ( zsr == zsrMax )
  866. {
  867. _edist = BNDIST::ED_CI_MAX;
  868. }
  869. else
  870. {
  871. ErrorWarnNode(true,"unsupported PD function type \'%s\'", zsr.Szc());
  872. if ( zsr == zsrPlus )
  873. _edist = BNDIST::ED_CI_PLUS;
  874. }
  875. if ( _edist != BNDIST::ED_SPARSE && _vzsrParent.size() == 0 )
  876. {
  877. ErrorWarnNode(false,"parentless node cannot have distribution type \'%s\'; ignored", zsr.Szc());
  878. _edist = BNDIST::ED_SPARSE;
  879. }
  880. _bCI = true;
  881. }
  882. void DSCPARSER::CheckParentList()
  883. {
  884. if ( ! _pnode )
  885. return;
  886. UINT cErrs = 0;
  887. if ( _vzsr.size() > 0 )
  888. {
  889. switch ( _elbl )
  890. {
  891. case ESTDLBL_fixobs:
  892. case ESTDLBL_fixunobs:
  893. case ESTDLBL_unfix:
  894. ErrorWarnNode(false,"fixable node has parents");
  895. cErrs++;
  896. break;
  897. default:
  898. break;
  899. }
  900. }
  901. assert(_pnode);
  902. // Construct the probability distribution for this node & parent list
  903. VTKNPD vtknpd;
  904. // Cons-up "p(<node>|"
  905. vtknpd.push_back( TKNPD(DTKN_PD) );
  906. vtknpd.push_back( TKNPD( _pnode->ZsrefName() ) );
  907. _vimdDim.resize(_vzsr.size()+1);
  908. int iParent = 0;
  909. for ( UINT ip = 0 ; ip < _vzsr.size(); ip++ )
  910. {
  911. if ( ip > 0 )
  912. vtknpd.push_back( TKNPD(DTKN_AND) );
  913. else
  914. vtknpd.push_back( TKNPD(DTKN_COND) );
  915. ZSREF zsrParent = _vzsr[ip];
  916. GNODEMBND * pgndbnParent = PgndbnFind(zsrParent);
  917. if ( ! pgndbnParent )
  918. {
  919. ErrorWarnNode(true,"named parent \'%s\' was not declared", zsrParent.Szc());
  920. cErrs++;
  921. }
  922. else
  923. if ( ifind( _vzsrParent, zsrParent ) >= 0 )
  924. {
  925. ErrorWarnNode( true, "node \'%s\' has already been declared as a parent",
  926. zsrParent.Szc() );
  927. cErrs++;
  928. }
  929. else
  930. {
  931. _vzsrParent.push_back(zsrParent);
  932. vtknpd.push_back( TKNPD( pgndbnParent->ZsrefName() ) );
  933. _vimdDim[iParent++] = pgndbnParent->CState();
  934. if ( _pnode )
  935. {
  936. if ( Mbnet().BAcyclicEdge( pgndbnParent, _pnode ) )
  937. {
  938. Mbnet().AddElem( new GEDGEMBN_PROB( pgndbnParent, _pnode ) );
  939. }
  940. else
  941. {
  942. ErrorWarnNode( true, "connecting to parent \'%s\' creates a cycle",
  943. zsrParent.Szc() );
  944. cErrs++;
  945. }
  946. }
  947. }
  948. }
  949. _vimdDim.resize(iParent+1);
  950. if ( cErrs == 0 )
  951. {
  952. assert( _pnode );
  953. // Add the final dimension to the dimension array
  954. _vimdDim[iParent] = _pnode->CState();
  955. // Create the distribution
  956. CreateBndist( vtknpd, _vimdDim );
  957. }
  958. // If errors occurred, "_refbndist" remains empty
  959. }
  960. void DSCPARSER :: CreateBndist ( const VTKNPD & vtknpd, const VIMD & vimdDim )
  961. {
  962. // Check that there is no current distribution
  963. assert( ! RefBndist().BRef() );
  964. // Create the new distribution and its reference
  965. RefBndist() = new BNDIST;
  966. // Add it to the map in the model
  967. Mppd()[vtknpd] = RefBndist();
  968. // Declare it as "sparse" and provide its dimensionality
  969. RefBndist()->SetSparse( _vimdDim );
  970. // Check that everything worked
  971. assert( RefBndist().BRef() );
  972. }
  973. void DSCPARSER::InitProbEntries()
  974. {
  975. if ( ! BNodeProbOK() )
  976. return;
  977. _cdpi = 1;
  978. UINT cparent = _vzsrParent.size();
  979. for (UINT ip = cparent; ip-- > 0; )
  980. {
  981. GNODEMBND * pgndbnParent = PgndbnFind(_vzsrParent[ip]);
  982. assert( pgndbnParent );
  983. UINT cParentState = pgndbnParent->CState();
  984. if ( _bCI )
  985. _cdpi += cParentState - 1;
  986. else
  987. _cdpi *= cParentState;
  988. }
  989. _vsdpi.resize(_cdpi);
  990. for ( UINT idpi = 0; idpi < _cdpi; idpi++ )
  991. {
  992. _vsdpi[idpi] = sdpiAbsent;
  993. }
  994. }
  995. void DSCPARSER::CheckProbVector()
  996. {
  997. if ( _idpiLast < 0 || ! BNodeProbOK() )
  998. return; // Error already reported at higher level
  999. if (_vreal.size() != _pnode->CState())
  1000. {
  1001. ErrorWarnNode(true, "incorrect number of probabilities, found %u, expected %u",
  1002. _vreal.size(),
  1003. _pnode->CState());
  1004. return;
  1005. }
  1006. //
  1007. // At this point, _vui has the parent instantiation info,
  1008. // and _vreal has the values. Create the subscript
  1009. // array for the key to the map and the vector of
  1010. // reals for the values;
  1011. //
  1012. // MSRDEVBUG: the member variable arrays should be valarrays
  1013. // to make this more efficient
  1014. //
  1015. assert( _vui.size() == _vzsrParent.size() );
  1016. VIMD vimd;
  1017. VLREAL vlr;
  1018. //
  1019. // If this is the 'default' vector, store it with an empty subscript array.
  1020. // This special value will trigger its propagation into any empty slots of
  1021. // the dense version.
  1022. //
  1023. if ( !_bDefault )
  1024. {
  1025. // Not the 'default' vector; store it as the DPI
  1026. vdup( vimd, _vui );
  1027. }
  1028. vdup( vlr, _vreal );
  1029. // store the DPI and values into the map.
  1030. assert( RefBndist().BRef() );
  1031. RefBndist()->Mpcpdd()[vimd] = vlr;
  1032. }
  1033. // This node has an explictly empty probability distribution. Create just the "default"
  1034. // entry, and make it completely "unassessed" ("na" = -1.0).
  1035. void DSCPARSER::EmptyProbEntries()
  1036. {
  1037. if ( ! BNodeProbOK() )
  1038. return;
  1039. VIMD vimd; // Empty subscript array
  1040. // Build default vector of "na", a.k.a -1
  1041. VLREAL vlr( _pnode->CState() );
  1042. vlr = RNA;
  1043. RefBndist()->Mpcpdd()[vimd] = vlr;
  1044. }
  1045. // Check the discrete parent instantiation in _vui
  1046. void DSCPARSER::CheckDPI(bool bDefault)
  1047. {
  1048. _idpiLast = -1;
  1049. if ( ! BNodeProbOK() )
  1050. return;
  1051. if (bDefault)
  1052. {
  1053. if (!_bDefault)
  1054. {
  1055. _bDefault = bDefault;
  1056. }
  1057. else
  1058. {
  1059. ErrorWarnNode(true, "default entry already defined");
  1060. return;
  1061. }
  1062. }
  1063. UINT cui = _vui.size();
  1064. if ( (cui > 0 && _idpi > 0) || (cui == 0 && _idpi < -1) )
  1065. {
  1066. ErrorWarnNode(true, "mixtures of prefixed and unprefixed probability entries are not allowed");
  1067. return;
  1068. }
  1069. if ( cui > 0 )
  1070. _idpi = -2; // Disallow any further non-prefixed entries
  1071. else
  1072. _idpi++;
  1073. if (cui != _vzsrParent.size())
  1074. {
  1075. ErrorWarnNode(true, "incorrect number of instantiations, found %u, expected %u",
  1076. cui,
  1077. _vzsrParent.size());
  1078. return;
  1079. }
  1080. UINT idpi = 0 ;
  1081. if ( cui > 0 )
  1082. {
  1083. UINT cstate = 0;
  1084. UINT iui;
  1085. UINT isi;
  1086. if ( _bCI )
  1087. {
  1088. UINT cZeros = 0;
  1089. for (iui = cui; iui-- > 0; )
  1090. { if ( _vui[iui] == 0 )
  1091. cZeros++ ;
  1092. }
  1093. if ( cZeros < cui - 1 )
  1094. {
  1095. ErrorWarnNode(true, "invalid discrete CI parent instantiation");
  1096. return;
  1097. }
  1098. if ( _bCI && cZeros == cui)
  1099. {
  1100. idpi = 0; // It's the leak term
  1101. }
  1102. else
  1103. for (UINT iui = 0; iui < cui; iui++)
  1104. {
  1105. GNODEMBND * pgndbnParent = PgndbnFind(_vzsrParent[iui]);
  1106. assert(pgndbnParent);
  1107. isi = _vui[iui];
  1108. cstate = pgndbnParent->CState();
  1109. if ( isi > 0 )
  1110. {
  1111. idpi += isi; // This is the only non-zero term
  1112. break;
  1113. }
  1114. idpi += cstate - 1;
  1115. }
  1116. }
  1117. else
  1118. for ( iui = cui; iui-- > 0; )
  1119. {
  1120. GNODEMBND * pgndbnParent = PgndbnFind(_vzsrParent[iui]);
  1121. assert(pgndbnParent);
  1122. isi = _vui[iui];
  1123. cstate = pgndbnParent->CState();
  1124. if (isi >= cstate)
  1125. {
  1126. ErrorWarnNode(true, "invalid discrete parent instantiation");
  1127. return;
  1128. }
  1129. idpi *= cstate;
  1130. idpi += isi;
  1131. }
  1132. }
  1133. else
  1134. {
  1135. idpi = _idpi;
  1136. }
  1137. assert(idpi < _cdpi);
  1138. if (_vsdpi[idpi] != sdpiAbsent)
  1139. {
  1140. ErrorWarnNode(true, "DPI ");
  1141. PrintDPI(idpi);
  1142. _flpOut.Fprint( " %s\n", _vsdpi[idpi] == sdpiPresent
  1143. ? "already defined"
  1144. : "not needed");
  1145. }
  1146. _vsdpi[idpi] = sdpiPresent;
  1147. _idpiLast = idpi;
  1148. }
  1149. void DSCPARSER::PrintDPI ( UINT idpi )
  1150. {
  1151. _flpOut.Fprint("(");
  1152. for (UINT ip = 0; ip < _vzsrParent.size(); ip++)
  1153. {
  1154. GNODEMBND * pgndbnParent = PgndbnFind(_vzsrParent[ip]);
  1155. assert( pgndbnParent );
  1156. UINT cstate = pgndbnParent->CState();
  1157. _flpOut.Fprint( "%s%u", ip == 0 ? "" : ", ", idpi % cstate);
  1158. idpi /= cstate;
  1159. }
  1160. _flpOut.Fprint(")");
  1161. }
  1162. void DSCPARSER::CheckProbEntries()
  1163. {
  1164. if ( ! BNodeProbOK() )
  1165. return;
  1166. int cErrors = _cError;
  1167. if (!_bDefault)
  1168. {
  1169. UINT cdpiAbsent = 0;
  1170. for (UINT idpi = 0; idpi < _cdpi && _pnode; idpi++)
  1171. {
  1172. if (_vsdpi[idpi] == sdpiAbsent)
  1173. {
  1174. cdpiAbsent++;
  1175. }
  1176. }
  1177. if ( _cdpi == cdpiAbsent )
  1178. {
  1179. Warning("probabilities not defined for node \'%s\'",
  1180. _pnode->ZsrefName().Szc());
  1181. }
  1182. else
  1183. for (idpi = 0; idpi < _cdpi && _pnode; idpi++)
  1184. {
  1185. if (_vsdpi[idpi] == sdpiAbsent)
  1186. {
  1187. ErrorWarnNode(true, "no probabilities for DPI ");
  1188. PrintDPI(idpi);
  1189. _flpOut.Fprint( "\n");
  1190. }
  1191. }
  1192. }
  1193. // If no new errors arose, process probabilities
  1194. if ( cErrors == _cError )
  1195. {
  1196. assert( BNodeProbOK() ) ;
  1197. bool bOK = RefBndist()->BChangeSubtype( _edist );
  1198. assert( bOK );
  1199. }
  1200. }
  1201. void DSCPARSER :: ClearDomain()
  1202. {
  1203. _eBlk = EBLKDOM;
  1204. _domain.clear();
  1205. _ilimNext = -1;
  1206. }
  1207. void DSCPARSER :: SetRanges( bool bLower, REAL rLower, bool bUpper, REAL rUpper)
  1208. {
  1209. _rlimLower.first = bLower;
  1210. _rlimLower.second = rLower;
  1211. _rlimUpper.first = bUpper;
  1212. _rlimUpper.second = rUpper;
  1213. _ilimNext = rUpper;
  1214. }
  1215. void DSCPARSER :: SetRanges( ZSREF zsrLower, ZSREF zsrUpper )
  1216. {
  1217. if ( _eBlk != EBLKDIST )
  1218. Error("names are not allow in domain elements");
  1219. }
  1220. // Add a subrange to the currently building RDOMAIN
  1221. void DSCPARSER :: AddRange( ZSREF zsr, bool bSingleton )
  1222. {
  1223. if ( bSingleton )
  1224. {
  1225. ++_ilimNext;
  1226. SetRanges( true, _ilimNext, true, _ilimNext );
  1227. }
  1228. RANGEDEF rthis( _rlimLower, _rlimUpper, zsr );
  1229. if ( ! rthis.BValid() )
  1230. {
  1231. Error( "range \'%s\' is invalid", zsr.Szc() );
  1232. return;
  1233. }
  1234. else
  1235. if ( _domain.size() > 0 )
  1236. {
  1237. RANGEDEF & rlast = _domain.back();
  1238. // Overlap check detects and fails on equality
  1239. if ( rthis.BOverlap( rlast ) )
  1240. {
  1241. Error( "range \'%s\' overlaps with range \'%s\'",
  1242. zsr.Szc(),
  1243. rlast.ZsrName().Szc() );
  1244. return;
  1245. }
  1246. if ( rthis < rlast )
  1247. {
  1248. ErrorWarn( false, "range \'%s\' is out of sequence with \'%s\'",
  1249. zsr.Szc(),
  1250. rlast.ZsrName().Szc() );
  1251. }
  1252. else
  1253. {
  1254. assert( rlast < rthis );
  1255. }
  1256. RDOMAIN::const_iterator itdm = _domain.begin();
  1257. for ( ; itdm != _domain.end(); itdm++ )
  1258. {
  1259. const RANGEDEF & rdef = *itdm;
  1260. if ( rdef.ZsrName() == rthis.ZsrName() )
  1261. {
  1262. Error( "range name \'%s\' has already been used in this domain",
  1263. rdef.ZsrName().Szc() );
  1264. return;
  1265. }
  1266. }
  1267. }
  1268. _domain.push_back( rthis );
  1269. }
  1270. void DSCPARSER::CheckDomain ( ZSREF zsr )
  1271. {
  1272. GOBJMBN_DOMAIN * pgobjdom = new GOBJMBN_DOMAIN( & _domain );
  1273. if ( ! Mbnet().BAddElem( zsr, pgobjdom ) )
  1274. {
  1275. Error( "domain name \'%s\' is already in use", zsr.Szc() );
  1276. delete pgobjdom;
  1277. }
  1278. _domain.clear();
  1279. _eBlk = EBLKNONE;
  1280. }
  1281. // Set the state list for a node based upon a domain
  1282. void DSCPARSER::SetNodeDomain( ZSREF zsr )
  1283. {
  1284. // Verify the domain name referenced
  1285. GOBJMBN_DOMAIN * pgobjdom = NULL;
  1286. GOBJMBN * pbnobj = PbnobjFind(zsr);
  1287. if ( pbnobj )
  1288. pgobjdom = dynamic_cast<GOBJMBN_DOMAIN *>(pbnobj);
  1289. if ( pgobjdom == NULL )
  1290. {
  1291. Error( "domain name \'%s\' has not been defined", zsr.Szc() );
  1292. return;
  1293. }
  1294. // Copy the state names from the domain to the variable
  1295. _pnode->SetDomain( *pgobjdom );
  1296. }
  1297. void DSCPARSER::CheckPDF( ZSREF zsr )
  1298. {
  1299. if ( ! _pnode )
  1300. return;
  1301. ReportNYI("CheckPDF");
  1302. }
  1303. void DSCPARSER::CheckIdent( ZSREF zsr )
  1304. {
  1305. ReportNYI("CheckIdent");
  1306. }
  1307. // End of BNPARSE.CPP