1526 lines
30 KiB
C++
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
|