windows-nt/Source/XPSP1/NT/enduser/troubleshoot/bn/bnparse.cpp
2020-09-26 16:20:57 +08:00

1526 lines
30 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: bnparse.cpp
//
//--------------------------------------------------------------------------
//
// BNPARSE.CPP
//
#include <windows.h>
#include <stdarg.h>
#include <assert.h>
#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(<node>|"
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<GOBJMBN_DOMAIN *>(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