diff -r 000000000000 -r b16258d2340f applayerprotocols/wapbase/bnf/CBNFParser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/applayerprotocols/wapbase/bnf/CBNFParser.cpp Tue Feb 02 01:09:52 2010 +0200 @@ -0,0 +1,907 @@ +// Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include + +#include +#include +#include +#include + +#include "BNFPanicCodes.h" + + +/** Allocates and constructs a new BNF parser. + +@return New parser +@param aLUT Attribute lookup table in which to store attributes for +the rule tree +*/ +EXPORT_C CBNFParser* CBNFParser::NewL(CAttributeLookupTable& aLUT) + { + CBNFParser* model = new (ELeave) CBNFParser(aLUT); + return (model); + } + +/** Constructor. + +@param aLUT Attribute lookup table +*/ +EXPORT_C CBNFParser::CBNFParser(CAttributeLookupTable& aLUT) + : iLUT(aLUT) + { +// store pointers to these to avoid continual unnecessary calls to the CBNFNode DLL + iReferenceString=CBNFNode::KReference(); + iRangeStart=CBNFNode::KRangeStart(); + iRangeEnd=CBNFNode::KRangeEnd(); + iMoreMinimum=CBNFNode::KNMoreMinimum(); + iMoreCount=CBNFNode::KNMoreCount(); + iMoreMaximum=CBNFNode::KNMoreMaximum(); + iPreRuleCallback=CBNFNode::KPreRuleCallback(); + iPostRuleCallback=CBNFNode::KPostRuleCallback(); + } + +/** Destructor. +*/ +EXPORT_C CBNFParser::~CBNFParser() + { + delete iTree; + } + +/** Reset the parser to a state where it can accept and parse new input. + +If no BNF tree yet exists the virtual method TreeL() is called to obtain the BNF tree for this parser. +Any existing state of parsing and input data is destroyed. */ +EXPORT_C void CBNFParser::ResetL() + { + if (iTree == NULL) + iTree = TreeL(); + + iRuleStack.Clear(); + iRuleStack.PushL(iTree); + + iSubRuleMatched = EFalse; + iSubRule = NULL; + iStringComplete = EFalse; + iString.Reset(); + } + +/** Gets the attribute look-up table used by this parser. + +@return Attribute look-up table +*/ +EXPORT_C CAttributeLookupTable& CBNFParser::AttributeLUT() const + { + return iLUT; + } + +/** Processes a reference rule node. + +It is called by PerformRuleL(). + +@return ETrue if the function completed processing this node, otherwise EFalse +@param aRule The rule node being processed +@param aMatched On return, flag indicating if input stream matched the rule +*/ +EXPORT_C TBool CBNFParser::ReferenceL(CBNFNode& aRule, CFragmentedString::TStringMatch& /*aMatched*/) +// Handle a reference node. +// The pointer to the refered rule is stored as an attribute to a node which +// is stored as an attribute to the reference node. Nice and simple, isn't it? :-) + { + // new to this Reference, or returning from a sub match? + if (iSubRule) + // No operation is required when returning from the refered rule - continue up. + return ETrue; + else + { + CNoDeleteAttributeT* attributeNode = REINTERPRET_CAST(CNoDeleteAttributeT*, aRule.Attribute(iReferenceString)); +// iRuleStack.Pop(); //Optimisation not possible as other bnf parts use this 'rule' node to find the next sibling (i.e. And, Or etc) + iRuleStack.PushL(attributeNode->Attribute()); + } + return EFalse; + } + +/** Processes an EExact rule node. + +It is called by PerformRuleL(). + +@return ETrue if the function completed processing this node, otherwise EFalse +@param aRule The rule node being processed +@param aMatched On return, flag indicating if input stream matched the rule +*/ +EXPORT_C TBool CBNFParser::ExactL(CBNFNode& aRule, CFragmentedString::TStringMatch& aMatched) +// Handle an EExact rule +// Attempts to match a string with the stream. + { + if ((aMatched=iString.Match(REINTERPRET_CAST(HBufC*, aRule.Data())->Des()))==CFragmentedString::EMatch) + iString.ConsumeMatched(); + return ETrue; + } + +/** Processes an ERange rule node. + +It is called by PerformRuleL(). + +@return ETrue if the function completed processing this node, otherwise EFalse +@param aRule The rule node being processed +@param aMatched On return, flag indicating if input stream matched the rule +*/ +EXPORT_C TBool CBNFParser::RangeL(CBNFNode& aRule, CFragmentedString::TStringMatch& aMatched) +// Handle ERange rule +// Checks if the next character in the stream fits into the chracter range defined by the rule + { + CNoDeleteAttributeT* rangeStartAttribute = REINTERPRET_CAST(CNoDeleteAttributeT*, aRule.Attribute(iRangeStart)); + TInt rangeStart; + if (rangeStartAttribute) + rangeStart = rangeStartAttribute->Attribute(); + else + rangeStart = 0; + + CNoDeleteAttributeT* rangeEndAttribute = REINTERPRET_CAST(CNoDeleteAttributeT*, aRule.Attribute(iRangeEnd)); + TInt rangeEnd; + if (rangeEndAttribute) + rangeEnd = rangeEndAttribute->Attribute(); + else + rangeEnd = 0; + + if ((aMatched = iString.MatchRange(rangeStart, rangeEnd)) == CFragmentedString::EMatch) + iString.ConsumeMatched(); + return ETrue; + } + + +/** Processes an ESelect rule node. + +It is called by PerformRuleL(). + +@return ETrue if the function completed processing this node, otherwise EFalse +@param aRule The rule node being processed +@param aMatched On return, flag indicating if input stream matched the rule +*/ +EXPORT_C TBool CBNFParser::SelectL(CBNFNode& aRule, CFragmentedString::TStringMatch& aMatched) +// Handle Select rule +// Check if the next character in the stream matches to any of the chracters included +// into the set defined by the select rule. +// The selection can also be performed as inverted selection (by using "^" as the first char) +// in which case all the other characters but the ones defined in the set match correctly to the stream. + { + if ((*aRule.Data())[0] == '^') + aMatched = iString.MatchNotSelect((*REINTERPRET_CAST(HBufC*, aRule.Data())).Mid(1)); + else + aMatched = iString.MatchSelect(*REINTERPRET_CAST(HBufC*, aRule.Data())); + +//! if (aMatched == CFragmentedString::EMatch) + iString.ConsumeMatched(); + return ETrue; + } + +/** Processes an EWithout rule node. + +It is called by PerformRuleL(). + +@return ETrue if the function completed processing this node, otherwise EFalse +@param aRule The rule node being processed +@param aMatched On return, flag indicating if input stream matched the rule +*/ +EXPORT_C TBool CBNFParser::WithoutL(CBNFNode& aRule, CFragmentedString::TStringMatch& aMatched) +// Handle EWithout rule +// An example Without rule: [A-Z] - B +// Here we are trying to match all characters from A-Z except character B. +// The rule is performed here by first executing the latter part of the rule (in the example +// by trying to match B). If the latter rule matches, then the stream contains the chracter +// string we didn't want it to include and hence the Without rule is false. However, if the +// latter rule doesn't match we proceed to matching the first part of the rule and if it +// does match the whole Without rule is true. +// The Without rule node has two children of which the first one (child on index 0) +// is the rule we are trying to match and the second child is the "except" part of the rule. + { + TBool performedMatch = EFalse; + // new to this Without, or returning from a sub match? + CBNFNode* newRule = NULL; + if (iSubRule) + { + if (iSubRule == aRule.Child(1)) + { + iString.ResetToMark(); + iString.DeleteMark(); + if (!iSubRuleMatched) + newRule = REINTERPRET_CAST(CBNFNode*, aRule.Child(0)); + else + aMatched = CFragmentedString::ENoMatch; + } + } + else + { + iString.Mark(); // Mark can leave + StartConditional((enum TParserNodeTypes)aRule.Type()); + newRule = REINTERPRET_CAST(CBNFNode*, aRule.Child(1)); + } + if (newRule) + { + iRuleStack.PushL(newRule); + iSubRule = NULL; // going down + } + else + { + EndConditional((enum TParserNodeTypes)aRule.Type(), iSubRuleMatched); + performedMatch = ETrue; + } + return performedMatch; + } + +/** Processes an EAnd rule node. + +It is called by PerformRuleL(). + +@return ETrue if the function completed processing this node, otherwise EFalse +@param aRule The rule node being processed +@param aMatched On return, flag indicating if input stream matched the rule +*/ +EXPORT_C TBool CBNFParser::AndL(CBNFNode& aRule, CFragmentedString::TStringMatch& /*aMatched*/) +// Handle And rule +// An EAnd rule is true if all of its children are true. Processing the child nodes of +// the And rule continues until all the children has been processed of one of them doesn't +// match. Notice, that the order of the child rules has signifigance, since we are +// matching a chracter stream and the first child is matched first, followed by the second etc. + { + TBool performedMatch = EFalse; + // new to this And, or returning from a sub match? + CBNFNode* newRule = NULL; + if (iSubRule) + { + if (iSubRuleMatched) + { + newRule = REINTERPRET_CAST(CBNFNode*, iSubRule->NextSibling()); + if (!newRule) + performedMatch = ETrue; + } + else + performedMatch = ETrue; + } + else + { + newRule = REINTERPRET_CAST(CBNFNode*, aRule.Child(0)); + StartConditional((enum TParserNodeTypes)aRule.Type()); + } + if (newRule) + { + iRuleStack.PushL(newRule); + iSubRule = NULL; // going down + } + else + { + EndConditional((enum TParserNodeTypes)aRule.Type(), iSubRuleMatched); +//! performedMatch = ETrue; + } + return performedMatch; + } + + +/** Processes an EOr rule node. + +It is called by PerformRuleL(). + +@return ETrue if the function completed processing this node, otherwise EFalse +@param aRule The rule node being processed +@param aMatched On return, flag indicating if input stream matched the rule +*/ +EXPORT_C TBool CBNFParser::OrL(CBNFNode& aRule, CFragmentedString::TStringMatch& /*aMatched*/) +// Handle Or rule +// We attempt to match the child rules of the Or node and stop when we have the first match. +// With the Or type rule each of the child rules are matched agaist the same bit of input +// stream. Before we start processing the first child rule we set a mark to the input stream +// and if a child rule doesn't match, we rollback the input stream to the mark and try +// to match the next child. + { + TBool performedMatch = EFalse; + CBNFNode* newRule = NULL; + // new to this Or, or returning from a sub match? + if (iSubRule) + { + if (!iSubRuleMatched) + { + newRule = REINTERPRET_CAST(CBNFNode*, iSubRule->NextSibling()); + } + EndConditional((enum TParserNodeTypes)aRule.Type(), iSubRuleMatched); + } + else + { + newRule = REINTERPRET_CAST(CBNFNode*, aRule.Child(0)); + iString.Mark(); // Mark can leave + } + if (newRule) + { + iRuleStack.PushL(newRule); + iSubRule = NULL; // going down + iString.ResetToMark(); + StartConditional((enum TParserNodeTypes)aRule.Type()); + } + else + { + performedMatch = ETrue; + if (!iSubRuleMatched) + iString.ResetToMark(); + iString.DeleteMark(); + } + return performedMatch; + } + +EXPORT_C TBool CBNFParser::OptionalL(CBNFNode& aRule, CFragmentedString::TStringMatch& aMatched) +// Handle Optional rule +// Process the subrule attached to the optional rule. +// An optional rule is always successfully processed regardless to success or failure of matching +// the subrule. This is because of the nature of the optional rule - the subrule here either may +// or may not be there. + { + TBool performedMatch = EFalse; + // new to this Optional, or returning from a sub match? + if (iSubRule) + { + performedMatch = ETrue; + aMatched = CFragmentedString::EMatch; + iOptionalMatched = iSubRuleMatched; + if (!iSubRuleMatched) + iString.ResetToMark(); + iString.DeleteMark(); + } + else + { + iString.Mark(); // Mark can leave + iRuleStack.PushL(REINTERPRET_CAST(CBNFNode*, aRule.Child(0))); + iSubRule = NULL; + } + return performedMatch; + } + + + +/** Processes an ENMore rule node. + +It is called by PerformRuleL(). + +@return ETrue if the function completed processing this node, otherwise EFalse +@param aRule The rule node being processed +@param aMatched On return, flag indicating if input stream matched the rule +*/ +EXPORT_C TBool CBNFParser::NMoreL(CBNFNode& aRule, CFragmentedString::TStringMatch& aMatched) +// Handle NMore rule +// NMore rule implements the "multiplier" elements of BNF (* and +). +// We attempt to match the subrule and if it matches we try again until it doesn't match +// or we run into the upperlimit set to this rule. +// An NMore rule may contain lower and upper limits for the number of times the matching +// can or needs to be done. These are included as attributes to the NMore node. The NMore +// node also holds a counter attribute, which holds the amount of times this rule has been +// matched. + { + TBool performedMatch = EFalse; + // new to this NMore, or returning from a sub match? + if (iSubRule) + { + CNoDeleteAttributeT* countAttribute = REINTERPRET_CAST(CNoDeleteAttributeT*, aRule.Attribute(iMoreCount)); + CNoDeleteAttributeT* maxCountAttribute = REINTERPRET_CAST(CNoDeleteAttributeT*, aRule.Attribute(iMoreMaximum)); + + if (iSubRuleMatched) + countAttribute->SetAttribute(countAttribute->Attribute()+1); + else + { + performedMatch = ETrue; + CNoDeleteAttributeT* minCountAttribute = REINTERPRET_CAST(CNoDeleteAttributeT*, aRule.Attribute(iMoreMinimum)); + if ((minCountAttribute == NULL) || (countAttribute->Attribute() >= minCountAttribute->Attribute())) + aMatched = CFragmentedString::EMatch; + iString.ResetToMark(); + } + + if ((maxCountAttribute) && (countAttribute->Attribute() >= maxCountAttribute->Attribute())) + performedMatch = ETrue; + + iString.DeleteMark(); + } + else + { + aRule.DeleteAttribute(iMoreCount); + CNoDeleteAttributeT* countAttribute = new (ELeave) CNoDeleteAttributeT(0); + CleanupStack::PushL(countAttribute); + aRule.AddAttributeL(iMoreCount, countAttribute); + CleanupStack::Pop(); + } + if (!performedMatch) + { + iRuleStack.PushL(REINTERPRET_CAST(CBNFNode*, aRule.Child(0))); + iSubRule = NULL; + iString.Mark(); // Mark can leave + } + return performedMatch; + } + +/** Executes a pre-rule callback function. + +@param aRule Node specifying the callback +*/ +EXPORT_C +void +CBNFParser::ExecutePreRuleCallbackL(CBNFNode& aRule) + { + CNoDeleteAttributeT* preRuleAttribute; + if ((preRuleAttribute= REINTERPRET_CAST(CNoDeleteAttributeT*, aRule.Attribute(iPreRuleCallback)))!=NULL) + (*preRuleAttribute->Attribute())(*this); + } + +/** Executes a post-rule callback function. + +@param aRule Node specifying the callback +*/ +EXPORT_C +void +CBNFParser::ExecutePostRuleCallbackL(CBNFNode& aRule) + { + CNoDeleteAttributeT* postRuleAttribute; + if ((postRuleAttribute = REINTERPRET_CAST(CNoDeleteAttributeT*, aRule.Attribute(iPostRuleCallback)))!=NULL) + (*postRuleAttribute->Attribute())(*this); + } + +/** Handles a node in the rule tree. + +It calls the appropriate handler method for the rule type. + +@return ETrue if the function completed processing this node, otherwise EFalse +@param aRule Rule node +@param aMatched On return, flag indicating if input stream matched the rule +*/ +EXPORT_C +TBool +CBNFParser::PerformRuleL(CBNFNode& aRule, CFragmentedString::TStringMatch& aMatched) +// Dispatches a rule node of given type to the appropriate handler + { + TBool performedMatch; + switch (aRule.Type()) + { + case EReference: + performedMatch = ReferenceL(aRule, aMatched); + break; + case EExact: + performedMatch = ExactL(aRule, aMatched); + break; + case ERange: + performedMatch = RangeL(aRule, aMatched); + break; + case ESelect: + performedMatch = SelectL(aRule, aMatched); + break; + case EWithout: + performedMatch = WithoutL(aRule, aMatched); + break; + case ERoot: + case EAnd: + performedMatch = AndL(aRule, aMatched); + break; + case EOr: + performedMatch = OrL(aRule, aMatched); + break; + case EOptional: + performedMatch = OptionalL(aRule, aMatched); + break; + case ENMore: + performedMatch = NMoreL(aRule, aMatched); + break; + case EIncomplete: + default: + __ASSERT_DEBUG(EFalse, User::Panic(_L("CBNFPARSE"), 1)); + // Oh dear an incomplete node in the rule tree. FAIL NOW!!! + performedMatch = ETrue; + aMatched = CFragmentedString::ENoMatch; + break; + } + return performedMatch; + } + +EXPORT_C TBool CBNFParser::ParseL() +// Performs the actual parsing. +// Consumes as much of the input data as it can using the iTree BNF tree. +// Whilst parsing the appropriate callbacks are invoked on the parsed rules allowing actions to be performed. +// Should the input data be fully consumed and the parser has not been notified that there is no more input data +// this method returns leaving the parser in a state waiting for more input. + { + iParsing = EActive; + while ((State() == EActive) && (!iRuleStack.IsEmpty())) + { + // find next rule + CBNFNode *currentRule = iRuleStack.Head(); + + // are we going up or down the tree? + if (iSubRule == NULL) + ExecutePreRuleCallbackL(*currentRule); + + if (PerformRuleL(*currentRule, iMatched)) + { + switch (iMatched) + { + case CFragmentedString::EMatch: + // we matched take ourselves off the stack + iRuleStack.Pop(); + iSubRuleMatched = ETrue; + iSubRule = currentRule; + break; + case CFragmentedString::EInsufficientData: + // we ran out of data doing the match, should we try again later or is it a no match + if (!iStringComplete) + { + iParsing= EStopped; + break; + } + case CFragmentedString::ENoMatch: + // we didn't match take ourselves off the stack + iRuleStack.Pop(); + iSubRuleMatched = EFalse; + iSubRule = currentRule; + break; + default: + // naughty, naughty. + break; + } + if( iMatched != CFragmentedString::EInsufficientData || iStringComplete) + ExecutePostRuleCallbackL(*currentRule); + } + // have we finished all the rules!?!?! + if (iRuleStack.IsEmpty()) + iParsing= EStopped; + } + return (iSubRuleMatched); + } + + +// +// assist BNF tree building +/** Creates a new rule tree root node. + +It creates a new single instance of CBNFNode as the root node of the rule tree. +All the top-level rules are attached as attributes to this node. The root node +should have single child node, which should be a reference to the logical root +of the rule tree. This can be done be attaching the logical root rule as a component +to the root rule. + +@return New rule tree root node +*/ +EXPORT_C CBNFNode* CBNFParser::NewBNFL() +// Generate a new ROOT node for a BNF tree. + { + return CBNFNode::NewL(ERoot); + } + +/** Creates a new rule node and adds it to the root of the rule tree. + +This overload takes ownership of the node data. + +@return The newly created rule node in the rule tree +@param aRootRule Pointer to the root BNF node, created with NewBNFL() +@param aRuleName Reference to a string identifying this rule. The string is used to make references to this rule from other rule's subtrees. +@param aRuleType Rule type +@param aData Rule data pointer. This is used with EExact and ESelect type rules to match actual text strings. +@param aPreRule Function pointer to a pre-rule function that gets called before the parser starts processing this rule and its children (i.e. the rule subtree). +@param aPostRule Function pointer to a post-rule function that gets called after the parser has processed this rule and its subtree. +*/ +EXPORT_C CBNFNode& CBNFParser::NewRuleL(CBNFNode* aRootRule, const TDesC& aRuleName, TParserNodeTypes aRuleType, HBufC* aData, TRuleCallback* aPreRule, TRuleCallback* aPostRule) +// Add a new rule to the BNF tree, the new rule is given the name aRuleName (so it can be referred by another rule). +// The parameter aData is used by the RuleTypes: Exact & Select. + { + // taken ownership of aData + CleanupStack::PushL(aData); + const HBufC* id = iLUT.Des2IDL(aRuleName); + + CBNFNode* terminal = REINTERPRET_CAST(CBNFNode*, aRootRule->Attribute(id)); + + if (terminal) + terminal->SetType(aRuleType); + else + { + terminal = CBNFNode::NewL(aRuleType); + CleanupStack::PushL(terminal); + aRootRule->AddAttributeL(id, terminal); + CleanupStack::Pop(); + } + + if (aData) + terminal->SetDataL(aData); + CleanupStack::Pop(); + + AddRuleCallbackL(*terminal, iPreRuleCallback, aPreRule); + AddRuleCallbackL(*terminal, iPostRuleCallback, aPostRule); + + return *terminal; + } + +/** Creates a new rule node and adds it to the root of the rule tree. + +This overload takes a reference to the node data instead of owning it. + +@return The newly created rule node in the rule tree +@param aRootRule Pointer to the root BNF node, created with NewBNFL() +@param aRuleName Reference to a string identifying this rule. The string is used to make references to this rule from other rule's subtrees. +@param aRuleType Rule type +@param aData Rule data pointer. This is used with EExact and ESelect type rules to match actual text strings. +@param aPreRule Function pointer to a pre-rule function that gets called before the parser starts processing this rule and its children (i.e. the rule subtree). +@param aPostRule Function pointer to a post-rule function that gets called after the parser has processed this rule and its subtree. +*/ +EXPORT_C CBNFNode& CBNFParser::NewRuleL(CBNFNode* aRootRule, const TDesC& aRuleName, TParserNodeTypes aRuleType, const TDesC& aData, TRuleCallback* aPreRule, TRuleCallback* aPostRule) + { + return NewRuleL(aRootRule, aRuleName, aRuleType, aData.AllocL(), aPreRule, aPostRule); + } + +/** Adds a callback to a rule. + +@param aRule The rule to which the callback is to be added +@param aCallbackID Callback type: either CBNFNode::KPreRuleCallback() or CBNFNode::KPostRuleCallback() +@param aCallback Callback function +*/ +EXPORT_C void CBNFParser::AddRuleCallbackL(CBNFNode& aRule, const TDesC* aCallbackID, TRuleCallback* aCallback) + { + if (aCallback) + { + CNoDeleteAttributeT* ruleAttribute = new (ELeave) CNoDeleteAttributeT(aCallback); + CleanupStack::PushL(ruleAttribute); + aRule.AddAttributeL(aCallbackID, ruleAttribute); + CleanupStack::Pop(); + } + } + +/** Creates a new reference rule node. + +@return The new reference rule node +@param aRootRule Root node +@param aRuleName Rule name +*/ +EXPORT_C CBNFNode* CBNFParser::NewComponentL(CBNFNode* aRootRule, const TDesC& aRuleName) + { + CBNFNode *terminalNode = (CBNFNode*)aRootRule->Attribute(iLUT.Des2IDL(aRuleName)); + if (terminalNode == NULL) + terminalNode = &NewRuleL(aRootRule, aRuleName, EIncomplete, NULL, NULL, NULL); + + CBNFNode* rule = CBNFNode::NewL(EReference); + CleanupStack::PushL(rule); + CNoDeleteAttributeT* attributeNode = new (ELeave) CNoDeleteAttributeT(terminalNode); + CleanupStack::PushL(attributeNode); + rule->AddAttributeL(iReferenceString, attributeNode); + CleanupStack::Pop(2); + + return rule; + } + + +/** Creates a new rule node, but does not add it to the tree. + +This overload sets no rule callbacks. + +@return The new rule node +@param aRuleType Rule type +@param aData Rule data reference. This is used with EExact and ESelect type rules to match actual text strings. +*/ +EXPORT_C CBNFNode* CBNFParser::NewComponentL(TParserNodeTypes aRuleType, const TDesC& aData) +// Adds a new rule component to the given ParentRule. + { + return NewComponentL(aRuleType, aData.AllocL()); + } + +/** Creates a new rule node, but does not add it to the tree. + +This overload allows rule callbacks to be set. + +@return The new rule node +@param aRuleType Rule type +@param aData Rule data pointer. This is used with EExact and ESelect type rules to match actual text strings. +@param aPreRule Function pointer to a pre-rule function that gets called before the parser starts processing this rule and its subtree. +@param aPostRule The new rule node +*/ +EXPORT_C CBNFNode* CBNFParser::NewComponentL(TParserNodeTypes aRuleType, HBufC* aData/*=NULL*/, TRuleCallback* aPreRule/*=NULL*/, TRuleCallback* aPostRule/*=NULL*/) + { + // taken ownership of aData + CleanupStack::PushL(aData); + CBNFNode* terminal = CBNFNode::NewL(aRuleType); + CleanupStack::PushL(terminal); + if (aData) + terminal->SetDataL(aData); + // correct cleanupstack + CleanupStack::Pop(2); + CleanupStack::PushL(terminal); + + AddRuleCallbackL(*terminal, iPreRuleCallback, aPreRule); + AddRuleCallbackL(*terminal, iPostRuleCallback, aPostRule); + + CleanupStack::Pop(); //terminal + return terminal; + } + + +/** Creates a new sub-rule, and makes it a child of a specified parent rule. + +This overload sets no rule callbacks. + +@return The new sub-rule node +@param aParentRule The rule to the new sub-rule shall be added as a child +@param aRuleType Rule type +@param aData Rule data reference. This is used with EExact and ESelect type rules to match actual text strings. +*/ +EXPORT_C CBNFNode& CBNFParser::NewComponentL(CBNFNode &aParentRule, TParserNodeTypes aRuleType, const TDesC& aData) +// Adds a new rule component to the given ParentRule. + { + return NewComponentL(aParentRule, aRuleType, aData.AllocL()); + } + +/** Creates a new sub-rule, and makes it a child of a specified parent rule. + +This overload sets rule callbacks. + +@return The new sub-rule node +@param aParentRule The rule to the new sub-rule shall be added as a child +@param aRuleType Rule type +@param aData Rule data pointer. This is used with EExact and ESelect type rules to match actual text strings. +@param aPreRule Function pointer to a pre-rule function that gets called before the parser starts processing this rule and its subtree. +@param aPostRule Function pointer to a post-rule function that gets called after the parser has processed this rule and its subtree. +*/ +EXPORT_C CBNFNode& CBNFParser::NewComponentL(CBNFNode &aParentRule, TParserNodeTypes aRuleType, HBufC* aData, TRuleCallback* aPreRule, TRuleCallback* aPostRule) + { + // take ownership of aData + CleanupStack::PushL(aData); + CBNFNode& terminal = REINTERPRET_CAST(CBNFNode&, aParentRule.AppendNodeL(aRuleType)); + AddRuleCallbackL(terminal, iPreRuleCallback, aPreRule); + AddRuleCallbackL(terminal, iPostRuleCallback, aPostRule); + + if (aData) + terminal.SetDataL(aData); + CleanupStack::Pop(); + + return terminal; + } + + +/** Creates a new reference rule node, and adds it as a child of the specified parent. + +Note that the function succeeds even if the target rule aRuleName does not yet exist. + +@return The new reference rule node +@param aRootRule Root node: the function needs this to find the target rule identified by aRuleName +@param aParentRule Parent rule to which to attach the new rule as a child +@param aRuleName The name of the rule that the new node refers to +*/ +EXPORT_C CBNFNode& CBNFParser::NewComponentL(CBNFNode* aRootRule, CBNFNode &aParentRule, const TDesC& aRuleName) + { + CBNFNode *terminalNode = (CBNFNode*)aRootRule->Attribute(iLUT.Des2IDL(aRuleName)); + if (terminalNode == NULL) + terminalNode = &NewRuleL(aRootRule, aRuleName, EIncomplete, NULL, NULL, NULL); + + CBNFNode& rule = REINTERPRET_CAST(CBNFNode&, aParentRule.AppendNodeL(EReference)); + CNoDeleteAttributeT* attributeNode = new (ELeave) CNoDeleteAttributeT(terminalNode); + CleanupStack::PushL(attributeNode); + rule.AddAttributeL(iReferenceString, attributeNode); + CleanupStack::Pop(); + + return rule; + } + +/** Adds an additional attribute to an existing rule node. + +For example, this is used with range rules, which specify the range boundaries using start and end attributes. + +@param aRule Rule node on which to set the attribute +@param aAttribute Attribute type +@param aInt Attribute value +*/ +EXPORT_C void CBNFParser::AddComponentAttributeL(CBNFNode& aRule, CBNFNodeAttributeType aAttribute, TInt aInt) +// Adds a restriction to a rule component, this is used for instance with Range restrictions (Start/End) + { + CNoDeleteAttributeT* aTIntAttribute = new (ELeave) CNoDeleteAttributeT(aInt); + CleanupStack::PushL(aTIntAttribute); + aRule.AddAttributeL(aAttribute, aTIntAttribute); + CleanupStack::Pop(); + } + +/** Inserts a mark to the current position of the stream being processed. + +Adding a mark is a very common callback operation before starting to process a rule, so the method is provided by the parser. + +@param aParser Parser processing the stream +*/ +EXPORT_C void CBNFParser::MarkCallback(CBNFParser& aParser) +// Provide a very common preaction callback to mark the input stream before the next rule attempts to parse it. + {// static + aParser.Mark(); // Mark can leave + } + + +// +// Data Provider access +/** Called by the data provider to add data for the parser to process. + +This implements MDataProviderObserver::ProcessDataL(). + +@param aData The data to process +*/ +EXPORT_C void CBNFParser::ProcessDataL(HBufC8& aData) +// Add new data as the input to the parser, ownership is taken of the aData. + { + HBufC* newData = HBufC::NewL(aData.Length()); + newData->Des().Copy(aData.Des()); + + iString.AddStringL(newData); + + ParseL(); + } + +/** Called by the data provider to report its status to its observer. + +This implements MDataProviderObserver::SetStatus(). + +@param aStatusCode Status code +*/ +EXPORT_C void CBNFParser::SetStatus(TInt aStatusCode) +// Notify the parser that there is no more (new) input data to be added/parsed. + { + if (aStatusCode == EPluginComplete) + { + // No more data will be pushed at us + // so do what we need to finish and set our + // status + iStringComplete = ETrue; + } + } + +EXPORT_C void CBNFParser::SetDocumentTypeL(const TDesC& /*aDocType*/) + { + } + +EXPORT_C void CBNFParser::SetDocumentTypeL(const TDesC&, const TDesC&) + { + } + +EXPORT_C void CBNFParser::SetDataExpected(TInt) + { + } + +EXPORT_C void CBNFParser::SetBaseUriL(const TDesC* /*aBaseUri*/) + { + } + +/** Notifies the parser that all the data has been passed in. + +It causes the parser to parse any of the input stream not already parsed. +*/ +EXPORT_C void CBNFParser::CommitL() + { + if (iStringComplete) + ParseL(); + } + +EXPORT_C CBNFNode* CBNFParser::TreeL() + { + return NULL; + } + +EXPORT_C void CBNFParser::StartConditional(TParserNodeTypes /*aRuleType*/) + { + } + +EXPORT_C void CBNFParser::EndConditional(TParserNodeTypes /*aRuleType*/, TBool /*aSuccess*/) + { + } + + +// Provide an implementation for the interface class +EXPORT_C void CBNFParser::MDataProviderObserverReserved1() + { + User::Panic(_L("Reserved"),KErrNotSupported); + } + +EXPORT_C void CBNFParser::MDataProviderObserverReserved2() + { + User::Panic(_L("Reserved"),KErrNotSupported); + }