Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Speech / Src / Internal / SrgsCompiler / backend.cs / 1 / backend.cs
//------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Description:
// CFG Grammar backend
//
// History:
// 5/1/2004 jeanfp Created from the Sapi Managed code
//-----------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;
using System.IO;
using System.Speech.Internal.SrgsParser;
namespace System.Speech.Internal.SrgsCompiler
{
///
/// Summary description for GrammarBackEnd.
///
internal sealed partial class Backend
{
//*******************************************************************
//
// Constructors
//
//*******************************************************************
#region Constructors
internal Backend ()
{
_words = new StringBlob ();
_symbols = new StringBlob ();
}
internal Backend (StreamMarshaler streamHelper)
{
InitFromBinaryGrammar (streamHelper);
}
#endregion
//********************************************************************
//
// Internal Methods
//
//*******************************************************************
#region Internal Methods
///
/// Optimizes the grammar network by removing the epsilon states and merging
/// duplicate transitions. See GrammarOptimization.doc for details.
///
internal void Optimize ()
{
//DumpGrammarStatistics ("GrammarOptimization: Pre optimize");
_states.Optimize ();
//DumpGrammarStatistics ("GrammarOptimization: Post optimize");
// Most likely, there will be an arc with a weight != 1. So we need a weight table.
_fNeedWeightTable = true;
}
///
/// Performs consistency checks of the grammar structure, creates the
/// serialized format and either saves it to the stream provided by SetSaveOptions,
/// or reloads it into the CFG engine.
///
///
internal void Commit (StreamMarshaler streamBuffer)
{
// For debugging purpose, assert if the position is not it is assumed it should be
// Keep the start position in the stream
long startStreamPostion = streamBuffer.Stream.Position;
// put all states State into a sorted array by rule parent index and serialized index
List sortedStates = new List (_states);
// Release the memory for the original list of states
_states = null;
sortedStates.Sort ();
// Validate the grammar
ValidateAndTagRules ();
CheckLeftRecursion (sortedStates);
// Include null terminator
int cBasePath = _basePath != null ? _basePath.Length + 1 : 0;
float [] pWeights;
int cArcs;
// Add the top level semantic interpreatation tag
// This should be set as the first symbol in the symbol string blog since it must hold on a 16 bits value.
int semanticInterpretationGlobals = 0;
if (_globalTags.Count > 0)
{
StringBuilder sb = new StringBuilder ();
foreach (string s in _globalTags)
{
sb.Append (s);
}
_symbols.Add (sb.ToString (), out semanticInterpretationGlobals);
semanticInterpretationGlobals = _symbols.OffsetFromId (semanticInterpretationGlobals);
if (semanticInterpretationGlobals > UInt16.MaxValue)
{
throw new OverflowException (SR.Get (SRID.TooManyRulesWithSemanticsGlobals));
}
}
#if !NO_STG
// Write the method names as symbols
foreach (ScriptRef script in _scriptRefs)
{
_symbols.Add (script._sMethod, out script._idSymbol);
}
#endif
// get the header
CfgGrammar.CfgSerializedHeader header = BuildHeader (sortedStates, cBasePath, unchecked ((UInt16) semanticInterpretationGlobals), out cArcs, out pWeights);
streamBuffer.WriteStream (header);
//
// For the string blobs, we must explicitly report I/O error since the blobs don't
// use the error log facility.
//
System.Diagnostics.Debug.Assert (streamBuffer.Stream.Position - startStreamPostion == header.pszWords);
streamBuffer.WriteArrayChar (_words.SerializeData (), _words.SerializeSize ());
System.Diagnostics.Debug.Assert (streamBuffer.Stream.Position - startStreamPostion == header.pszSymbols);
streamBuffer.WriteArrayChar (_symbols.SerializeData (), _symbols.SerializeSize ());
System.Diagnostics.Debug.Assert (streamBuffer.Stream.Position - startStreamPostion == header.pRules);
foreach (Rule rule in _rules)
{
rule.Serialize (streamBuffer);
}
if (cBasePath > 0)
{
streamBuffer.WriteArrayChar (_basePath.ToCharArray (), _basePath.Length);
// Add a zero to be compatible with SAPI 5
System.Diagnostics.Debug.Assert (_basePath.Length + 1 == cBasePath);
streamBuffer.WriteArrayChar (_achZero, 1);
// Zero-pad to align following structures
streamBuffer.WriteArray (_abZero3, cBasePath * Helpers._sizeOfChar & 3);
}
//
// Write a dummy 0 index state entry
//
CfgArc dummyArc = new CfgArc ();
System.Diagnostics.Debug.Assert (streamBuffer.Stream.Position - startStreamPostion == header.pArcs);
streamBuffer.WriteStream (dummyArc);
int ulWeightOffset = 1;
uint arcOffset = 1;
bool semanticInterpretation = (GrammarOptions & GrammarOptions.MssV1) == GrammarOptions.MssV1;
foreach (State state in sortedStates)
{
state.SerializeStateEntries (streamBuffer, semanticInterpretation, pWeights, ref arcOffset, ref ulWeightOffset);
}
System.Diagnostics.Debug.Assert (streamBuffer.Stream.Position - startStreamPostion == header.pWeights);
if (_fNeedWeightTable)
{
streamBuffer.WriteArray (pWeights, cArcs);
}
System.Diagnostics.Debug.Assert (streamBuffer.Stream.Position - startStreamPostion == header.tags);
if (!semanticInterpretation)
{
foreach (State state in sortedStates)
{
state.SetEndArcIndexForTags ();
}
}
// Remove the orphaned arcs
// This could happen in the case of a -
for (int i = _tags.Count - 1; i >= 0; i--)
{
// When arc are created the index is set to zero. This value changes during serialization
// if an arc references it
if (_tags [i]._cfgTag.ArcIndex == 0)
{
_tags.RemoveAt (i);
}
}
// Sort the _tags array by ArcIndex
_tags.Sort ();
// Write the _tags array
foreach (Tag tag in _tags)
{
tag.Serialize (streamBuffer);
}
#if !NO_STG
// Write the script references and the IL write after the header so getting it for the grammar
// Does not require a seek to the end of the file
System.Diagnostics.Debug.Assert (header.pScripts == 0 || streamBuffer.Stream.Position - startStreamPostion == header.pScripts);
foreach (ScriptRef script in _scriptRefs)
{
script.Serialize (_symbols, streamBuffer);
}
// Write the assembly bits
System.Diagnostics.Debug.Assert (header.pIL == 0 || streamBuffer.Stream.Position - startStreamPostion == header.pIL);
if (_il != null && _il.Length > 0)
{
streamBuffer.Stream.Write (_il, 0, _il.Length);
}
System.Diagnostics.Debug.Assert (header.pPDB == 0 || streamBuffer.Stream.Position - startStreamPostion == header.pPDB);
if (_pdb != null && _pdb.Length > 0)
{
streamBuffer.Stream.Write (_pdb, 0, _pdb.Length);
}
#endif
}
///
/// Description:
/// Combine the current data in a grammar with one comming from a CFG
///
///
///
///
internal static Backend CombineGrammar (string ruleName, Backend org, Backend extra)
{
//
Backend be = new Backend ();
be._fLoadedFromBinary = true;
be._fNeedWeightTable = org._fNeedWeightTable;
be._grammarMode = org._grammarMode;
be._grammarOptions = org._grammarOptions;
// Hash source state to destination state
Dictionary srcToDestHash = new Dictionary ();
// Find the rule
foreach (Rule orgRule in org._rules)
{
if (orgRule.Name == ruleName)
{
be.CloneSubGraph (orgRule, org, extra, srcToDestHash, true);
}
}
return be;
}
internal State CreateNewState (Rule rule)
{
return _states.CreateNewState (rule);
}
internal void DeleteState (State state)
{
_states.DeleteState (state);
}
internal void MoveInputTransitionsAndDeleteState (State from, State to)
{
_states.MoveInputTransitionsAndDeleteState (from, to);
}
internal void MoveOutputTransitionsAndDeleteState (State from, State to)
{
_states.MoveOutputTransitionsAndDeleteState (from, to);
}
///
/// Tries to find the rule's initial state handle. If both a name and an id
/// are provided, then both have to match in order for this call to succeed.
/// If the rule doesn't already exist then we define it if fCreateIfNotExists,
/// otherwise we return an error ().
///
/// - pszRuleName name of rule to find/define (null: don't care)
/// - ruleId id of rule to find/define (0: don't care)
/// - dwAttribute rule attribute for defining the rule
/// - fCreateIfNotExists creates the rule using name, id, and attributes
/// in case the rule doesn't already exist
///
/// throws:
/// S_OK, E_INVALIDARG, E_OUTOFMEMORY
/// SPERR_RULE_NOT_FOUND -- no rule found and we don't create a new one
/// SPERR_RULE_NAME_ID_CONFLICT -- rule name and id don't match
///
///
///
///
internal Rule CreateRule (string name, SPCFGRULEATTRIBUTES attributes)
{
//CfgGrammar.TraceInformation ("BackEnd::CreateRule");
SPCFGRULEATTRIBUTES allFlags = SPCFGRULEATTRIBUTES.SPRAF_TopLevel | SPCFGRULEATTRIBUTES.SPRAF_Active | SPCFGRULEATTRIBUTES.SPRAF_Export | SPCFGRULEATTRIBUTES.SPRAF_Import | SPCFGRULEATTRIBUTES.SPRAF_Interpreter | SPCFGRULEATTRIBUTES.SPRAF_Dynamic | SPCFGRULEATTRIBUTES.SPRAF_Root;
if (attributes != 0 && ((attributes & ~allFlags) != 0 || ((attributes & SPCFGRULEATTRIBUTES.SPRAF_Import) != 0 && (attributes & SPCFGRULEATTRIBUTES.SPRAF_Export) != 0)))
{
throw new ArgumentException ("attributes");
}
// PS: 52277 - SAPI does not properly handle a rule marked as Import and TopLevel/Active/Root.
// - To maintain maximal backwards compatibility, if a rule is marked as Import, we will unmark TopLevel/Active/Root.
// - This changes the behavior when application tries to activate this rule. However, given that it is already
// broken/fragile, we believe it is better to change the behavior.
if ((attributes & SPCFGRULEATTRIBUTES.SPRAF_Import) != 0 && ((attributes & SPCFGRULEATTRIBUTES.SPRAF_TopLevel) != 0 || (attributes & SPCFGRULEATTRIBUTES.SPRAF_Active) != 0 || (attributes & SPCFGRULEATTRIBUTES.SPRAF_Root) != 0))
{
//CfgGrammar.TraceInformation ("Warning: A rule cannot be marked as both Import and TopLevel/Active/Root.\n" + " TopLevel/Active/Root have been disabled.");
attributes &= ~(SPCFGRULEATTRIBUTES.SPRAF_TopLevel | SPCFGRULEATTRIBUTES.SPRAF_Active | SPCFGRULEATTRIBUTES.SPRAF_Root);
}
if ((attributes & SPCFGRULEATTRIBUTES.SPRAF_Import) != 0 && (name [0] == '\0'))
{
LogError (name, SRID.InvalidImport);
}
if (_fLoadedFromBinary)
{
// Scan all non-dynamic names and prevent a duplicate...
foreach (Rule r in _rules)
{
string wpszName = _symbols [r._cfgRule._nameOffset];
if (!r._cfgRule.Dynamic && name == wpszName)
{
LogError (name, SRID.DuplicatedRuleName);
}
}
}
int idString;
int cImportedRule = 0;
Rule rule = new Rule (this, name, _symbols.Add (name, out idString), attributes, _ruleIndex, 0, _grammarOptions & GrammarOptions.TagFormat, ref cImportedRule);
rule._iSerialize2 = _ruleIndex++;
if ((attributes & SPCFGRULEATTRIBUTES.SPRAF_Root) != 0)
{
if (_rootRule != null)
{
//We already have a root rule, return error code.
LogError (name, SRID.RootRuleAlreadyDefined);
}
else
{
_rootRule = rule;
}
}
// Add rule to RuleListByName and RuleListByID hash tables.
if (rule._cfgRule._nameOffset != 0)
{
_nameOffsetRules.Add (rule._cfgRule._nameOffset, rule);
}
//
// It is important to insert this at the tail for dynamic rules to
// retain their slot number.
//
_rules.Add (rule);
_rules.Sort ();
return rule;
}
///
/// Internal method for finding rule in rule list
///
///
///
internal Rule FindRule (string sRule)
{
//CfgGrammar.TraceInformation ("BackEnd::FindRule");
Rule rule = null;
if (_nameOffsetRules.Count > 0)
{
// Find rule corresponding to name symbol offset corresponding to the RuleName
int iWord = _symbols.Find (sRule);
if (iWord > 0)
{
int dwSymbolOffset = _symbols.OffsetFromId (iWord);
System.Diagnostics.Debug.Assert (dwSymbolOffset == 0 || _symbols [iWord] == sRule);
rule = dwSymbolOffset > 0 && _nameOffsetRules.ContainsKey (dwSymbolOffset) ? _nameOffsetRules [dwSymbolOffset] : null;
}
}
if (rule != null)
{
string sRuleFound = rule.Name;
// at least one of the 2 arguments matched
// names either match or they are both null!
if (!((string.IsNullOrEmpty (sRule) || (!string.IsNullOrEmpty (sRule) && !string.IsNullOrEmpty (sRuleFound) && sRuleFound == sRule))))
{
LogError (sRule, SRID.RuleNameIdConflict);
}
}
return rule != null ? rule : null;
}
///
/// Adds a word transition from hFromState to hToState. If hToState == null
/// then the arc will be to the (implicit) terminal state. If psz == null then
/// we add an epsilon transition. Properties are pushed back to the
/// first un-ambiguous arc in case we can share a common initial state path.
/// The weight will be placed on the first arc (if there exists an arc with
/// the same word but different weight we will create a new arc).
///
internal Arc WordTransition (string sWord, float flWeight, int requiredConfidence)
{
return CreateTransition (sWord, flWeight, requiredConfidence);
}
internal Arc SubsetTransition (string text, MatchMode matchMode)
{
// Performs white space normalization in place
text = NormalizeTokenWhiteSpace (text);
return new Arc (text, null, _words, 1.0f, CfgGrammar.SP_NORMAL_CONFIDENCE, null, matchMode, ref _fNeedWeightTable);
}
///
/// Adds a rule (reference) transition from hFromState to hToState.
/// hRule can also be one of these special transition handles:
/// SPRULETRANS_WILDCARD : "WILDCARD" transition
/// SPRULETRANS_DICTATION : single word from dictation
/// SPRULETRANS_TEXTBUFFER : "TEXTBUFFER" transition
///
/// must be initial state of rule
/// Rule calling the ruleref
///
internal Arc RuleTransition (Rule rule, Rule parentRule, float flWeight)
{
//CfgGrammar.TraceInformation ("BackEnd::AddRuleTransition");
Rule ruleToTransitionTo = null;
if (flWeight < 0.0f)
{
XmlParser.ThrowSrgsException (SRID.UnsupportedFormat);
}
Rule specialRuleTrans = null;
if (rule == CfgGrammar.SPRULETRANS_WILDCARD || rule == CfgGrammar.SPRULETRANS_DICTATION || rule == CfgGrammar.SPRULETRANS_TEXTBUFFER)
{
specialRuleTrans = rule;
}
else
{
ruleToTransitionTo = rule;
}
bool fNeedWeightTable = false;
Arc arc = new Arc (null, ruleToTransitionTo, _words, flWeight, '\0', specialRuleTrans, MatchMode.AllWords, ref fNeedWeightTable);
AddArc (arc);
if (ruleToTransitionTo != null && parentRule != null)
{
ruleToTransitionTo._listRules.Insert (0, parentRule);
}
return arc;
}
///
/// Adds a word transition from hFromState to hToState. If hToState == null
/// then the arc will be to the (implicit) terminal state. If psz == null then
/// we add an epsilon transition. Properties are pushed back to the
/// first un-ambiguous arc in case we can share a common initial state path.
/// The weight will be placed on the first arc (if there exists an arc with
/// the same word but different weight we will create a new arc).
///
///
///
internal Arc EpsilonTransition (float flWeight)
{
return CreateTransition (null, flWeight, CfgGrammar.SP_NORMAL_CONFIDENCE);
}
internal void AddSemanticInterpretationTag (Arc arc, CfgGrammar.CfgProperty propertyInfo)
{
//CfgGrammar.TraceInformation ("BackEnd::AddSemanticTag");
Tag tag = new Tag (this, propertyInfo);
_tags.Add (tag);
arc.AddStartTag (tag);
arc.AddEndTag (tag);
}
internal void AddPropertyTag (Arc start, Arc end, CfgGrammar.CfgProperty propertyInfo)
{
//CfgGrammar.TraceInformation ("BackEnd::AddSemanticTag");
Tag tag = new Tag (this, propertyInfo);
_tags.Add (tag);
start.AddStartTag (tag);
end.AddEndTag (tag);
}
///
/// Traverse the graph starting from SrcStartState, cloning each state as we go along,
/// cloning each transition except ones originating from SrcEndState, and return
/// the cloned state corresponding to SrcEndState.
///
///
///
///
///
internal State CloneSubGraph (State srcFromState, State srcEndState, State destFromState)
{
Dictionary SrcToDestHash = new Dictionary (); // Hash source state to destination state
Stack CloneStack = new Stack (); // States to process
Dictionary tags = new Dictionary ();
// Add initial state to CloneStack and SrcToDestHash.
SrcToDestHash.Add (srcFromState, destFromState);
CloneStack.Push (srcFromState);
// While there are still states on the CloneStack (ToDo collection)
while (CloneStack.Count > 0)
{
srcFromState = CloneStack.Pop ();
destFromState = SrcToDestHash [srcFromState];
System.Diagnostics.Debug.Assert (destFromState != null);
// For each transition from srcFromState (except SrcEndState)
foreach (Arc arc in srcFromState.OutArcs)
{
// - Lookup the DestToState corresponding to SrcToState
State srcToState = arc.End;
State destToState = null;
if (srcToState != null)
{
// - If not found, clone a new DestToState, add SrcToState.DestToState to SrcToDestHash, and add SrcToState to CloneStack.
if (!SrcToDestHash.ContainsKey (srcToState))
{
destToState = CreateNewState (srcToState.Rule);
SrcToDestHash.Add (srcToState, destToState);
CloneStack.Push (srcToState);
}
else
{
destToState = SrcToDestHash [srcToState]; ;
}
}
// - Clone the transition from SrcFromState.SrcToState at DestFromState.DestToState
// -- Clone Arc
Arc newArc = new Arc (arc, destFromState, destToState);
AddArc (newArc);
// -- Clone SemanticTag
newArc.CloneTags (arc, _tags, tags, null);
// -- Add Arc
newArc.ConnectStates ();
}
}
System.Diagnostics.Debug.Assert (tags.Count == 0);
return SrcToDestHash [srcEndState];
}
///
/// Traverse the graph starting from SrcStartState, cloning each state as we go along,
/// cloning each transition except ones originating from SrcEndState, and return
/// the cloned state corresponding to SrcEndState.
///
///
///
///
///
///
///
internal void CloneSubGraph (Rule rule, Backend org, Backend extra, Dictionary srcToDestHash, bool fromOrg)
{
Backend beSrc = fromOrg ? org : extra;
List CloneStack = new List (); // States to process
Dictionary tags = new Dictionary ();
// Push all the state for the top level rule
CloneState (rule._firstState, CloneStack, srcToDestHash);
// While there are still states on the CloneStack (ToDo collection)
while (CloneStack.Count > 0)
{
State srcFromState = CloneStack [0];
CloneStack.RemoveAt (0);
State destFromState = srcToDestHash [srcFromState];
// For each transition from srcFromState (except SrcEndState)
foreach (Arc arc in srcFromState.OutArcs)
{
// - Lookup the DestToState corresponding to SrcToState
State srcToState = arc.End;
State destToState = null;
if (srcToState != null)
{
if (!srcToDestHash.ContainsKey (srcToState))
{
// - If not found, then it is a new rule, just clown it.
CloneState (srcToState, CloneStack, srcToDestHash);
}
destToState = srcToDestHash [srcToState];
}
// - Clone the transition from SrcFromState.SrcToState at DestFromState.DestToState
// -- Clone Arc
int newWordId = arc.WordId;
if (beSrc != null && arc.WordId > 0)
{
_words.Add (beSrc.Words [arc.WordId], out newWordId);
}
Arc newArc = new Arc (arc, destFromState, destToState, newWordId);
// -- Clone SemanticTag
newArc.CloneTags (arc, _tags, tags, this);
// For rule ref push the first state of the ruleref
if (arc.RuleRef != null)
{
string ruleName;
// Check for DYNAMIC grammars
if (arc.RuleRef.Name.IndexOf ("URL:DYNAMIC#", StringComparison.Ordinal) == 0)
{
ruleName = arc.RuleRef.Name.Substring (12);
if (fromOrg == true && FindInRules (ruleName) == null)
{
Rule ruleExtra = extra.FindInRules (ruleName);
if (ruleExtra == null)
{
XmlParser.ThrowSrgsException (SRID.DynamicRuleNotFound, ruleName);
}
CloneSubGraph (ruleExtra, org, extra, srcToDestHash, false);
}
}
else if (arc.RuleRef.Name.IndexOf ("URL:STATIC#", StringComparison.Ordinal) == 0)
{
ruleName = arc.RuleRef.Name.Substring (11);
if (fromOrg == false && FindInRules (ruleName) == null)
{
Rule ruleOrg = org.FindInRules (ruleName);
if (ruleOrg == null)
{
XmlParser.ThrowSrgsException (SRID.DynamicRuleNotFound, ruleName);
}
CloneSubGraph (ruleOrg, org, extra, srcToDestHash, true);
}
}
else
{
ruleName = arc.RuleRef.Name;
Rule ruleExtra = org.FindInRules (ruleName);
if (fromOrg == false)
{
CloneSubGraph (arc.RuleRef, org, extra, srcToDestHash, true);
}
}
Rule refRule = FindInRules (ruleName);
if (refRule == null)
{
refRule = CloneState (arc.RuleRef._firstState, CloneStack, srcToDestHash);
}
newArc.RuleRef = refRule;
}
// -- Add Arc
newArc.ConnectStates ();
}
}
System.Diagnostics.Debug.Assert (tags.Count == 0);
}
///
/// Delete disconnected subgraph starting at hState.
/// Traverse the graph starting from SrcStartState, and delete each state as we go along.
///
///
internal void DeleteSubGraph (State state)
{
// Add initial state to DeleteStack.
Stack stateToProcess = new Stack (); // States to delete
Collection arcsToDelete = new Collection ();
Collection statesToDelete = new Collection ();
stateToProcess.Push (state);
// While there are still states on the listDelete (ToDo collection)
while (stateToProcess.Count > 0)
{
// For each transition from state,
state = stateToProcess.Pop ();
statesToDelete.Add (state);
arcsToDelete.Clear ();
// Accumulate the arcs to delete and add new states to the stack of states to process
foreach (Arc arc in state.OutArcs)
{
// Add EndState to listDelete, if unique
State endState = arc.End;
// Add this state to the list of states to delete
if (endState != null && !stateToProcess.Contains (endState) && !statesToDelete.Contains (endState))
{
stateToProcess.Push (endState);
}
arcsToDelete.Add (arc);
}
// Clear up the arcs
foreach (Arc arc in arcsToDelete)
{
arc.Start = arc.End = null;
}
}
foreach (State stateToDelete in statesToDelete)
{
// Delete state and remove from listDelete
System.Diagnostics.Debug.Assert (stateToDelete != null);
System.Diagnostics.Debug.Assert (stateToDelete.InArcs.IsEmpty);
System.Diagnostics.Debug.Assert (stateToDelete.OutArcs.IsEmpty);
DeleteState (stateToDelete);
}
}
///
/// Modify the placeholder rule attributes after it has been created.
/// This is only safe to use in the context of SRGSGrammarCompiler.
///
///
///
///
internal void SetRuleAttributes (Rule rule, SPCFGRULEATTRIBUTES dwAttributes)
{
// Check if this is the Root rule
if ((dwAttributes & SPCFGRULEATTRIBUTES.SPRAF_Root) != 0)
{
if (_rootRule != null)
{
//We already have a root rule, return error code.
XmlParser.ThrowSrgsException (SRID.RootRuleAlreadyDefined);
}
else
{
_rootRule = rule;
}
}
rule._cfgRule.TopLevel = ((dwAttributes & SPCFGRULEATTRIBUTES.SPRAF_TopLevel) != 0);
rule._cfgRule.DefaultActive = ((dwAttributes & SPCFGRULEATTRIBUTES.SPRAF_Active) != 0);
rule._cfgRule.PropRule = ((dwAttributes & SPCFGRULEATTRIBUTES.SPRAF_Interpreter) != 0);
rule._cfgRule.Export = ((dwAttributes & SPCFGRULEATTRIBUTES.SPRAF_Export) != 0);
rule._cfgRule.Dynamic = ((dwAttributes & SPCFGRULEATTRIBUTES.SPRAF_Dynamic) != 0);
rule._cfgRule.Import = ((dwAttributes & SPCFGRULEATTRIBUTES.SPRAF_Import) != 0);
}
///
/// Set the path from which relative grammar imports are calculated. As specified by xml:base / meta base
/// Null or empty string will clear any existing base path.
///
///
internal void SetBasePath (string sBasePath)
{
if (!string.IsNullOrEmpty (sBasePath))
{
// Validate base path.
Uri uri = new Uri (sBasePath, UriKind.RelativeOrAbsolute);
//Url Canonicalized
_basePath = uri.ToString ();
}
else
{
_basePath = null;
}
}
///
/// Perform white space normalization in place.
/// - Trim leading/trailing white spaces.
/// - Collapse white space sequences to a single ' '.
///
///
///
internal static string NormalizeTokenWhiteSpace (string sToken)
{
System.Diagnostics.Debug.Assert (!string.IsNullOrEmpty (sToken));
// Trim leading and ending white spaces
sToken = sToken.Trim (Helpers._achTrimChars);
// Easy out if there are no consecutive double white spaces
if (sToken.IndexOf (" ", StringComparison.Ordinal) == -1)
{
return sToken;
}
// Normalize internal spaces
char [] achSrc = sToken.ToCharArray ();
int iDest = 0;
for (int i = 0; i < achSrc.Length; )
{
// Collapsed multiple white spaces into ' '
if (achSrc [i] == ' ')
{
do
{
i++;
} while (achSrc [i] == ' ');
achSrc [iDest++] = ' ';
continue;
}
// Copy the non-white space character
achSrc [iDest++] = achSrc [i++];
}
return new string (achSrc, 0, iDest);
}
#endregion
//********************************************************************
//
// Internal Property
//
//********************************************************************
#region Internal Property
internal StringBlob Words
{
get
{
return this._words;
}
}
internal StringBlob Symbols
{
get
{
return this._symbols;
}
}
#endregion
//*******************************************************************
//
// Private Methods
//
//********************************************************************
#region Private Methods
///
/// Description:
/// Load compiled grammar data. This overwrites any existing data in the grammar
/// We end up with containers of words, symbols, rules, arcs, states and state handles, etc.
///
///
#if true
internal void InitFromBinaryGrammar (StreamMarshaler streamHelper)
{
//CfgGrammar.TraceInformation ("BackEnd::InitFromBinaryGrammar");
CfgGrammar.CfgHeader header = CfgGrammar.ConvertCfgHeader (streamHelper);
_words = header.pszWords;
_symbols = header.pszSymbols;
_grammarOptions = header.GrammarOptions;
//
// Build up the internal representation
//
State [] apStateTable = new State [header.arcs.Length];
SortedDictionary ruleFirstArcs = new SortedDictionary ();
//
// Initialize the rules
//
int previousCfgLastRules = _rules.Count;
BuildRulesFromBinaryGrammar (header, apStateTable, ruleFirstArcs, previousCfgLastRules);
//
// Initialize the arcs
//
Arc [] apArcTable = new Arc [header.arcs.Length];
bool fLastArcNull = true;
CfgArc pLastArc = new CfgArc ();
State currentState = null;
IEnumerator> ieFirstArcs = ruleFirstArcs.GetEnumerator ();
// If no rules, then we have no arcs
if (ieFirstArcs.MoveNext ())
{
KeyValuePair kvFirstArc = ieFirstArcs.Current;
Rule ruleCur = kvFirstArc.Value;
// We repersist the static AND dynamic parts for now. This allows the grammar to be queried
// with the automation interfaces
for (int k = 1; k < header.arcs.Length; k++)
{
CfgArc arc = header.arcs [k];
// Reset the Transition index based on the compbined stringblobs
if (arc.RuleRef)
{
// for a ruleref offset the rule index
ruleCur._listRules.Add (_rules [(int) arc.TransitionIndex]);
}
if (kvFirstArc.Key == k)
{
// we are entering a new rule now
ruleCur = kvFirstArc.Value;
// Reset to zero once we have read the last rule.
if (ieFirstArcs.MoveNext ())
{
kvFirstArc = ieFirstArcs.Current;
}
}
// new currentState?
if (fLastArcNull || pLastArc.LastArc)
{
if (apStateTable [k] == null)
{
uint hNewState = CfgGrammar.NextHandle;
apStateTable [k] = new State (ruleCur, hNewState, k);
AddState (apStateTable [k]);
}
currentState = apStateTable [k];
}
//
// now get the arc
//
int iNextArc = (int) (arc.NextStartArcIndex);
Arc newArc;
State targetState = null;
if (currentState != null && iNextArc != 0)
{
if (apStateTable [iNextArc] == null)
{
uint hNewState = CfgGrammar.NextHandle;
apStateTable [iNextArc] = new State (ruleCur, hNewState, iNextArc);
AddState (apStateTable [iNextArc]);
}
targetState = apStateTable [iNextArc];
}
float flWeight = header.weights != null ? header.weights [k] : CfgGrammar.DEFAULT_WEIGHT;
// determine properties of the arc now ...
if (arc.RuleRef)
{
Rule ruleToTransitionTo = _rules [(int) arc.TransitionIndex];
newArc = new Arc (null, ruleToTransitionTo, _words, flWeight, CfgGrammar.SP_NORMAL_CONFIDENCE, null, MatchMode.AllWords, ref _fNeedWeightTable);
}
else
{
int transitionIndex = (int) arc.TransitionIndex;
int ulSpecialTransitionIndex = (int) ((transitionIndex == CfgGrammar.SPWILDCARDTRANSITION || transitionIndex == CfgGrammar.SPDICTATIONTRANSITION || transitionIndex == CfgGrammar.SPTEXTBUFFERTRANSITION) ? transitionIndex : 0);
newArc = new Arc ((ulSpecialTransitionIndex != 0) ? 0 : (int) arc.TransitionIndex, flWeight, arc.LowConfRequired ? CfgGrammar.SP_LOW_CONFIDENCE : arc.HighConfRequired ? CfgGrammar.SP_HIGH_CONFIDENCE : CfgGrammar.SP_NORMAL_CONFIDENCE, ulSpecialTransitionIndex, MatchMode.AllWords, ref _fNeedWeightTable);
}
newArc.Start = currentState;
newArc.End = targetState;
AddArc (newArc);
apArcTable [k] = newArc;
fLastArcNull = false;
pLastArc = arc;
}
}
// Initialize the Semantics tags
for (int k = 1, iCurTag = 0; k < header.arcs.Length; k++)
{
CfgArc arc = header.arcs [k];
if (arc.HasSemanticTag)
{
System.Diagnostics.Debug.Assert (header.tags [iCurTag].StartArcIndex == k);
while (iCurTag < header.tags.Length && header.tags [iCurTag].StartArcIndex == k)
{
// we should already point to the tag
CfgSemanticTag semTag = header.tags [iCurTag];
Tag tag = new Tag (this, semTag);
_tags.Add (tag);
apArcTable [tag._cfgTag.StartArcIndex].AddStartTag (tag);
apArcTable [tag._cfgTag.EndArcIndex].AddEndTag (tag);
// If we have ms-properties than _nameOffset != overwise it is w3c tags.
if (semTag._nameOffset > 0)
{
tag._cfgTag._nameOffset = _symbols.OffsetFromId (_symbols.Find (_symbols.FromOffset (semTag._nameOffset)));
}
else
{
// The offset of the JScrip expression is stored in the value field.
tag._cfgTag._valueOffset = _symbols.OffsetFromId (_symbols.Find (_symbols.FromOffset (semTag._valueOffset)));
}
iCurTag++;
}
}
}
//
_fNeedWeightTable = true;
if (header.BasePath != null)
{
SetBasePath (header.BasePath);
}
_guid = header.GrammarGUID;
_langId = header.langId;
_grammarMode = header.GrammarMode;
_fLoadedFromBinary = true;
// Save Last ArcIndex
#if VSCOMPILE && DEBUG
DumpGrammarStatistics ("InitFromBinaryGrammar");
#endif
}
private Arc CreateTransition (string sWord, float flWeight, int requiredConfidence)
{
// epsilon transition for empty words
return AddSingleWordTransition (!string.IsNullOrEmpty (sWord) ? sWord : null, flWeight, requiredConfidence);
}
///
///
///
///
///
///
///
///
///
private CfgGrammar.CfgSerializedHeader BuildHeader (List sortedStates, int cBasePath, UInt16 iSemanticGlobals, out int cArcs, out float [] pWeights)
{
cArcs = 1; // Start with offset one! (0 indicates dead state).
pWeights = null;
int cSemanticTags = 0;
int cLargest = 0;
foreach (State state in sortedStates)
{
// For new states SerializeId is INFINITE so we set it correctly here.
// For existing states we preserve the index from loading,
// unless new states have been added in.
state.SerializeId = cArcs;
int thisState = state.NumArcs;
#if DEBUG
if (thisState == 0 && state.InArcs.IsEmpty && state.Rule._cStates > 1)
{
XmlParser.ThrowSrgsException (SRID.StateWithNoArcs);
}
#endif
cArcs += thisState;
if (cLargest < thisState)
{
cLargest = thisState;
}
cSemanticTags += state.NumSemanticTags;
}
CfgGrammar.CfgSerializedHeader header = new CfgGrammar.CfgSerializedHeader ();
uint ulOffset = (uint) Marshal.SizeOf (typeof (CfgGrammar.CfgSerializedHeader));
header.FormatId = CfgGrammar._SPGDF_ContextFree;
_guid = Guid.NewGuid ();
header.GrammarGUID = _guid;
header.LangID = (UInt16) _langId;
header.pszSemanticInterpretationGlobals = iSemanticGlobals;
header.cArcsInLargestState = cLargest;
header.cchWords = _words.StringSize ();
header.cWords = _words.Count;
// For compat with SAPI 5.x add one to cWords if there's more than one word.
// The CFGEngine code assumes cWords includes the initial empty-string word.
// See PS 11491 and 61982.
if (header.cWords > 0)
{
header.cWords++;
}
header.pszWords = ulOffset;
ulOffset += (uint) _words.SerializeSize () * Helpers._sizeOfChar;
header.cchSymbols = _symbols.StringSize ();
header.pszSymbols = ulOffset;
ulOffset += (uint) _symbols.SerializeSize () * Helpers._sizeOfChar;
header.cRules = _rules.Count;
header.pRules = ulOffset;
ulOffset += (uint) (_rules.Count * Marshal.SizeOf (typeof (CfgRule)));
header.cBasePath = cBasePath > 0 ? ulOffset : 0; //If there is no base path offset is set to zero
ulOffset += (uint) (((int) cBasePath * Helpers._sizeOfChar + 3) & ~3);
header.cArcs = cArcs;
header.pArcs = ulOffset;
ulOffset += (uint) (cArcs * Marshal.SizeOf (typeof (CfgArc)));
if (_fNeedWeightTable)
{
header.pWeights = ulOffset;
ulOffset += (uint) (cArcs * Marshal.SizeOf (typeof (float)));
pWeights = new float [cArcs];
pWeights [0] = 0.0f;
}
else
{
header.pWeights = 0;
ulOffset += 0;
}
if (_rootRule != null)
{
//We have a root rule
header.ulRootRuleIndex = (uint) _rootRule._iSerialize;
}
else
{
//-1 means there is no root rule
header.ulRootRuleIndex = 0xFFFFFFFF;
}
header.GrammarOptions = _grammarOptions | ((_alphabet == AlphabetType.Sapi) ? 0 : GrammarOptions.IpaPhoneme);
#if !NO_STG
header.GrammarOptions |= _scriptRefs.Count > 0 ? GrammarOptions.STG | GrammarOptions.KeyValuePairSrgs : 0;
#endif
header.GrammarMode = (uint) _grammarMode;
header.cTags = cSemanticTags;
header.tags = ulOffset;
ulOffset += (uint) (cSemanticTags * Marshal.SizeOf (typeof (CfgSemanticTag)));
#if !NO_STG
header.cScripts = _scriptRefs.Count;
header.pScripts = header.cScripts > 0 ? ulOffset : 0;
ulOffset += (uint) (_scriptRefs.Count * Marshal.SizeOf (typeof (CfgScriptRef)));
header.cIL = _il != null ? _il.Length : 0;
header.pIL = header.cIL > 0 ? ulOffset : 0;
ulOffset += (uint) (header.cIL * Marshal.SizeOf (typeof (byte)));
header.cPDB = _pdb != null ? _pdb.Length : 0;
header.pPDB = header.cPDB > 0 ? ulOffset : 0;
ulOffset += (uint) (header.cPDB * Marshal.SizeOf (typeof (byte)));
#endif
header.ulTotalSerializedSize = ulOffset;
return header;
}
private CfgGrammar.CfgHeader BuildRulesFromBinaryGrammar (CfgGrammar.CfgHeader header, State [] apStateTable, SortedDictionary ruleFirstArcs, int previousCfgLastRules)
{
for (int i = 0; i < header.rules.Length; i++)
{
// Check if the rule does not exist already
CfgRule cfgRule = header.rules [i];
int firstArc = (int) cfgRule.FirstArcIndex;
cfgRule._nameOffset = _symbols.OffsetFromId (_symbols.Find (header.pszSymbols.FromOffset (cfgRule._nameOffset)));
Rule rule = new Rule (this, _symbols.FromOffset (cfgRule._nameOffset), cfgRule, i + previousCfgLastRules, _grammarOptions & GrammarOptions.TagFormat, ref _cImportedRules);
rule._firstState = _states.CreateNewState (rule);
_rules.Add (rule);
// Add the rule to the list of firstArc/rule
if (firstArc > 0)
{
ruleFirstArcs.Add ((int) cfgRule.FirstArcIndex, rule);
}
rule._fStaticRule = (cfgRule.Dynamic) ? false : true;
rule._cfgRule.DirtyRule = false;
// by default loaded static rules have an exist
rule._fHasExitPath = (rule._fStaticRule) ? true : false;
// or they wouldn't be there in the first place
if (firstArc != 0)
{
System.Diagnostics.Debug.Assert (apStateTable [firstArc] == null);
rule._firstState.SerializeId = (int) cfgRule.FirstArcIndex;
apStateTable [firstArc] = rule._firstState;
}
if (rule._cfgRule.HasResources)
{
throw new NotImplementedException ();
}
if (header.ulRootRuleIndex == i)
{
_rootRule = rule;
}
// Add rule to RuleListByName and RuleListByID hash tables.
if (rule._cfgRule._nameOffset != 0)
{
// Look for the rule in the original CFG and map it in the combined string blobs
_nameOffsetRules.Add (rule._cfgRule._nameOffset, rule);
}
}
return header;
}
#endif
private Rule CloneState (State srcToState, List CloneStack, Dictionary srcToDestHash)
{
bool newRule = false;
int posDynamic = srcToState.Rule.Name.IndexOf ("URL:DYNAMIC#", StringComparison.Ordinal);
string ruleName = posDynamic != 0 ? srcToState.Rule.Name : srcToState.Rule.Name.Substring (12);
Rule dstRule = FindInRules (ruleName);
// Clone this rule into this GrammarBuilder if it does not exist yet
if (dstRule == null)
{
dstRule = srcToState.Rule.Clone (_symbols, ruleName);
_rules.Add (dstRule);
newRule = true;
}
// Should not exist yet
System.Diagnostics.Debug.Assert (!srcToDestHash.ContainsKey (srcToState));
// push all the states for that rule
State newState = CreateNewState (dstRule);
srcToDestHash.Add (srcToState, newState);
CloneStack.Add (srcToState);
if (newRule)
{
dstRule._firstState = newState;
}
return dstRule;
}
private Rule FindInRules (string ruleName)
{
foreach (Rule rule in _rules)
{
if (rule.Name == ruleName)
{
return rule;
}
}
return null;
}
private static void LogError (string rule, SRID srid, params object [] args)
{
string sError = SR.Get (srid, args);
throw new FormatException (string.Format (CultureInfo.InvariantCulture, "Rule=\"{0}\" - ", rule) + sError);
}
///
/// Connect arc to the state graph.
///
///
#if DEBUG
private
#else
private static
#endif
void AddArc (Arc arc)
{
#if DEBUG
arc.Backend = this;
#endif
}
///
///
///
///
private void ValidateAndTagRules ()
{
//CfgGrammar.TraceInformation ("BackEnd::ValidateAndTagRules");
//
bool fAtLeastOneRule = false;
int ulIndex = 0;
foreach (Rule rule in _rules)
{
// set _fHasExitPath = true for empty dynamic grammars and imported rules
// Clear this for the next loop through the rules....
rule._fHasExitPath |= (rule._cfgRule.Dynamic | rule._cfgRule.Import) ? true : false;
rule._iSerialize = ulIndex++;
fAtLeastOneRule |= (rule._cfgRule.Dynamic || rule._cfgRule.TopLevel || rule._cfgRule.Export);
rule.Validate ();
}
#if DEBUG
//
// Now make sure that all rules have an exit path.
//
foreach (Rule rule in _rules)
{
_ulRecursiveDepth = 0;
//The following function will use recursive function that might change _ulRecursiveDepth
rule.CheckForExitPath (ref _ulRecursiveDepth);
}
#endif
//
// Check each exported rule if it has a dynamic rule in its "scope"
//
foreach (Rule rule in _rules)
{
if (rule._cfgRule.Dynamic)
{
rule._cfgRule.HasDynamicRef = true;
_ulRecursiveDepth = 0;
rule.PopulateDynamicRef (ref _ulRecursiveDepth);
}
}
}
private void CheckLeftRecursion (List states)
{
bool fReachedEndState;
foreach (State state in states)
{
state.CheckLeftRecursion (out fReachedEndState);
}
}
///
///
///
///
///
///
private Arc AddSingleWordTransition (string s, float flWeight, int requiredConfidence)
{
//CfgGrammar.TraceInformation ("BackEnd::CGramComp::AddSingleWordTransition");
Arc arc = new Arc (s, null, _words, flWeight, requiredConfidence, null, MatchMode.AllWords, ref _fNeedWeightTable);
AddArc (arc);
return arc;
}
internal void AddState (State state)
{
_states.Add (state);
}
#if VSCOMPILE && DEBUG
///
internal void DumpStateTable (string sTitle)
{
List states = new List (_states);
DumpStateTable (sTitle, states.ToArray ());
}
internal void DumpStateTable (string sTitle, State [] states)
{
CfgGrammar.TraceInformation2 (sTitle);
int iHandle2 = 0;
for (int iState = 0; iState < states.Length; iState++)
{
State state = states [iState];
if (state == null)
{
continue;
}
//string s = state.OutArcs.Count > 0 ? state.OutArcs.First.WordId > 0 ? _words [state.OutArcs.First.WordId] : string.Empty : string.Empty;
string s = _symbols.FromOffset (state.Rule._cfgRule._nameOffset);
CfgGrammar.TraceInformation3 (string.Format (CultureInfo.InvariantCulture, "{0}: {1} {2} {3} '", iHandle2, state.Id, state.SerializeId, s));
foreach (Arc arc2 in state.OutArcs)
{
int iWord = arc2.WordId;
string sWord = arc2.RuleRef != null ? _symbols.FromOffset (arc2.RuleRef._cfgRule._nameOffset) : iWord > 0 ? _words [iWord] : string.Empty;
//CfgGrammar.TraceInformation3 (string.Format (CultureInfo.InvariantCulture, "{0}{1} [{2}]", (fFirst ? string.Empty : ", "), sWord, arc2.Id));
//if (arc2._tag != null)
//{
// CfgGrammar.TraceInformation3 (string.Format (CultureInfo.InvariantCulture, "({0}, {1}, {2})", _symbols.FromOffset (arc2._tag._cfgTag._valueOffset), arc2._tag._startArc.Id, arc2._tag._endArc.Id));
//}
}
CfgGrammar.TraceInformation2 ("'");
}
}
internal void DumpStateMachine (TextWriter tw)
{
tw.WriteLine ("Word Blobs");
for (int i = 1; i < _words.Count; i++)
{
tw.WriteLine (" \"" + _words [i] + "\"");
}
tw.WriteLine ("\nSymbols Blobs");
for (int i = 1; i < _symbols.Count; i++)
{
tw.WriteLine (" \"" + _symbols [i] + "\"");
}
tw.WriteLine ("\nRules");
foreach (Rule rule in _rules)
{
tw.WriteLine (string.Format (CultureInfo.InvariantCulture, " \"{0}\" id: {1} flags: {2}", rule.Name, rule._cfgRule._id, rule._cfgRule._flag.ToString ("x", CultureInfo.InvariantCulture)));
tw.WriteLine (string.Format (CultureInfo.InvariantCulture, " States: {0}", rule._cStates));
}
tw.WriteLine (string.Format (CultureInfo.InvariantCulture, "\nStates:\n Count: {0}", _states.Count));
foreach (State state in _states)
{
tw.WriteLine (string.Format (CultureInfo.InvariantCulture, " \"{0}\"", state.Rule.Name));
}
}
//GrammarOptimization
///
/// Dump grammar statistics to debug window. (Debug only)
///
///
void DumpGrammarStatistics (string title)
{
int iNumStates = 0;
int iNumArcs = 0;
int iNumEpsilonArcs = 0;
int iMaxBranch = 0;
int iNumProperties = 0;
foreach (State state in _states)
{
iNumStates++;
int cArcs = 0;
foreach (Arc arc in state.OutArcs)
{
cArcs++;
if (arc.IsEpsilonTransition)
{
iNumEpsilonArcs++;
}
//if (arc._tag != null)
//{
// iNumProperties++;
//}
}
if (iMaxBranch < cArcs)
iMaxBranch = cArcs;
iNumArcs += cArcs;
}
Console.WriteLine (title);
Console.WriteLine (string.Format (CultureInfo.InvariantCulture, "{0}\n NumStates = {0}\n NumArcs = {1}\n NumEpsilons = {2}\n", iNumStates, iNumArcs, iNumEpsilonArcs));
Console.WriteLine (string.Format (CultureInfo.InvariantCulture, " MaxBranch = {0}\n" + " NumProperties = {1}\n", iMaxBranch, iNumProperties));
}
#endif
#endregion
//*******************************************************************
//
// Internal Properties
//
//*******************************************************************
#region Internal Properties
internal int LangId
{
get
{
return _langId;
}
set
{
_langId = value;
}
}
internal GrammarOptions GrammarOptions
{
get
{
return _grammarOptions;
}
set
{
_grammarOptions = value;
}
}
internal GrammarType GrammarMode
{
set
{
_grammarMode = value;
}
}
internal AlphabetType Alphabet
{
set
{
_alphabet = value;
}
get
{
return _alphabet;
}
}
internal Collection GlobalTags
{
get
{
return _globalTags;
}
set
{
_globalTags = value;
}
}
#if !NO_STG
internal Collection ScriptRefs
{
set
{
_scriptRefs = value;
}
}
internal byte [] IL
{
set
{
_il = value;
}
}
internal byte [] PDB
{
set
{
_pdb = value;
}
}
#endif
#endregion
//*******************************************************************
//
// Private Fields
//
//********************************************************************
#region Private Fields
private int _langId = CultureInfo.CurrentUICulture.LCID;
private StringBlob _words;
private StringBlob _symbols;
//private int _cResources;
private Guid _guid;
private bool _fNeedWeightTable;
private Graph _states = new Graph ();
private List _rules = new List ();
private int _ruleIndex;
private Dictionary _nameOffsetRules = new Dictionary ();
private Rule _rootRule;
#if !SPEECHSERVER
private GrammarOptions _grammarOptions = GrammarOptions.KeyValuePairs;
#else
private GrammarOptions _grammarOptions = GrammarOptions.W3cV1;
#endif
// It is used sequentially. So there is no thread issue
private int _ulRecursiveDepth;
// Path from which relative grammar imports are calculated. As specified by xml:base
private string _basePath;
// Collection of all SemanticTags in the grammar (sorted by StartArc)
private List _tags = new List ();
// Voice or DTMF
private GrammarType _grammarMode = GrammarType.VoiceGrammar;
// Pron information is either IPA or SAPI
private AlphabetType _alphabet = AlphabetType.Sapi;
// Global value for the semantic interpretation tags
private Collection _globalTags = new Collection ();
//
private static byte [] _abZero3 = new byte [] { 0, 0, 0 };
private static char [] _achZero = new char [] { '\0' };
//
private const uint SPGF_RESET_DIRTY_FLAG = 0x80000000;
private int _cImportedRules;
#if !NO_STG
// List of cd /reference Rule->rule 'on'method-> .Net method
private Collection _scriptRefs = new Collection ();
// Grammar code assembly
private byte [] _il;
// Grammar debug symbols
private byte [] _pdb;
#endif
private bool _fLoadedFromBinary;
#endregion
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Description:
// CFG Grammar backend
//
// History:
// 5/1/2004 jeanfp Created from the Sapi Managed code
//-----------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;
using System.IO;
using System.Speech.Internal.SrgsParser;
namespace System.Speech.Internal.SrgsCompiler
{
///
/// Summary description for GrammarBackEnd.
///
internal sealed partial class Backend
{
//*******************************************************************
//
// Constructors
//
//*******************************************************************
#region Constructors
internal Backend ()
{
_words = new StringBlob ();
_symbols = new StringBlob ();
}
internal Backend (StreamMarshaler streamHelper)
{
InitFromBinaryGrammar (streamHelper);
}
#endregion
//********************************************************************
//
// Internal Methods
//
//*******************************************************************
#region Internal Methods
///
/// Optimizes the grammar network by removing the epsilon states and merging
/// duplicate transitions. See GrammarOptimization.doc for details.
///
internal void Optimize ()
{
//DumpGrammarStatistics ("GrammarOptimization: Pre optimize");
_states.Optimize ();
//DumpGrammarStatistics ("GrammarOptimization: Post optimize");
// Most likely, there will be an arc with a weight != 1. So we need a weight table.
_fNeedWeightTable = true;
}
///
/// Performs consistency checks of the grammar structure, creates the
/// serialized format and either saves it to the stream provided by SetSaveOptions,
/// or reloads it into the CFG engine.
///
///
internal void Commit (StreamMarshaler streamBuffer)
{
// For debugging purpose, assert if the position is not it is assumed it should be
// Keep the start position in the stream
long startStreamPostion = streamBuffer.Stream.Position;
// put all states State into a sorted array by rule parent index and serialized index
List sortedStates = new List (_states);
// Release the memory for the original list of states
_states = null;
sortedStates.Sort ();
// Validate the grammar
ValidateAndTagRules ();
CheckLeftRecursion (sortedStates);
// Include null terminator
int cBasePath = _basePath != null ? _basePath.Length + 1 : 0;
float [] pWeights;
int cArcs;
// Add the top level semantic interpreatation tag
// This should be set as the first symbol in the symbol string blog since it must hold on a 16 bits value.
int semanticInterpretationGlobals = 0;
if (_globalTags.Count > 0)
{
StringBuilder sb = new StringBuilder ();
foreach (string s in _globalTags)
{
sb.Append (s);
}
_symbols.Add (sb.ToString (), out semanticInterpretationGlobals);
semanticInterpretationGlobals = _symbols.OffsetFromId (semanticInterpretationGlobals);
if (semanticInterpretationGlobals > UInt16.MaxValue)
{
throw new OverflowException (SR.Get (SRID.TooManyRulesWithSemanticsGlobals));
}
}
#if !NO_STG
// Write the method names as symbols
foreach (ScriptRef script in _scriptRefs)
{
_symbols.Add (script._sMethod, out script._idSymbol);
}
#endif
// get the header
CfgGrammar.CfgSerializedHeader header = BuildHeader (sortedStates, cBasePath, unchecked ((UInt16) semanticInterpretationGlobals), out cArcs, out pWeights);
streamBuffer.WriteStream (header);
//
// For the string blobs, we must explicitly report I/O error since the blobs don't
// use the error log facility.
//
System.Diagnostics.Debug.Assert (streamBuffer.Stream.Position - startStreamPostion == header.pszWords);
streamBuffer.WriteArrayChar (_words.SerializeData (), _words.SerializeSize ());
System.Diagnostics.Debug.Assert (streamBuffer.Stream.Position - startStreamPostion == header.pszSymbols);
streamBuffer.WriteArrayChar (_symbols.SerializeData (), _symbols.SerializeSize ());
System.Diagnostics.Debug.Assert (streamBuffer.Stream.Position - startStreamPostion == header.pRules);
foreach (Rule rule in _rules)
{
rule.Serialize (streamBuffer);
}
if (cBasePath > 0)
{
streamBuffer.WriteArrayChar (_basePath.ToCharArray (), _basePath.Length);
// Add a zero to be compatible with SAPI 5
System.Diagnostics.Debug.Assert (_basePath.Length + 1 == cBasePath);
streamBuffer.WriteArrayChar (_achZero, 1);
// Zero-pad to align following structures
streamBuffer.WriteArray (_abZero3, cBasePath * Helpers._sizeOfChar & 3);
}
//
// Write a dummy 0 index state entry
//
CfgArc dummyArc = new CfgArc ();
System.Diagnostics.Debug.Assert (streamBuffer.Stream.Position - startStreamPostion == header.pArcs);
streamBuffer.WriteStream (dummyArc);
int ulWeightOffset = 1;
uint arcOffset = 1;
bool semanticInterpretation = (GrammarOptions & GrammarOptions.MssV1) == GrammarOptions.MssV1;
foreach (State state in sortedStates)
{
state.SerializeStateEntries (streamBuffer, semanticInterpretation, pWeights, ref arcOffset, ref ulWeightOffset);
}
System.Diagnostics.Debug.Assert (streamBuffer.Stream.Position - startStreamPostion == header.pWeights);
if (_fNeedWeightTable)
{
streamBuffer.WriteArray (pWeights, cArcs);
}
System.Diagnostics.Debug.Assert (streamBuffer.Stream.Position - startStreamPostion == header.tags);
if (!semanticInterpretation)
{
foreach (State state in sortedStates)
{
state.SetEndArcIndexForTags ();
}
}
// Remove the orphaned arcs
// This could happen in the case of a -
for (int i = _tags.Count - 1; i >= 0; i--)
{
// When arc are created the index is set to zero. This value changes during serialization
// if an arc references it
if (_tags [i]._cfgTag.ArcIndex == 0)
{
_tags.RemoveAt (i);
}
}
// Sort the _tags array by ArcIndex
_tags.Sort ();
// Write the _tags array
foreach (Tag tag in _tags)
{
tag.Serialize (streamBuffer);
}
#if !NO_STG
// Write the script references and the IL write after the header so getting it for the grammar
// Does not require a seek to the end of the file
System.Diagnostics.Debug.Assert (header.pScripts == 0 || streamBuffer.Stream.Position - startStreamPostion == header.pScripts);
foreach (ScriptRef script in _scriptRefs)
{
script.Serialize (_symbols, streamBuffer);
}
// Write the assembly bits
System.Diagnostics.Debug.Assert (header.pIL == 0 || streamBuffer.Stream.Position - startStreamPostion == header.pIL);
if (_il != null && _il.Length > 0)
{
streamBuffer.Stream.Write (_il, 0, _il.Length);
}
System.Diagnostics.Debug.Assert (header.pPDB == 0 || streamBuffer.Stream.Position - startStreamPostion == header.pPDB);
if (_pdb != null && _pdb.Length > 0)
{
streamBuffer.Stream.Write (_pdb, 0, _pdb.Length);
}
#endif
}
///
/// Description:
/// Combine the current data in a grammar with one comming from a CFG
///
///
///
///
internal static Backend CombineGrammar (string ruleName, Backend org, Backend extra)
{
//
Backend be = new Backend ();
be._fLoadedFromBinary = true;
be._fNeedWeightTable = org._fNeedWeightTable;
be._grammarMode = org._grammarMode;
be._grammarOptions = org._grammarOptions;
// Hash source state to destination state
Dictionary srcToDestHash = new Dictionary ();
// Find the rule
foreach (Rule orgRule in org._rules)
{
if (orgRule.Name == ruleName)
{
be.CloneSubGraph (orgRule, org, extra, srcToDestHash, true);
}
}
return be;
}
internal State CreateNewState (Rule rule)
{
return _states.CreateNewState (rule);
}
internal void DeleteState (State state)
{
_states.DeleteState (state);
}
internal void MoveInputTransitionsAndDeleteState (State from, State to)
{
_states.MoveInputTransitionsAndDeleteState (from, to);
}
internal void MoveOutputTransitionsAndDeleteState (State from, State to)
{
_states.MoveOutputTransitionsAndDeleteState (from, to);
}
///
/// Tries to find the rule's initial state handle. If both a name and an id
/// are provided, then both have to match in order for this call to succeed.
/// If the rule doesn't already exist then we define it if fCreateIfNotExists,
/// otherwise we return an error ().
///
/// - pszRuleName name of rule to find/define (null: don't care)
/// - ruleId id of rule to find/define (0: don't care)
/// - dwAttribute rule attribute for defining the rule
/// - fCreateIfNotExists creates the rule using name, id, and attributes
/// in case the rule doesn't already exist
///
/// throws:
/// S_OK, E_INVALIDARG, E_OUTOFMEMORY
/// SPERR_RULE_NOT_FOUND -- no rule found and we don't create a new one
/// SPERR_RULE_NAME_ID_CONFLICT -- rule name and id don't match
///
///
///
///
internal Rule CreateRule (string name, SPCFGRULEATTRIBUTES attributes)
{
//CfgGrammar.TraceInformation ("BackEnd::CreateRule");
SPCFGRULEATTRIBUTES allFlags = SPCFGRULEATTRIBUTES.SPRAF_TopLevel | SPCFGRULEATTRIBUTES.SPRAF_Active | SPCFGRULEATTRIBUTES.SPRAF_Export | SPCFGRULEATTRIBUTES.SPRAF_Import | SPCFGRULEATTRIBUTES.SPRAF_Interpreter | SPCFGRULEATTRIBUTES.SPRAF_Dynamic | SPCFGRULEATTRIBUTES.SPRAF_Root;
if (attributes != 0 && ((attributes & ~allFlags) != 0 || ((attributes & SPCFGRULEATTRIBUTES.SPRAF_Import) != 0 && (attributes & SPCFGRULEATTRIBUTES.SPRAF_Export) != 0)))
{
throw new ArgumentException ("attributes");
}
// PS: 52277 - SAPI does not properly handle a rule marked as Import and TopLevel/Active/Root.
// - To maintain maximal backwards compatibility, if a rule is marked as Import, we will unmark TopLevel/Active/Root.
// - This changes the behavior when application tries to activate this rule. However, given that it is already
// broken/fragile, we believe it is better to change the behavior.
if ((attributes & SPCFGRULEATTRIBUTES.SPRAF_Import) != 0 && ((attributes & SPCFGRULEATTRIBUTES.SPRAF_TopLevel) != 0 || (attributes & SPCFGRULEATTRIBUTES.SPRAF_Active) != 0 || (attributes & SPCFGRULEATTRIBUTES.SPRAF_Root) != 0))
{
//CfgGrammar.TraceInformation ("Warning: A rule cannot be marked as both Import and TopLevel/Active/Root.\n" + " TopLevel/Active/Root have been disabled.");
attributes &= ~(SPCFGRULEATTRIBUTES.SPRAF_TopLevel | SPCFGRULEATTRIBUTES.SPRAF_Active | SPCFGRULEATTRIBUTES.SPRAF_Root);
}
if ((attributes & SPCFGRULEATTRIBUTES.SPRAF_Import) != 0 && (name [0] == '\0'))
{
LogError (name, SRID.InvalidImport);
}
if (_fLoadedFromBinary)
{
// Scan all non-dynamic names and prevent a duplicate...
foreach (Rule r in _rules)
{
string wpszName = _symbols [r._cfgRule._nameOffset];
if (!r._cfgRule.Dynamic && name == wpszName)
{
LogError (name, SRID.DuplicatedRuleName);
}
}
}
int idString;
int cImportedRule = 0;
Rule rule = new Rule (this, name, _symbols.Add (name, out idString), attributes, _ruleIndex, 0, _grammarOptions & GrammarOptions.TagFormat, ref cImportedRule);
rule._iSerialize2 = _ruleIndex++;
if ((attributes & SPCFGRULEATTRIBUTES.SPRAF_Root) != 0)
{
if (_rootRule != null)
{
//We already have a root rule, return error code.
LogError (name, SRID.RootRuleAlreadyDefined);
}
else
{
_rootRule = rule;
}
}
// Add rule to RuleListByName and RuleListByID hash tables.
if (rule._cfgRule._nameOffset != 0)
{
_nameOffsetRules.Add (rule._cfgRule._nameOffset, rule);
}
//
// It is important to insert this at the tail for dynamic rules to
// retain their slot number.
//
_rules.Add (rule);
_rules.Sort ();
return rule;
}
///
/// Internal method for finding rule in rule list
///
///
///
internal Rule FindRule (string sRule)
{
//CfgGrammar.TraceInformation ("BackEnd::FindRule");
Rule rule = null;
if (_nameOffsetRules.Count > 0)
{
// Find rule corresponding to name symbol offset corresponding to the RuleName
int iWord = _symbols.Find (sRule);
if (iWord > 0)
{
int dwSymbolOffset = _symbols.OffsetFromId (iWord);
System.Diagnostics.Debug.Assert (dwSymbolOffset == 0 || _symbols [iWord] == sRule);
rule = dwSymbolOffset > 0 && _nameOffsetRules.ContainsKey (dwSymbolOffset) ? _nameOffsetRules [dwSymbolOffset] : null;
}
}
if (rule != null)
{
string sRuleFound = rule.Name;
// at least one of the 2 arguments matched
// names either match or they are both null!
if (!((string.IsNullOrEmpty (sRule) || (!string.IsNullOrEmpty (sRule) && !string.IsNullOrEmpty (sRuleFound) && sRuleFound == sRule))))
{
LogError (sRule, SRID.RuleNameIdConflict);
}
}
return rule != null ? rule : null;
}
///
/// Adds a word transition from hFromState to hToState. If hToState == null
/// then the arc will be to the (implicit) terminal state. If psz == null then
/// we add an epsilon transition. Properties are pushed back to the
/// first un-ambiguous arc in case we can share a common initial state path.
/// The weight will be placed on the first arc (if there exists an arc with
/// the same word but different weight we will create a new arc).
///
internal Arc WordTransition (string sWord, float flWeight, int requiredConfidence)
{
return CreateTransition (sWord, flWeight, requiredConfidence);
}
internal Arc SubsetTransition (string text, MatchMode matchMode)
{
// Performs white space normalization in place
text = NormalizeTokenWhiteSpace (text);
return new Arc (text, null, _words, 1.0f, CfgGrammar.SP_NORMAL_CONFIDENCE, null, matchMode, ref _fNeedWeightTable);
}
///
/// Adds a rule (reference) transition from hFromState to hToState.
/// hRule can also be one of these special transition handles:
/// SPRULETRANS_WILDCARD : "WILDCARD" transition
/// SPRULETRANS_DICTATION : single word from dictation
/// SPRULETRANS_TEXTBUFFER : "TEXTBUFFER" transition
///
/// must be initial state of rule
/// Rule calling the ruleref
///
internal Arc RuleTransition (Rule rule, Rule parentRule, float flWeight)
{
//CfgGrammar.TraceInformation ("BackEnd::AddRuleTransition");
Rule ruleToTransitionTo = null;
if (flWeight < 0.0f)
{
XmlParser.ThrowSrgsException (SRID.UnsupportedFormat);
}
Rule specialRuleTrans = null;
if (rule == CfgGrammar.SPRULETRANS_WILDCARD || rule == CfgGrammar.SPRULETRANS_DICTATION || rule == CfgGrammar.SPRULETRANS_TEXTBUFFER)
{
specialRuleTrans = rule;
}
else
{
ruleToTransitionTo = rule;
}
bool fNeedWeightTable = false;
Arc arc = new Arc (null, ruleToTransitionTo, _words, flWeight, '\0', specialRuleTrans, MatchMode.AllWords, ref fNeedWeightTable);
AddArc (arc);
if (ruleToTransitionTo != null && parentRule != null)
{
ruleToTransitionTo._listRules.Insert (0, parentRule);
}
return arc;
}
///
/// Adds a word transition from hFromState to hToState. If hToState == null
/// then the arc will be to the (implicit) terminal state. If psz == null then
/// we add an epsilon transition. Properties are pushed back to the
/// first un-ambiguous arc in case we can share a common initial state path.
/// The weight will be placed on the first arc (if there exists an arc with
/// the same word but different weight we will create a new arc).
///
///
///
internal Arc EpsilonTransition (float flWeight)
{
return CreateTransition (null, flWeight, CfgGrammar.SP_NORMAL_CONFIDENCE);
}
internal void AddSemanticInterpretationTag (Arc arc, CfgGrammar.CfgProperty propertyInfo)
{
//CfgGrammar.TraceInformation ("BackEnd::AddSemanticTag");
Tag tag = new Tag (this, propertyInfo);
_tags.Add (tag);
arc.AddStartTag (tag);
arc.AddEndTag (tag);
}
internal void AddPropertyTag (Arc start, Arc end, CfgGrammar.CfgProperty propertyInfo)
{
//CfgGrammar.TraceInformation ("BackEnd::AddSemanticTag");
Tag tag = new Tag (this, propertyInfo);
_tags.Add (tag);
start.AddStartTag (tag);
end.AddEndTag (tag);
}
///
/// Traverse the graph starting from SrcStartState, cloning each state as we go along,
/// cloning each transition except ones originating from SrcEndState, and return
/// the cloned state corresponding to SrcEndState.
///
///
///
///
///
internal State CloneSubGraph (State srcFromState, State srcEndState, State destFromState)
{
Dictionary SrcToDestHash = new Dictionary (); // Hash source state to destination state
Stack CloneStack = new Stack (); // States to process
Dictionary tags = new Dictionary ();
// Add initial state to CloneStack and SrcToDestHash.
SrcToDestHash.Add (srcFromState, destFromState);
CloneStack.Push (srcFromState);
// While there are still states on the CloneStack (ToDo collection)
while (CloneStack.Count > 0)
{
srcFromState = CloneStack.Pop ();
destFromState = SrcToDestHash [srcFromState];
System.Diagnostics.Debug.Assert (destFromState != null);
// For each transition from srcFromState (except SrcEndState)
foreach (Arc arc in srcFromState.OutArcs)
{
// - Lookup the DestToState corresponding to SrcToState
State srcToState = arc.End;
State destToState = null;
if (srcToState != null)
{
// - If not found, clone a new DestToState, add SrcToState.DestToState to SrcToDestHash, and add SrcToState to CloneStack.
if (!SrcToDestHash.ContainsKey (srcToState))
{
destToState = CreateNewState (srcToState.Rule);
SrcToDestHash.Add (srcToState, destToState);
CloneStack.Push (srcToState);
}
else
{
destToState = SrcToDestHash [srcToState]; ;
}
}
// - Clone the transition from SrcFromState.SrcToState at DestFromState.DestToState
// -- Clone Arc
Arc newArc = new Arc (arc, destFromState, destToState);
AddArc (newArc);
// -- Clone SemanticTag
newArc.CloneTags (arc, _tags, tags, null);
// -- Add Arc
newArc.ConnectStates ();
}
}
System.Diagnostics.Debug.Assert (tags.Count == 0);
return SrcToDestHash [srcEndState];
}
///
/// Traverse the graph starting from SrcStartState, cloning each state as we go along,
/// cloning each transition except ones originating from SrcEndState, and return
/// the cloned state corresponding to SrcEndState.
///
///
///
///
///
///
///
internal void CloneSubGraph (Rule rule, Backend org, Backend extra, Dictionary srcToDestHash, bool fromOrg)
{
Backend beSrc = fromOrg ? org : extra;
List CloneStack = new List (); // States to process
Dictionary tags = new Dictionary ();
// Push all the state for the top level rule
CloneState (rule._firstState, CloneStack, srcToDestHash);
// While there are still states on the CloneStack (ToDo collection)
while (CloneStack.Count > 0)
{
State srcFromState = CloneStack [0];
CloneStack.RemoveAt (0);
State destFromState = srcToDestHash [srcFromState];
// For each transition from srcFromState (except SrcEndState)
foreach (Arc arc in srcFromState.OutArcs)
{
// - Lookup the DestToState corresponding to SrcToState
State srcToState = arc.End;
State destToState = null;
if (srcToState != null)
{
if (!srcToDestHash.ContainsKey (srcToState))
{
// - If not found, then it is a new rule, just clown it.
CloneState (srcToState, CloneStack, srcToDestHash);
}
destToState = srcToDestHash [srcToState];
}
// - Clone the transition from SrcFromState.SrcToState at DestFromState.DestToState
// -- Clone Arc
int newWordId = arc.WordId;
if (beSrc != null && arc.WordId > 0)
{
_words.Add (beSrc.Words [arc.WordId], out newWordId);
}
Arc newArc = new Arc (arc, destFromState, destToState, newWordId);
// -- Clone SemanticTag
newArc.CloneTags (arc, _tags, tags, this);
// For rule ref push the first state of the ruleref
if (arc.RuleRef != null)
{
string ruleName;
// Check for DYNAMIC grammars
if (arc.RuleRef.Name.IndexOf ("URL:DYNAMIC#", StringComparison.Ordinal) == 0)
{
ruleName = arc.RuleRef.Name.Substring (12);
if (fromOrg == true && FindInRules (ruleName) == null)
{
Rule ruleExtra = extra.FindInRules (ruleName);
if (ruleExtra == null)
{
XmlParser.ThrowSrgsException (SRID.DynamicRuleNotFound, ruleName);
}
CloneSubGraph (ruleExtra, org, extra, srcToDestHash, false);
}
}
else if (arc.RuleRef.Name.IndexOf ("URL:STATIC#", StringComparison.Ordinal) == 0)
{
ruleName = arc.RuleRef.Name.Substring (11);
if (fromOrg == false && FindInRules (ruleName) == null)
{
Rule ruleOrg = org.FindInRules (ruleName);
if (ruleOrg == null)
{
XmlParser.ThrowSrgsException (SRID.DynamicRuleNotFound, ruleName);
}
CloneSubGraph (ruleOrg, org, extra, srcToDestHash, true);
}
}
else
{
ruleName = arc.RuleRef.Name;
Rule ruleExtra = org.FindInRules (ruleName);
if (fromOrg == false)
{
CloneSubGraph (arc.RuleRef, org, extra, srcToDestHash, true);
}
}
Rule refRule = FindInRules (ruleName);
if (refRule == null)
{
refRule = CloneState (arc.RuleRef._firstState, CloneStack, srcToDestHash);
}
newArc.RuleRef = refRule;
}
// -- Add Arc
newArc.ConnectStates ();
}
}
System.Diagnostics.Debug.Assert (tags.Count == 0);
}
///
/// Delete disconnected subgraph starting at hState.
/// Traverse the graph starting from SrcStartState, and delete each state as we go along.
///
///
internal void DeleteSubGraph (State state)
{
// Add initial state to DeleteStack.
Stack stateToProcess = new Stack (); // States to delete
Collection arcsToDelete = new Collection ();
Collection statesToDelete = new Collection ();
stateToProcess.Push (state);
// While there are still states on the listDelete (ToDo collection)
while (stateToProcess.Count > 0)
{
// For each transition from state,
state = stateToProcess.Pop ();
statesToDelete.Add (state);
arcsToDelete.Clear ();
// Accumulate the arcs to delete and add new states to the stack of states to process
foreach (Arc arc in state.OutArcs)
{
// Add EndState to listDelete, if unique
State endState = arc.End;
// Add this state to the list of states to delete
if (endState != null && !stateToProcess.Contains (endState) && !statesToDelete.Contains (endState))
{
stateToProcess.Push (endState);
}
arcsToDelete.Add (arc);
}
// Clear up the arcs
foreach (Arc arc in arcsToDelete)
{
arc.Start = arc.End = null;
}
}
foreach (State stateToDelete in statesToDelete)
{
// Delete state and remove from listDelete
System.Diagnostics.Debug.Assert (stateToDelete != null);
System.Diagnostics.Debug.Assert (stateToDelete.InArcs.IsEmpty);
System.Diagnostics.Debug.Assert (stateToDelete.OutArcs.IsEmpty);
DeleteState (stateToDelete);
}
}
///
/// Modify the placeholder rule attributes after it has been created.
/// This is only safe to use in the context of SRGSGrammarCompiler.
///
///
///
///
internal void SetRuleAttributes (Rule rule, SPCFGRULEATTRIBUTES dwAttributes)
{
// Check if this is the Root rule
if ((dwAttributes & SPCFGRULEATTRIBUTES.SPRAF_Root) != 0)
{
if (_rootRule != null)
{
//We already have a root rule, return error code.
XmlParser.ThrowSrgsException (SRID.RootRuleAlreadyDefined);
}
else
{
_rootRule = rule;
}
}
rule._cfgRule.TopLevel = ((dwAttributes & SPCFGRULEATTRIBUTES.SPRAF_TopLevel) != 0);
rule._cfgRule.DefaultActive = ((dwAttributes & SPCFGRULEATTRIBUTES.SPRAF_Active) != 0);
rule._cfgRule.PropRule = ((dwAttributes & SPCFGRULEATTRIBUTES.SPRAF_Interpreter) != 0);
rule._cfgRule.Export = ((dwAttributes & SPCFGRULEATTRIBUTES.SPRAF_Export) != 0);
rule._cfgRule.Dynamic = ((dwAttributes & SPCFGRULEATTRIBUTES.SPRAF_Dynamic) != 0);
rule._cfgRule.Import = ((dwAttributes & SPCFGRULEATTRIBUTES.SPRAF_Import) != 0);
}
///
/// Set the path from which relative grammar imports are calculated. As specified by xml:base / meta base
/// Null or empty string will clear any existing base path.
///
///
internal void SetBasePath (string sBasePath)
{
if (!string.IsNullOrEmpty (sBasePath))
{
// Validate base path.
Uri uri = new Uri (sBasePath, UriKind.RelativeOrAbsolute);
//Url Canonicalized
_basePath = uri.ToString ();
}
else
{
_basePath = null;
}
}
///
/// Perform white space normalization in place.
/// - Trim leading/trailing white spaces.
/// - Collapse white space sequences to a single ' '.
///
///
///
internal static string NormalizeTokenWhiteSpace (string sToken)
{
System.Diagnostics.Debug.Assert (!string.IsNullOrEmpty (sToken));
// Trim leading and ending white spaces
sToken = sToken.Trim (Helpers._achTrimChars);
// Easy out if there are no consecutive double white spaces
if (sToken.IndexOf (" ", StringComparison.Ordinal) == -1)
{
return sToken;
}
// Normalize internal spaces
char [] achSrc = sToken.ToCharArray ();
int iDest = 0;
for (int i = 0; i < achSrc.Length; )
{
// Collapsed multiple white spaces into ' '
if (achSrc [i] == ' ')
{
do
{
i++;
} while (achSrc [i] == ' ');
achSrc [iDest++] = ' ';
continue;
}
// Copy the non-white space character
achSrc [iDest++] = achSrc [i++];
}
return new string (achSrc, 0, iDest);
}
#endregion
//********************************************************************
//
// Internal Property
//
//********************************************************************
#region Internal Property
internal StringBlob Words
{
get
{
return this._words;
}
}
internal StringBlob Symbols
{
get
{
return this._symbols;
}
}
#endregion
//*******************************************************************
//
// Private Methods
//
//********************************************************************
#region Private Methods
///
/// Description:
/// Load compiled grammar data. This overwrites any existing data in the grammar
/// We end up with containers of words, symbols, rules, arcs, states and state handles, etc.
///
///
#if true
internal void InitFromBinaryGrammar (StreamMarshaler streamHelper)
{
//CfgGrammar.TraceInformation ("BackEnd::InitFromBinaryGrammar");
CfgGrammar.CfgHeader header = CfgGrammar.ConvertCfgHeader (streamHelper);
_words = header.pszWords;
_symbols = header.pszSymbols;
_grammarOptions = header.GrammarOptions;
//
// Build up the internal representation
//
State [] apStateTable = new State [header.arcs.Length];
SortedDictionary ruleFirstArcs = new SortedDictionary ();
//
// Initialize the rules
//
int previousCfgLastRules = _rules.Count;
BuildRulesFromBinaryGrammar (header, apStateTable, ruleFirstArcs, previousCfgLastRules);
//
// Initialize the arcs
//
Arc [] apArcTable = new Arc [header.arcs.Length];
bool fLastArcNull = true;
CfgArc pLastArc = new CfgArc ();
State currentState = null;
IEnumerator> ieFirstArcs = ruleFirstArcs.GetEnumerator ();
// If no rules, then we have no arcs
if (ieFirstArcs.MoveNext ())
{
KeyValuePair kvFirstArc = ieFirstArcs.Current;
Rule ruleCur = kvFirstArc.Value;
// We repersist the static AND dynamic parts for now. This allows the grammar to be queried
// with the automation interfaces
for (int k = 1; k < header.arcs.Length; k++)
{
CfgArc arc = header.arcs [k];
// Reset the Transition index based on the compbined stringblobs
if (arc.RuleRef)
{
// for a ruleref offset the rule index
ruleCur._listRules.Add (_rules [(int) arc.TransitionIndex]);
}
if (kvFirstArc.Key == k)
{
// we are entering a new rule now
ruleCur = kvFirstArc.Value;
// Reset to zero once we have read the last rule.
if (ieFirstArcs.MoveNext ())
{
kvFirstArc = ieFirstArcs.Current;
}
}
// new currentState?
if (fLastArcNull || pLastArc.LastArc)
{
if (apStateTable [k] == null)
{
uint hNewState = CfgGrammar.NextHandle;
apStateTable [k] = new State (ruleCur, hNewState, k);
AddState (apStateTable [k]);
}
currentState = apStateTable [k];
}
//
// now get the arc
//
int iNextArc = (int) (arc.NextStartArcIndex);
Arc newArc;
State targetState = null;
if (currentState != null && iNextArc != 0)
{
if (apStateTable [iNextArc] == null)
{
uint hNewState = CfgGrammar.NextHandle;
apStateTable [iNextArc] = new State (ruleCur, hNewState, iNextArc);
AddState (apStateTable [iNextArc]);
}
targetState = apStateTable [iNextArc];
}
float flWeight = header.weights != null ? header.weights [k] : CfgGrammar.DEFAULT_WEIGHT;
// determine properties of the arc now ...
if (arc.RuleRef)
{
Rule ruleToTransitionTo = _rules [(int) arc.TransitionIndex];
newArc = new Arc (null, ruleToTransitionTo, _words, flWeight, CfgGrammar.SP_NORMAL_CONFIDENCE, null, MatchMode.AllWords, ref _fNeedWeightTable);
}
else
{
int transitionIndex = (int) arc.TransitionIndex;
int ulSpecialTransitionIndex = (int) ((transitionIndex == CfgGrammar.SPWILDCARDTRANSITION || transitionIndex == CfgGrammar.SPDICTATIONTRANSITION || transitionIndex == CfgGrammar.SPTEXTBUFFERTRANSITION) ? transitionIndex : 0);
newArc = new Arc ((ulSpecialTransitionIndex != 0) ? 0 : (int) arc.TransitionIndex, flWeight, arc.LowConfRequired ? CfgGrammar.SP_LOW_CONFIDENCE : arc.HighConfRequired ? CfgGrammar.SP_HIGH_CONFIDENCE : CfgGrammar.SP_NORMAL_CONFIDENCE, ulSpecialTransitionIndex, MatchMode.AllWords, ref _fNeedWeightTable);
}
newArc.Start = currentState;
newArc.End = targetState;
AddArc (newArc);
apArcTable [k] = newArc;
fLastArcNull = false;
pLastArc = arc;
}
}
// Initialize the Semantics tags
for (int k = 1, iCurTag = 0; k < header.arcs.Length; k++)
{
CfgArc arc = header.arcs [k];
if (arc.HasSemanticTag)
{
System.Diagnostics.Debug.Assert (header.tags [iCurTag].StartArcIndex == k);
while (iCurTag < header.tags.Length && header.tags [iCurTag].StartArcIndex == k)
{
// we should already point to the tag
CfgSemanticTag semTag = header.tags [iCurTag];
Tag tag = new Tag (this, semTag);
_tags.Add (tag);
apArcTable [tag._cfgTag.StartArcIndex].AddStartTag (tag);
apArcTable [tag._cfgTag.EndArcIndex].AddEndTag (tag);
// If we have ms-properties than _nameOffset != overwise it is w3c tags.
if (semTag._nameOffset > 0)
{
tag._cfgTag._nameOffset = _symbols.OffsetFromId (_symbols.Find (_symbols.FromOffset (semTag._nameOffset)));
}
else
{
// The offset of the JScrip expression is stored in the value field.
tag._cfgTag._valueOffset = _symbols.OffsetFromId (_symbols.Find (_symbols.FromOffset (semTag._valueOffset)));
}
iCurTag++;
}
}
}
//
_fNeedWeightTable = true;
if (header.BasePath != null)
{
SetBasePath (header.BasePath);
}
_guid = header.GrammarGUID;
_langId = header.langId;
_grammarMode = header.GrammarMode;
_fLoadedFromBinary = true;
// Save Last ArcIndex
#if VSCOMPILE && DEBUG
DumpGrammarStatistics ("InitFromBinaryGrammar");
#endif
}
private Arc CreateTransition (string sWord, float flWeight, int requiredConfidence)
{
// epsilon transition for empty words
return AddSingleWordTransition (!string.IsNullOrEmpty (sWord) ? sWord : null, flWeight, requiredConfidence);
}
///
///
///
///
///
///
///
///
///
private CfgGrammar.CfgSerializedHeader BuildHeader (List sortedStates, int cBasePath, UInt16 iSemanticGlobals, out int cArcs, out float [] pWeights)
{
cArcs = 1; // Start with offset one! (0 indicates dead state).
pWeights = null;
int cSemanticTags = 0;
int cLargest = 0;
foreach (State state in sortedStates)
{
// For new states SerializeId is INFINITE so we set it correctly here.
// For existing states we preserve the index from loading,
// unless new states have been added in.
state.SerializeId = cArcs;
int thisState = state.NumArcs;
#if DEBUG
if (thisState == 0 && state.InArcs.IsEmpty && state.Rule._cStates > 1)
{
XmlParser.ThrowSrgsException (SRID.StateWithNoArcs);
}
#endif
cArcs += thisState;
if (cLargest < thisState)
{
cLargest = thisState;
}
cSemanticTags += state.NumSemanticTags;
}
CfgGrammar.CfgSerializedHeader header = new CfgGrammar.CfgSerializedHeader ();
uint ulOffset = (uint) Marshal.SizeOf (typeof (CfgGrammar.CfgSerializedHeader));
header.FormatId = CfgGrammar._SPGDF_ContextFree;
_guid = Guid.NewGuid ();
header.GrammarGUID = _guid;
header.LangID = (UInt16) _langId;
header.pszSemanticInterpretationGlobals = iSemanticGlobals;
header.cArcsInLargestState = cLargest;
header.cchWords = _words.StringSize ();
header.cWords = _words.Count;
// For compat with SAPI 5.x add one to cWords if there's more than one word.
// The CFGEngine code assumes cWords includes the initial empty-string word.
// See PS 11491 and 61982.
if (header.cWords > 0)
{
header.cWords++;
}
header.pszWords = ulOffset;
ulOffset += (uint) _words.SerializeSize () * Helpers._sizeOfChar;
header.cchSymbols = _symbols.StringSize ();
header.pszSymbols = ulOffset;
ulOffset += (uint) _symbols.SerializeSize () * Helpers._sizeOfChar;
header.cRules = _rules.Count;
header.pRules = ulOffset;
ulOffset += (uint) (_rules.Count * Marshal.SizeOf (typeof (CfgRule)));
header.cBasePath = cBasePath > 0 ? ulOffset : 0; //If there is no base path offset is set to zero
ulOffset += (uint) (((int) cBasePath * Helpers._sizeOfChar + 3) & ~3);
header.cArcs = cArcs;
header.pArcs = ulOffset;
ulOffset += (uint) (cArcs * Marshal.SizeOf (typeof (CfgArc)));
if (_fNeedWeightTable)
{
header.pWeights = ulOffset;
ulOffset += (uint) (cArcs * Marshal.SizeOf (typeof (float)));
pWeights = new float [cArcs];
pWeights [0] = 0.0f;
}
else
{
header.pWeights = 0;
ulOffset += 0;
}
if (_rootRule != null)
{
//We have a root rule
header.ulRootRuleIndex = (uint) _rootRule._iSerialize;
}
else
{
//-1 means there is no root rule
header.ulRootRuleIndex = 0xFFFFFFFF;
}
header.GrammarOptions = _grammarOptions | ((_alphabet == AlphabetType.Sapi) ? 0 : GrammarOptions.IpaPhoneme);
#if !NO_STG
header.GrammarOptions |= _scriptRefs.Count > 0 ? GrammarOptions.STG | GrammarOptions.KeyValuePairSrgs : 0;
#endif
header.GrammarMode = (uint) _grammarMode;
header.cTags = cSemanticTags;
header.tags = ulOffset;
ulOffset += (uint) (cSemanticTags * Marshal.SizeOf (typeof (CfgSemanticTag)));
#if !NO_STG
header.cScripts = _scriptRefs.Count;
header.pScripts = header.cScripts > 0 ? ulOffset : 0;
ulOffset += (uint) (_scriptRefs.Count * Marshal.SizeOf (typeof (CfgScriptRef)));
header.cIL = _il != null ? _il.Length : 0;
header.pIL = header.cIL > 0 ? ulOffset : 0;
ulOffset += (uint) (header.cIL * Marshal.SizeOf (typeof (byte)));
header.cPDB = _pdb != null ? _pdb.Length : 0;
header.pPDB = header.cPDB > 0 ? ulOffset : 0;
ulOffset += (uint) (header.cPDB * Marshal.SizeOf (typeof (byte)));
#endif
header.ulTotalSerializedSize = ulOffset;
return header;
}
private CfgGrammar.CfgHeader BuildRulesFromBinaryGrammar (CfgGrammar.CfgHeader header, State [] apStateTable, SortedDictionary ruleFirstArcs, int previousCfgLastRules)
{
for (int i = 0; i < header.rules.Length; i++)
{
// Check if the rule does not exist already
CfgRule cfgRule = header.rules [i];
int firstArc = (int) cfgRule.FirstArcIndex;
cfgRule._nameOffset = _symbols.OffsetFromId (_symbols.Find (header.pszSymbols.FromOffset (cfgRule._nameOffset)));
Rule rule = new Rule (this, _symbols.FromOffset (cfgRule._nameOffset), cfgRule, i + previousCfgLastRules, _grammarOptions & GrammarOptions.TagFormat, ref _cImportedRules);
rule._firstState = _states.CreateNewState (rule);
_rules.Add (rule);
// Add the rule to the list of firstArc/rule
if (firstArc > 0)
{
ruleFirstArcs.Add ((int) cfgRule.FirstArcIndex, rule);
}
rule._fStaticRule = (cfgRule.Dynamic) ? false : true;
rule._cfgRule.DirtyRule = false;
// by default loaded static rules have an exist
rule._fHasExitPath = (rule._fStaticRule) ? true : false;
// or they wouldn't be there in the first place
if (firstArc != 0)
{
System.Diagnostics.Debug.Assert (apStateTable [firstArc] == null);
rule._firstState.SerializeId = (int) cfgRule.FirstArcIndex;
apStateTable [firstArc] = rule._firstState;
}
if (rule._cfgRule.HasResources)
{
throw new NotImplementedException ();
}
if (header.ulRootRuleIndex == i)
{
_rootRule = rule;
}
// Add rule to RuleListByName and RuleListByID hash tables.
if (rule._cfgRule._nameOffset != 0)
{
// Look for the rule in the original CFG and map it in the combined string blobs
_nameOffsetRules.Add (rule._cfgRule._nameOffset, rule);
}
}
return header;
}
#endif
private Rule CloneState (State srcToState, List CloneStack, Dictionary srcToDestHash)
{
bool newRule = false;
int posDynamic = srcToState.Rule.Name.IndexOf ("URL:DYNAMIC#", StringComparison.Ordinal);
string ruleName = posDynamic != 0 ? srcToState.Rule.Name : srcToState.Rule.Name.Substring (12);
Rule dstRule = FindInRules (ruleName);
// Clone this rule into this GrammarBuilder if it does not exist yet
if (dstRule == null)
{
dstRule = srcToState.Rule.Clone (_symbols, ruleName);
_rules.Add (dstRule);
newRule = true;
}
// Should not exist yet
System.Diagnostics.Debug.Assert (!srcToDestHash.ContainsKey (srcToState));
// push all the states for that rule
State newState = CreateNewState (dstRule);
srcToDestHash.Add (srcToState, newState);
CloneStack.Add (srcToState);
if (newRule)
{
dstRule._firstState = newState;
}
return dstRule;
}
private Rule FindInRules (string ruleName)
{
foreach (Rule rule in _rules)
{
if (rule.Name == ruleName)
{
return rule;
}
}
return null;
}
private static void LogError (string rule, SRID srid, params object [] args)
{
string sError = SR.Get (srid, args);
throw new FormatException (string.Format (CultureInfo.InvariantCulture, "Rule=\"{0}\" - ", rule) + sError);
}
///
/// Connect arc to the state graph.
///
///
#if DEBUG
private
#else
private static
#endif
void AddArc (Arc arc)
{
#if DEBUG
arc.Backend = this;
#endif
}
///
///
///
///
private void ValidateAndTagRules ()
{
//CfgGrammar.TraceInformation ("BackEnd::ValidateAndTagRules");
//
bool fAtLeastOneRule = false;
int ulIndex = 0;
foreach (Rule rule in _rules)
{
// set _fHasExitPath = true for empty dynamic grammars and imported rules
// Clear this for the next loop through the rules....
rule._fHasExitPath |= (rule._cfgRule.Dynamic | rule._cfgRule.Import) ? true : false;
rule._iSerialize = ulIndex++;
fAtLeastOneRule |= (rule._cfgRule.Dynamic || rule._cfgRule.TopLevel || rule._cfgRule.Export);
rule.Validate ();
}
#if DEBUG
//
// Now make sure that all rules have an exit path.
//
foreach (Rule rule in _rules)
{
_ulRecursiveDepth = 0;
//The following function will use recursive function that might change _ulRecursiveDepth
rule.CheckForExitPath (ref _ulRecursiveDepth);
}
#endif
//
// Check each exported rule if it has a dynamic rule in its "scope"
//
foreach (Rule rule in _rules)
{
if (rule._cfgRule.Dynamic)
{
rule._cfgRule.HasDynamicRef = true;
_ulRecursiveDepth = 0;
rule.PopulateDynamicRef (ref _ulRecursiveDepth);
}
}
}
private void CheckLeftRecursion (List states)
{
bool fReachedEndState;
foreach (State state in states)
{
state.CheckLeftRecursion (out fReachedEndState);
}
}
///
///
///
///
///
///
private Arc AddSingleWordTransition (string s, float flWeight, int requiredConfidence)
{
//CfgGrammar.TraceInformation ("BackEnd::CGramComp::AddSingleWordTransition");
Arc arc = new Arc (s, null, _words, flWeight, requiredConfidence, null, MatchMode.AllWords, ref _fNeedWeightTable);
AddArc (arc);
return arc;
}
internal void AddState (State state)
{
_states.Add (state);
}
#if VSCOMPILE && DEBUG
///
internal void DumpStateTable (string sTitle)
{
List states = new List (_states);
DumpStateTable (sTitle, states.ToArray ());
}
internal void DumpStateTable (string sTitle, State [] states)
{
CfgGrammar.TraceInformation2 (sTitle);
int iHandle2 = 0;
for (int iState = 0; iState < states.Length; iState++)
{
State state = states [iState];
if (state == null)
{
continue;
}
//string s = state.OutArcs.Count > 0 ? state.OutArcs.First.WordId > 0 ? _words [state.OutArcs.First.WordId] : string.Empty : string.Empty;
string s = _symbols.FromOffset (state.Rule._cfgRule._nameOffset);
CfgGrammar.TraceInformation3 (string.Format (CultureInfo.InvariantCulture, "{0}: {1} {2} {3} '", iHandle2, state.Id, state.SerializeId, s));
foreach (Arc arc2 in state.OutArcs)
{
int iWord = arc2.WordId;
string sWord = arc2.RuleRef != null ? _symbols.FromOffset (arc2.RuleRef._cfgRule._nameOffset) : iWord > 0 ? _words [iWord] : string.Empty;
//CfgGrammar.TraceInformation3 (string.Format (CultureInfo.InvariantCulture, "{0}{1} [{2}]", (fFirst ? string.Empty : ", "), sWord, arc2.Id));
//if (arc2._tag != null)
//{
// CfgGrammar.TraceInformation3 (string.Format (CultureInfo.InvariantCulture, "({0}, {1}, {2})", _symbols.FromOffset (arc2._tag._cfgTag._valueOffset), arc2._tag._startArc.Id, arc2._tag._endArc.Id));
//}
}
CfgGrammar.TraceInformation2 ("'");
}
}
internal void DumpStateMachine (TextWriter tw)
{
tw.WriteLine ("Word Blobs");
for (int i = 1; i < _words.Count; i++)
{
tw.WriteLine (" \"" + _words [i] + "\"");
}
tw.WriteLine ("\nSymbols Blobs");
for (int i = 1; i < _symbols.Count; i++)
{
tw.WriteLine (" \"" + _symbols [i] + "\"");
}
tw.WriteLine ("\nRules");
foreach (Rule rule in _rules)
{
tw.WriteLine (string.Format (CultureInfo.InvariantCulture, " \"{0}\" id: {1} flags: {2}", rule.Name, rule._cfgRule._id, rule._cfgRule._flag.ToString ("x", CultureInfo.InvariantCulture)));
tw.WriteLine (string.Format (CultureInfo.InvariantCulture, " States: {0}", rule._cStates));
}
tw.WriteLine (string.Format (CultureInfo.InvariantCulture, "\nStates:\n Count: {0}", _states.Count));
foreach (State state in _states)
{
tw.WriteLine (string.Format (CultureInfo.InvariantCulture, " \"{0}\"", state.Rule.Name));
}
}
//GrammarOptimization
///
/// Dump grammar statistics to debug window. (Debug only)
///
///
void DumpGrammarStatistics (string title)
{
int iNumStates = 0;
int iNumArcs = 0;
int iNumEpsilonArcs = 0;
int iMaxBranch = 0;
int iNumProperties = 0;
foreach (State state in _states)
{
iNumStates++;
int cArcs = 0;
foreach (Arc arc in state.OutArcs)
{
cArcs++;
if (arc.IsEpsilonTransition)
{
iNumEpsilonArcs++;
}
//if (arc._tag != null)
//{
// iNumProperties++;
//}
}
if (iMaxBranch < cArcs)
iMaxBranch = cArcs;
iNumArcs += cArcs;
}
Console.WriteLine (title);
Console.WriteLine (string.Format (CultureInfo.InvariantCulture, "{0}\n NumStates = {0}\n NumArcs = {1}\n NumEpsilons = {2}\n", iNumStates, iNumArcs, iNumEpsilonArcs));
Console.WriteLine (string.Format (CultureInfo.InvariantCulture, " MaxBranch = {0}\n" + " NumProperties = {1}\n", iMaxBranch, iNumProperties));
}
#endif
#endregion
//*******************************************************************
//
// Internal Properties
//
//*******************************************************************
#region Internal Properties
internal int LangId
{
get
{
return _langId;
}
set
{
_langId = value;
}
}
internal GrammarOptions GrammarOptions
{
get
{
return _grammarOptions;
}
set
{
_grammarOptions = value;
}
}
internal GrammarType GrammarMode
{
set
{
_grammarMode = value;
}
}
internal AlphabetType Alphabet
{
set
{
_alphabet = value;
}
get
{
return _alphabet;
}
}
internal Collection GlobalTags
{
get
{
return _globalTags;
}
set
{
_globalTags = value;
}
}
#if !NO_STG
internal Collection ScriptRefs
{
set
{
_scriptRefs = value;
}
}
internal byte [] IL
{
set
{
_il = value;
}
}
internal byte [] PDB
{
set
{
_pdb = value;
}
}
#endif
#endregion
//*******************************************************************
//
// Private Fields
//
//********************************************************************
#region Private Fields
private int _langId = CultureInfo.CurrentUICulture.LCID;
private StringBlob _words;
private StringBlob _symbols;
//private int _cResources;
private Guid _guid;
private bool _fNeedWeightTable;
private Graph _states = new Graph ();
private List _rules = new List ();
private int _ruleIndex;
private Dictionary _nameOffsetRules = new Dictionary ();
private Rule _rootRule;
#if !SPEECHSERVER
private GrammarOptions _grammarOptions = GrammarOptions.KeyValuePairs;
#else
private GrammarOptions _grammarOptions = GrammarOptions.W3cV1;
#endif
// It is used sequentially. So there is no thread issue
private int _ulRecursiveDepth;
// Path from which relative grammar imports are calculated. As specified by xml:base
private string _basePath;
// Collection of all SemanticTags in the grammar (sorted by StartArc)
private List _tags = new List ();
// Voice or DTMF
private GrammarType _grammarMode = GrammarType.VoiceGrammar;
// Pron information is either IPA or SAPI
private AlphabetType _alphabet = AlphabetType.Sapi;
// Global value for the semantic interpretation tags
private Collection _globalTags = new Collection ();
//
private static byte [] _abZero3 = new byte [] { 0, 0, 0 };
private static char [] _achZero = new char [] { '\0' };
//
private const uint SPGF_RESET_DIRTY_FLAG = 0x80000000;
private int _cImportedRules;
#if !NO_STG
// List of cd /reference Rule->rule 'on'method-> .Net method
private Collection _scriptRefs = new Collection ();
// Grammar code assembly
private byte [] _il;
// Grammar debug symbols
private byte [] _pdb;
#endif
private bool _fLoadedFromBinary;
#endregion
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- WebPartVerb.cs
- BitmapSizeOptions.cs
- PictureBox.cs
- SqlDataSourceCache.cs
- ErrorEventArgs.cs
- HeaderedItemsControl.cs
- MetadataArtifactLoaderCompositeFile.cs
- CodeTypeReferenceExpression.cs
- Cast.cs
- BaseCodeDomTreeGenerator.cs
- XmlSchemaException.cs
- CheckoutException.cs
- TemplateNameScope.cs
- FrugalList.cs
- ListControlConvertEventArgs.cs
- SecurityRuntime.cs
- Normalization.cs
- DefaultValidator.cs
- PropertyEmitter.cs
- XmlAttributeCollection.cs
- BookmarkEventArgs.cs
- ExpressionNode.cs
- XmlDictionaryReader.cs
- EpmSourceTree.cs
- DiscoveryDefaults.cs
- WebServicesSection.cs
- MouseCaptureWithinProperty.cs
- SessionStateSection.cs
- ChildDocumentBlock.cs
- CssStyleCollection.cs
- DiagnosticsConfiguration.cs
- HyperLinkDataBindingHandler.cs
- SelectionPattern.cs
- CatalogZoneAutoFormat.cs
- XsdBuildProvider.cs
- HttpModuleCollection.cs
- DesignerCategoryAttribute.cs
- DesignerAttribute.cs
- DecimalConverter.cs
- util.cs
- CompiledWorkflowDefinitionContext.cs
- WeakReferenceEnumerator.cs
- Tablet.cs
- MSAAEventDispatcher.cs
- EntityTransaction.cs
- DataContractAttribute.cs
- NetworkInformationPermission.cs
- PagedDataSource.cs
- ClientRuntimeConfig.cs
- MiniMapControl.xaml.cs
- ExpressionsCollectionEditor.cs
- ListDictionaryInternal.cs
- DataRowCollection.cs
- FunctionImportElement.cs
- SingleAnimationBase.cs
- XmlDocumentViewSchema.cs
- XmlSchemaAppInfo.cs
- codemethodreferenceexpression.cs
- DesignerActionTextItem.cs
- SelectionUIHandler.cs
- DescriptionAttribute.cs
- Bits.cs
- XmlBoundElement.cs
- EntryIndex.cs
- Signature.cs
- SchemaImporterExtensionElement.cs
- UInt32Storage.cs
- ExceptionAggregator.cs
- WebPartEditorOkVerb.cs
- XmlIlGenerator.cs
- StylusButtonEventArgs.cs
- UrlPath.cs
- MoveSizeWinEventHandler.cs
- TreeViewAutomationPeer.cs
- ToolStripHighContrastRenderer.cs
- InlineCollection.cs
- SignatureToken.cs
- ReadOnlyCollection.cs
- ListenerChannelContext.cs
- BufferedWebEventProvider.cs
- ChildTable.cs
- XmlObjectSerializerWriteContextComplex.cs
- TreeViewTemplateSelector.cs
- EntityDataSourceColumn.cs
- DebugHandleTracker.cs
- ClaimTypeElementCollection.cs
- DBDataPermission.cs
- DataPointer.cs
- JsonDeserializer.cs
- GifBitmapDecoder.cs
- NamedElement.cs
- EncoderParameter.cs
- HTMLTextWriter.cs
- DataServiceCollectionOfT.cs
- FastPropertyAccessor.cs
- CodeAssignStatement.cs
- UpDownEvent.cs
- SaveCardRequest.cs
- InvalidPropValue.cs
- OleDbException.cs