//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1997 - 1999 // // File: bnparse.cpp // //-------------------------------------------------------------------------- // // BNPARSE.CPP // #include #include #include #include "bnparse.h" #include "bnreg.h" DSCPARSER :: DSCPARSER ( MBNET & mbnet, PARSIN & flpIn, PARSOUT & _flpOut ) : _flpIn( flpIn ), _flpOut( _flpOut ), _mbnet(mbnet), _cchToken(0), _iLine(1), _cError(0), _cWarning(0), _bUngetToken(false), _cerrorNode(0), _pnode(NULL), _bCI(false), _edist(BNDIST::ED_NONE), _bDefault(false), _idpi(0), _cdpi(0), _idpiLast(-1), _chCur(' '), _chUnget(0), _tokenCur(tokenNil), _bPropDefs(false), _cNode(0), _eBlk(EBLKNONE), _ppropMgr(NULL), _elbl(ESTDLBL_other), _ilimNext(-1) { ResetParser(); } DSCPARSER :: ~ DSCPARSER () { ResetParser(); } bool DSCPARSER :: BInitOpen( SZC szcFile ) { return _flpIn.Open( szcFile, "rt" ); } // Clear the string references from the parser. Since our // definition of YYSTYPE contains a ZSREF, we must reset the // contents of all such structures so that the MBNET's symbol // table can be destroyed at any time. void DSCPARSER :: ResetParser () { _vchToken.resize( _cchTokenMax + 1 ); // Clear all ZSREF information maintained by the parser token ensemble yyval.zsr.Clear(); yylval.zsr.Clear(); for ( int i = 0; i < YYMAXDEPTH; ) { yyv[i++].zsr.Clear(); } // Do normal member variable clearing _chUnget = 0; _bUngetToken = false; delete _ppropMgr; _ppropMgr = NULL; } bool DSCPARSER :: BParse ( UINT & cError, UINT & cWarning ) { bool bResult = YaccParse() == 0 && _cError == 0; cError = _cError; cWarning = _cWarning; // Mark the model as having topology Mbnet().BSetBFlag( EIBF_Topology ); ResetParser(); _flpOut.Flush(); return bResult; } GOBJMBN * DSCPARSER :: PbnobjFind ( SZC szcName ) { return Mpsymtbl().find(szcName); } GNODEMBND * DSCPARSER::PgndbnFind (SZC szc) { GOBJMBN * pbnobj = PbnobjFind(szc); if ( pbnobj == NULL ) return NULL; INT ebno = pbnobj->EType() ; if ( ebno != GOBJMBN::EBNO_NODE ) return NULL; GNODEMBND * pgndd; DynCastThrow(pbnobj,pgndd); return pgndd; } bool DSCPARSER :: BChNext() { if ( _chUnget > 0 ) { _chCur = _chUnget; _chUnget = 0; } else { _chCur = (char)_flpIn.Getch(); } if ( _chCur == '\n') _iLine++; return bool(_chCur != EOF); } void DSCPARSER :: SkipWS() // skip white space { while (isspace(_chCur) && BChNext()); } void DSCPARSER :: SkipToEOL() { while (_chCur != '\n' && BChNext()); } // // Add a character to a normal token; if overlength, truncate. // void DSCPARSER :: AddChar ( TCHAR tch ) { int cch = _vchToken.size() - 2; if ( _cchToken < cch ) { _vchToken[_cchToken] = tch ? tch : _chCur; _vchToken[_cchToken+1] = 0; } // Add to scanned length to report overlength token _cchToken++; } // // Add a character to a string token; do not truncate. // void DSCPARSER :: AddCharStr ( TCHAR tch ) { int cch = _vchToken.size() - 2; if ( _cchToken >= cch ) { _vchToken.resize( 2 * _vchToken.size() ); } _vchToken[_cchToken] = tch ? tch : _chCur; _vchToken[_cchToken+1] = 0; _cchToken++; } char DSCPARSER :: ChEscape() { BChNext(); switch (_chCur) { case 'n': return '\n'; case 't': return '\t'; case 'v': return '\v'; case 'b': return '\b'; case 'r': return '\r'; case 'f': return '\f'; case 'a': return '\a'; default: return _chCur; } } void DSCPARSER :: CloseIdentifier() { if ( ! MBNET::BSzLegal( SzcToken() ) ) Error("identifier \'%s\' is not legal", SzcToken() ); CloseToken("identifier"); } void DSCPARSER :: CloseToken(SZC szcTokenType) { if (_cchToken >= _cchTokenMax) { Warning("%s of length %u exceeded maximum length %u", szcTokenType, _cchToken, _cchTokenMax); } } TOKEN DSCPARSER :: TokenKeyword() { // See if the captured token is a keyword TOKEN token = MBNETDSC::TokenFind( SzcToken() ); if ( token != tokenNil ) return token; // Intern the symbol yylval.zsr = Mpsymtbl().intern( SzcToken() ); // See if it's a property type GOBJMBN * pbnobj = PbnobjFind(yylval.zsr); if ( pbnobj && pbnobj->EType() == GOBJMBN::EBNO_PROP_TYPE ) return tokenPropIdent; // It's an identifier return tokenIdent; } void DSCPARSER::ErrorWarn ( bool bErr, SZC szcFormat, va_list & valist ) { SZC szcType = bErr ? "error" : "warning" ; if ( bErr ) _cError++; else _cWarning++; int iLine = _chCur != '\n' ? _iLine : _iLine - 1; _flpOut.Fprint("\n%s(%u) %s: ", _flpIn.ZsFn().Szc(), iLine, szcType); _flpOut.Vsprint(szcFormat, valist); _flpOut.ErrWarn( bErr, iLine ); _flpOut.Flush(); } void DSCPARSER::ErrorWarn( bool bErr, SZC szcFormat, ...) { va_list valist; va_start(valist, szcFormat); ErrorWarn(bErr,szcFormat,valist); va_end(valist); } void DSCPARSER::Error( SZC szcFormat, ...) { va_list valist; va_start(valist, szcFormat); ErrorWarn(true,szcFormat,valist); va_end(valist); } void DSCPARSER::Warning(SZC szcFormat, ...) { va_list valist; va_start(valist, szcFormat); ErrorWarn(false,szcFormat,valist); va_end(valist); } void DSCPARSER::ErrorWarnNode(bool bErr, SZC szcFormat, ...) { // If this node has already been deleted, other errors supercede if (!_pnode) return; // Report the error ErrorWarn(bErr, "node %s: ", _pnode->ZsrefName().Szc()); va_list valist; va_start(valist, szcFormat); _flpOut.Vsprint(szcFormat, valist); va_end(valist); if (++_cerrorNode == 5 || bErr) _pnode = NULL; } void DSCPARSER::WarningSkip ( ZSREF zsrBlockName ) { Warning("unrecognized block name \'%s\' skipped entirely", zsrBlockName.Szc()); } void DSCPARSER :: ReportNYI (SZC szcWhich) { ErrorWarn(true,"** UNIMPLEMENTED FUNCTION: \'%s\' **", szcWhich); } TOKEN DSCPARSER::TokenNextBasic() { for (;;) { // skip over white space and comments SkipWS(); if (_chCur != '/') break; BChNext(); if (_chCur == '/') { // it's a line comment SkipToEOL(); BChNext(); // discard '\n' } else if (_chCur == '*') { // it's a block comment bool fFoundEnd = false; BChNext(); for (char chPrev = _chCur; BChNext(); chPrev = _chCur) { if (_chCur == '/' && chPrev == '*') { fFoundEnd = true; break; } } if (fFoundEnd) BChNext(); // discard terminating '/' else { ErrorWarn(true,"end of file reached in block comment"); return tokenEOF; } } else { // not a comment, return '/' _vchToken[1] = '\0'; return TOKEN(_vchToken[0] = '/'); } } if (_chCur == EOF) return tokenEOF; _cchToken = 0; if ( MBNET::BChLegal( _chCur, MBNET::ECHNM_First ) ) { AddChar(); char chLast = _chCur; while (BChNext() && MBNET::BChLegal( _chCur, MBNET::ECHNM_Middle )) { // Check for the "range" operator ".." if ( _chCur == chLast && _chCur == '.' ) break; chLast = _chCur; AddChar(); } CloseIdentifier(); return TokenKeyword(); } else if (isdigit(_chCur) || _chCur == '.') { TOKEN token = _chCur == '.' ? tokenReal : tokenInteger; AddChar(); while ( BChNext() && isdigit(_chCur) ) AddChar(); // Check for the "range" operator ".." if ( token == tokenReal && _chCur == '.' && _cchToken == 1 ) { AddChar(); BChNext(); CloseToken("rangeop"); return tokenRangeOp; } if (_cchToken == 1 && _vchToken[0] == '.') { CloseToken("punctuation"); return TOKEN('.'); } if (_chCur == '.' && token == tokenInteger) { AddChar(); token = tokenReal; UINT cchOld = _cchToken; while (BChNext() && isdigit(_chCur)) AddChar(); // Check for the "range" operator ".." if ( _chCur == '.' && cchOld == _cchToken ) { _vchToken[ -- _cchToken] = 0; _chUnget = '.'; token = tokenInteger; } // Note that check for [eE] below will fail } if (_chCur == 'e' || _chCur == 'E') { AddChar(); BChNext(); token = tokenReal; if (_chCur == '-' || _chCur == '+') { AddChar(); BChNext(); } if (isdigit(_chCur)) { AddChar(); while (BChNext() && isdigit(_chCur)) AddChar(); } } CloseToken("integer/real"); if (token == tokenInteger) yylval.ui = UINT(::atol(SzcToken())); else yylval.real = ::atof(SzcToken()); return token; } else if (_chCur == '"') { while (BChNext() && _chCur != '\n' && _chCur != '"') { if (_chCur == '\\') _chCur = ChEscape(); AddCharStr(); } if (_chCur == '"') { BChNext(); CloseToken("string"); yylval.zsr = Mpsymtbl().intern( SzcToken() ); return tokenString; } ErrorWarn(true, _chCur == '\n' ? "new line in string" : "end of file in string"); return tokenError; } AddChar(); BChNext(); CloseToken(NULL); return TOKEN(_vchToken[0]); } TOKEN DSCPARSER::TokenNext() { // we need this to be able to skip tokens if (!_bUngetToken) _tokenCur = TokenNextBasic(); else _bUngetToken = false; return _tokenCur; } void DSCPARSER::SkipUntil ( SZC szcStop, bool bDidLookAhead ) { UINT cparen = 0; UINT cbrace = 0; for (; _tokenCur != tokenEOF; TokenNext()) { if (_tokenCur == '}') { if (cbrace > 0) cbrace--; else break; } else if (_tokenCur == ')') { if (cparen > 0) cparen--; else break; } if (cparen == 0 && cbrace == 0) { if (_tokenCur < 256 && ::strchr(szcStop, _tokenCur)) break; } if (_tokenCur == '{') cbrace++; else if (_tokenCur == '(') cparen++; bDidLookAhead = false; } if (!bDidLookAhead) _bUngetToken = true; } void DSCPARSER::SyntaxError ( SZC szcMessage ) { static char szTemp[256]; static char szFile[256]; SZC szcError = ""; switch (_tokenCur) { case tokenIdent: szcError = ": unexpected identifier '%s'"; break; case tokenEOF: szcError = ": unexpected end-of-file"; break; case tokenError: return; default: szcError = ": unexpected token '%s'"; break; } sprintf(szTemp, "%s%s\n", szcMessage, szcError); ErrorWarn(true, szTemp, SzcToken()); } GNODEMBND * DSCPARSER::PgndbnAdd(ZSREF zsr) { GOBJMBN * pbnobj = PbnobjFind(zsr); assert( pbnobj == NULL ); if ( ! Mbnet().BAddElem( zsr, _pnode = new GNODEMBND ) ) { delete _pnode; _pnode = NULL; } return _pnode; } void DSCPARSER::AddSymb(ZSREF zsr) { _vzsr.push_back(zsr); } void DSCPARSER::AddStr(ZSREF zsr) { Mpsymtbl().intern(zsr); AddSymb(zsr); } void DSCPARSER::AddPv ( PROPVAR & pv ) { _vpv.push_back(pv); } void DSCPARSER::AddPropVar (ZSREF zsr) { AddPv( PROPVAR(zsr) ); } void DSCPARSER::AddPropVar (REAL & r) { AddPv( PROPVAR(r) ); } void DSCPARSER::AddUi(UINT ui) { _vui.push_back(ui); } void DSCPARSER::AddReal(REAL real) { _vreal.push_back(real); } UINT DSCPARSER::UiDpi(ZSREF zsr) { if (!_pnode || _vui.size() >= _vzsrParent.size()) return 0; GNODEMBND * pParent = PgndbnFind(_vzsrParent[_vui.size()]); assert( pParent ); for ( UINT is = 0; is < pParent->CState(); is++ ) { if ( zsr == pParent->VzsrStates()[is] ) return is; } ErrorWarnNode(true, "parent \'%s\' doesn\'t have a state named \'%s\'", pParent->ZsrefName().Szc(), zsr.Szc()); return 0; } UINT DSCPARSER::UiDpi(UINT ui) { if (!_pnode || _vui.size() >= _vzsrParent.size()) return 0; GNODEMBND * pParent = PgndbnFind(_vzsrParent[_vui.size()]); assert( pParent ); if ( ui < pParent->CState() ) return ui; ErrorWarnNode(true, "parent \'%s\' doesn\'t have a state %d", pParent->ZsrefName().Szc(), ui) ; return 0; } void DSCPARSER::SetCreator(ZSREF zsr) { Mbnet().ZsCreator() = zsr; } void DSCPARSER::SetFormat(ZSREF zsr) { Mbnet().ZsFormat() = zsr; } void DSCPARSER::SetVersion(REAL r) { Mbnet().RVersion() = r; } void DSCPARSER::SetStates () { UINT cstr = _vzsr.size(); if (_pnode) { if ( cstr != _pnode->CState() ) { ErrorWarnNode(true, "wrong number of state labels, %d != %d", cstr, _pnode->CState() ); return; } _pnode->SetStates(_vzsr); } } void DSCPARSER::SetNetworkSymb(ZSREF zsr) { Mbnet().ZsNetworkID() = zsr; } void DSCPARSER::ClearNodeInfo() { _pnode = NULL; _elbl = ESTDLBL_other; RefBndist().Deref(); _cerrorNode = 0; _idpi = -1; _idpiLast = -1; _cdpi = 0; _bDefault = false; _bCI = false; ClearCstr(); ClearVpv(); _vimdDim.clear(); _vui.clear(); _vreal.clear(); _vsdpi.clear(); _vzsrParent.clear(); _edist = BNDIST::ED_SPARSE; } void DSCPARSER :: StartNodeDecl ( ZSREF zsr ) { ClearNodeInfo(); SetNodeSymb(zsr, true); // If this is the first node we've seen and no property declarations // were seen, import the standard properties from the Registry. if ( _cNode++ == 0 ) { if ( ! _bPropDefs ) ImportPropStandard(); } } void DSCPARSER::SetNodeSymb(ZSREF zsr, bool bNew) { _pnode = PgndbnFind(zsr); if ( bNew && _pnode == NULL ) { PgndbnAdd(zsr); ASSERT_THROW( _pnode != NULL, EC_INTERNAL_ERROR, "undetected duplicate name" ); } if ( _pnode == NULL ) { ErrorWarn(true, "identifier '%s' has %s been defined", zsr.Szc(), bNew ? "already" : "not"); } else { assert( _ppropMgr ); // Find the standard label for this node, if any. PROPMBN * pprop = _ppropMgr->PFind( *_pnode, ESTDP_label ); _elbl = pprop ? (ESTDLBL) _ppropMgr->IUserToLbl( pprop->Real() ) : ESTDLBL_other; } } void DSCPARSER::SetNodeFullName(ZSREF zsr) { assert(_pnode); _pnode->ZsFullName() = zsr; } void DSCPARSER::SetNodePosition( int x, int y ) { assert(_pnode); _pnode->PtPos()._x = x; _pnode->PtPos()._y = y; } void DSCPARSER::CheckNodeInfo() { if ( ! _pnode ) return; if ( ! _pnode->LtProp().Uniqify() ) { ErrorWarnNode(false,"some properties defined more than once"); } if ( _pnode->CState() == 0 ) { ErrorWarnNode(true,"no states defined"); } } void DSCPARSER::SetNodeCstate(UINT cstate) { if ( ! _pnode ) return; _pnode->_vzsrState.resize( cstate ); } void DSCPARSER::ClearCstr() { _vzsr.clear(); } void DSCPARSER::ClearVpv() { _vpv.clear(); } void DSCPARSER::AddPropType(ZSREF zsrName, UINT fType, ZSREF zsrComment) { GOBJMBN * pbnobj = PbnobjFind(zsrName); if ( pbnobj ) { Error("symbol name \'%s\' has already been defined", zsrName.Szc() ); } else { GOBJPROPTYPE * pbnpt = new GOBJPROPTYPE; pbnpt->_fType = fType; pbnpt->_zsrComment = zsrComment; if ( fType & fPropChoice ) { for ( UINT ichoice = 0 ; ichoice < _vzsr.size(); ichoice ) { pbnpt->_vzsrChoice.push_back(_vzsr[ichoice++]); } } bool bOk = Mbnet().BAddElem( zsrName, pbnpt ); assert( bOk ); // shouldn't happen; we've already checked for duplicates above } } void DSCPARSER::StartProperties() { _eBlk = EBLKPROP; _bPropDefs = true; } void DSCPARSER::EndProperties() { _eBlk = EBLKNONE; delete _ppropMgr; _ppropMgr = new PROPMGR( Mbnet() ); } void DSCPARSER::CheckProperty( ZSREF zsrName ) { GOBJMBN * pbnobj = PbnobjFind(zsrName); if ( pbnobj == NULL || pbnobj->EType() != GOBJMBN::EBNO_PROP_TYPE ) { Error("\'%s\' is not a valid property name", zsrName.Szc() ); return; } GOBJPROPTYPE * pbnpt = (GOBJPROPTYPE*) pbnobj; UINT fType = pbnpt->FPropType(); bool bArray = (fType & fPropArray) == fPropArray; bool bStr = (fType & fPropString) == fPropString; bool bOK = true; UINT cpv = _vpv.size(); // Check the context; that is, what kind of block are we parsing? LTBNPROP * pLtProp = NULL; switch ( _eBlk ) { case EBLKNODE: // We're in a node block if ( _pnode ) pLtProp = & _pnode->LtProp(); break; case EBLKPROP: // We're in the properties block pLtProp = & _mbnet.LtProp(); break; default: // How did the parser let this happen? SyntaxError("unexpected property declaration"); return; break; } if ( cpv > 1 && ! bArray ) { Error("property \'%s\' is not an array property", zsrName.Szc() ); bOK = false; } else if ( pLtProp ) { pLtProp->push_back( PROPMBN() ); PROPMBN & bnp = pLtProp->back(); bnp.Init( *pbnpt ); for ( UINT ip = 0; ip < cpv ; ip++ ) { REAL r = -1.0; ZSREF zsr; switch ( _vpv[ip]._eType ) { case PROPVAR::ETPV_STR: if ( bStr) { zsr = _vpv[ip]._zsref; break; } if ( bOK = (fType & fPropChoice) > 0 ) { UINT cChoice = pbnpt->VzsrChoice().size(); ZSREF zsrChoice = _vpv[ip]._zsref; // find the property choice in the array for ( UINT ic = 0 ; ic < cChoice; ic++ ) { ZSREF zsr = pbnpt->VzsrChoice()[ic]; if ( zsrChoice == zsr ) break; } if ( ic == cChoice ) { Error("property \'%s\' does not have a choice of \'%s\'", zsrName.Szc(), zsrChoice.Szc()) ; bOK = false; } else { r = ic; } } break; case PROPVAR::ETPV_REAL: bOK = (fType & (fPropChoice | fPropString)) == 0 ; if ( bOK ) { r = _vpv[ip]._r; } break; default: break; } if ( ! bOK ) break; if ( bArray && bStr ) bnp.Add( zsr ); else if ( bArray ) bnp.Add( r ); else if ( bStr ) bnp.Set( zsr ); else bnp.Set( r ); } if ( ! bOK ) { Error("item number %d is invalid for this property", ip ); } } } // Import the standard properties from the Registry void DSCPARSER::ImportPropStandard() { BNREG bnreg; try { bnreg.LoadPropertyTypes( _mbnet, true ); } catch ( GMException & exbn ) { if ( exbn.Ec() != EC_REGISTRY_ACCESS ) throw exbn; Error( "standard properties failed to load, error '%s'", (SZC) exbn.what() ); } } // Import a specific named property from the Registry void DSCPARSER :: ImportProp ( ZSREF zsrName ) { if ( PbnobjFind(zsrName) != NULL ) { Error("symbol name \'%s\' has already been defined", zsrName.Szc() ); return; } BNREG bnreg; try { bnreg.LoadPropertyType( _mbnet, zsrName ); } catch ( GMException & exbn ) { if ( exbn.Ec() != EC_REGISTRY_ACCESS ) throw exbn; Error( "imported property \'%s\' failed to load, error '%s'", zsrName.Szc(), (SZC) exbn.what() ); } } void DSCPARSER::CheckCIFunc(ZSREF zsr) { if ( _pnode == NULL ) return; ZSREF zsrMax = Mpsymtbl().intern("max"); ZSREF zsrPlus = Mpsymtbl().intern("plus"); if ( zsr == zsrMax ) { _edist = BNDIST::ED_CI_MAX; } else { ErrorWarnNode(true,"unsupported PD function type \'%s\'", zsr.Szc()); if ( zsr == zsrPlus ) _edist = BNDIST::ED_CI_PLUS; } if ( _edist != BNDIST::ED_SPARSE && _vzsrParent.size() == 0 ) { ErrorWarnNode(false,"parentless node cannot have distribution type \'%s\'; ignored", zsr.Szc()); _edist = BNDIST::ED_SPARSE; } _bCI = true; } void DSCPARSER::CheckParentList() { if ( ! _pnode ) return; UINT cErrs = 0; if ( _vzsr.size() > 0 ) { switch ( _elbl ) { case ESTDLBL_fixobs: case ESTDLBL_fixunobs: case ESTDLBL_unfix: ErrorWarnNode(false,"fixable node has parents"); cErrs++; break; default: break; } } assert(_pnode); // Construct the probability distribution for this node & parent list VTKNPD vtknpd; // Cons-up "p(|" vtknpd.push_back( TKNPD(DTKN_PD) ); vtknpd.push_back( TKNPD( _pnode->ZsrefName() ) ); _vimdDim.resize(_vzsr.size()+1); int iParent = 0; for ( UINT ip = 0 ; ip < _vzsr.size(); ip++ ) { if ( ip > 0 ) vtknpd.push_back( TKNPD(DTKN_AND) ); else vtknpd.push_back( TKNPD(DTKN_COND) ); ZSREF zsrParent = _vzsr[ip]; GNODEMBND * pgndbnParent = PgndbnFind(zsrParent); if ( ! pgndbnParent ) { ErrorWarnNode(true,"named parent \'%s\' was not declared", zsrParent.Szc()); cErrs++; } else if ( ifind( _vzsrParent, zsrParent ) >= 0 ) { ErrorWarnNode( true, "node \'%s\' has already been declared as a parent", zsrParent.Szc() ); cErrs++; } else { _vzsrParent.push_back(zsrParent); vtknpd.push_back( TKNPD( pgndbnParent->ZsrefName() ) ); _vimdDim[iParent++] = pgndbnParent->CState(); if ( _pnode ) { if ( Mbnet().BAcyclicEdge( pgndbnParent, _pnode ) ) { Mbnet().AddElem( new GEDGEMBN_PROB( pgndbnParent, _pnode ) ); } else { ErrorWarnNode( true, "connecting to parent \'%s\' creates a cycle", zsrParent.Szc() ); cErrs++; } } } } _vimdDim.resize(iParent+1); if ( cErrs == 0 ) { assert( _pnode ); // Add the final dimension to the dimension array _vimdDim[iParent] = _pnode->CState(); // Create the distribution CreateBndist( vtknpd, _vimdDim ); } // If errors occurred, "_refbndist" remains empty } void DSCPARSER :: CreateBndist ( const VTKNPD & vtknpd, const VIMD & vimdDim ) { // Check that there is no current distribution assert( ! RefBndist().BRef() ); // Create the new distribution and its reference RefBndist() = new BNDIST; // Add it to the map in the model Mppd()[vtknpd] = RefBndist(); // Declare it as "sparse" and provide its dimensionality RefBndist()->SetSparse( _vimdDim ); // Check that everything worked assert( RefBndist().BRef() ); } void DSCPARSER::InitProbEntries() { if ( ! BNodeProbOK() ) return; _cdpi = 1; UINT cparent = _vzsrParent.size(); for (UINT ip = cparent; ip-- > 0; ) { GNODEMBND * pgndbnParent = PgndbnFind(_vzsrParent[ip]); assert( pgndbnParent ); UINT cParentState = pgndbnParent->CState(); if ( _bCI ) _cdpi += cParentState - 1; else _cdpi *= cParentState; } _vsdpi.resize(_cdpi); for ( UINT idpi = 0; idpi < _cdpi; idpi++ ) { _vsdpi[idpi] = sdpiAbsent; } } void DSCPARSER::CheckProbVector() { if ( _idpiLast < 0 || ! BNodeProbOK() ) return; // Error already reported at higher level if (_vreal.size() != _pnode->CState()) { ErrorWarnNode(true, "incorrect number of probabilities, found %u, expected %u", _vreal.size(), _pnode->CState()); return; } // // At this point, _vui has the parent instantiation info, // and _vreal has the values. Create the subscript // array for the key to the map and the vector of // reals for the values; // // MSRDEVBUG: the member variable arrays should be valarrays // to make this more efficient // assert( _vui.size() == _vzsrParent.size() ); VIMD vimd; VLREAL vlr; // // If this is the 'default' vector, store it with an empty subscript array. // This special value will trigger its propagation into any empty slots of // the dense version. // if ( !_bDefault ) { // Not the 'default' vector; store it as the DPI vdup( vimd, _vui ); } vdup( vlr, _vreal ); // store the DPI and values into the map. assert( RefBndist().BRef() ); RefBndist()->Mpcpdd()[vimd] = vlr; } // This node has an explictly empty probability distribution. Create just the "default" // entry, and make it completely "unassessed" ("na" = -1.0). void DSCPARSER::EmptyProbEntries() { if ( ! BNodeProbOK() ) return; VIMD vimd; // Empty subscript array // Build default vector of "na", a.k.a -1 VLREAL vlr( _pnode->CState() ); vlr = RNA; RefBndist()->Mpcpdd()[vimd] = vlr; } // Check the discrete parent instantiation in _vui void DSCPARSER::CheckDPI(bool bDefault) { _idpiLast = -1; if ( ! BNodeProbOK() ) return; if (bDefault) { if (!_bDefault) { _bDefault = bDefault; } else { ErrorWarnNode(true, "default entry already defined"); return; } } UINT cui = _vui.size(); if ( (cui > 0 && _idpi > 0) || (cui == 0 && _idpi < -1) ) { ErrorWarnNode(true, "mixtures of prefixed and unprefixed probability entries are not allowed"); return; } if ( cui > 0 ) _idpi = -2; // Disallow any further non-prefixed entries else _idpi++; if (cui != _vzsrParent.size()) { ErrorWarnNode(true, "incorrect number of instantiations, found %u, expected %u", cui, _vzsrParent.size()); return; } UINT idpi = 0 ; if ( cui > 0 ) { UINT cstate = 0; UINT iui; UINT isi; if ( _bCI ) { UINT cZeros = 0; for (iui = cui; iui-- > 0; ) { if ( _vui[iui] == 0 ) cZeros++ ; } if ( cZeros < cui - 1 ) { ErrorWarnNode(true, "invalid discrete CI parent instantiation"); return; } if ( _bCI && cZeros == cui) { idpi = 0; // It's the leak term } else for (UINT iui = 0; iui < cui; iui++) { GNODEMBND * pgndbnParent = PgndbnFind(_vzsrParent[iui]); assert(pgndbnParent); isi = _vui[iui]; cstate = pgndbnParent->CState(); if ( isi > 0 ) { idpi += isi; // This is the only non-zero term break; } idpi += cstate - 1; } } else for ( iui = cui; iui-- > 0; ) { GNODEMBND * pgndbnParent = PgndbnFind(_vzsrParent[iui]); assert(pgndbnParent); isi = _vui[iui]; cstate = pgndbnParent->CState(); if (isi >= cstate) { ErrorWarnNode(true, "invalid discrete parent instantiation"); return; } idpi *= cstate; idpi += isi; } } else { idpi = _idpi; } assert(idpi < _cdpi); if (_vsdpi[idpi] != sdpiAbsent) { ErrorWarnNode(true, "DPI "); PrintDPI(idpi); _flpOut.Fprint( " %s\n", _vsdpi[idpi] == sdpiPresent ? "already defined" : "not needed"); } _vsdpi[idpi] = sdpiPresent; _idpiLast = idpi; } void DSCPARSER::PrintDPI ( UINT idpi ) { _flpOut.Fprint("("); for (UINT ip = 0; ip < _vzsrParent.size(); ip++) { GNODEMBND * pgndbnParent = PgndbnFind(_vzsrParent[ip]); assert( pgndbnParent ); UINT cstate = pgndbnParent->CState(); _flpOut.Fprint( "%s%u", ip == 0 ? "" : ", ", idpi % cstate); idpi /= cstate; } _flpOut.Fprint(")"); } void DSCPARSER::CheckProbEntries() { if ( ! BNodeProbOK() ) return; int cErrors = _cError; if (!_bDefault) { UINT cdpiAbsent = 0; for (UINT idpi = 0; idpi < _cdpi && _pnode; idpi++) { if (_vsdpi[idpi] == sdpiAbsent) { cdpiAbsent++; } } if ( _cdpi == cdpiAbsent ) { Warning("probabilities not defined for node \'%s\'", _pnode->ZsrefName().Szc()); } else for (idpi = 0; idpi < _cdpi && _pnode; idpi++) { if (_vsdpi[idpi] == sdpiAbsent) { ErrorWarnNode(true, "no probabilities for DPI "); PrintDPI(idpi); _flpOut.Fprint( "\n"); } } } // If no new errors arose, process probabilities if ( cErrors == _cError ) { assert( BNodeProbOK() ) ; bool bOK = RefBndist()->BChangeSubtype( _edist ); assert( bOK ); } } void DSCPARSER :: ClearDomain() { _eBlk = EBLKDOM; _domain.clear(); _ilimNext = -1; } void DSCPARSER :: SetRanges( bool bLower, REAL rLower, bool bUpper, REAL rUpper) { _rlimLower.first = bLower; _rlimLower.second = rLower; _rlimUpper.first = bUpper; _rlimUpper.second = rUpper; _ilimNext = rUpper; } void DSCPARSER :: SetRanges( ZSREF zsrLower, ZSREF zsrUpper ) { if ( _eBlk != EBLKDIST ) Error("names are not allow in domain elements"); } // Add a subrange to the currently building RDOMAIN void DSCPARSER :: AddRange( ZSREF zsr, bool bSingleton ) { if ( bSingleton ) { ++_ilimNext; SetRanges( true, _ilimNext, true, _ilimNext ); } RANGEDEF rthis( _rlimLower, _rlimUpper, zsr ); if ( ! rthis.BValid() ) { Error( "range \'%s\' is invalid", zsr.Szc() ); return; } else if ( _domain.size() > 0 ) { RANGEDEF & rlast = _domain.back(); // Overlap check detects and fails on equality if ( rthis.BOverlap( rlast ) ) { Error( "range \'%s\' overlaps with range \'%s\'", zsr.Szc(), rlast.ZsrName().Szc() ); return; } if ( rthis < rlast ) { ErrorWarn( false, "range \'%s\' is out of sequence with \'%s\'", zsr.Szc(), rlast.ZsrName().Szc() ); } else { assert( rlast < rthis ); } RDOMAIN::const_iterator itdm = _domain.begin(); for ( ; itdm != _domain.end(); itdm++ ) { const RANGEDEF & rdef = *itdm; if ( rdef.ZsrName() == rthis.ZsrName() ) { Error( "range name \'%s\' has already been used in this domain", rdef.ZsrName().Szc() ); return; } } } _domain.push_back( rthis ); } void DSCPARSER::CheckDomain ( ZSREF zsr ) { GOBJMBN_DOMAIN * pgobjdom = new GOBJMBN_DOMAIN( & _domain ); if ( ! Mbnet().BAddElem( zsr, pgobjdom ) ) { Error( "domain name \'%s\' is already in use", zsr.Szc() ); delete pgobjdom; } _domain.clear(); _eBlk = EBLKNONE; } // Set the state list for a node based upon a domain void DSCPARSER::SetNodeDomain( ZSREF zsr ) { // Verify the domain name referenced GOBJMBN_DOMAIN * pgobjdom = NULL; GOBJMBN * pbnobj = PbnobjFind(zsr); if ( pbnobj ) pgobjdom = dynamic_cast(pbnobj); if ( pgobjdom == NULL ) { Error( "domain name \'%s\' has not been defined", zsr.Szc() ); return; } // Copy the state names from the domain to the variable _pnode->SetDomain( *pgobjdom ); } void DSCPARSER::CheckPDF( ZSREF zsr ) { if ( ! _pnode ) return; ReportNYI("CheckPDF"); } void DSCPARSER::CheckIdent( ZSREF zsr ) { ReportNYI("CheckIdent"); } // End of BNPARSE.CPP