--- /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 <cbnfparser.h>
+
+#include <cnodeleteattribute.h>
+#include <attrlut.h>
+#include <estatus.h>
+#include <e32base.h>
+
+#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<CBNFNode*>* attributeNode = REINTERPRET_CAST(CNoDeleteAttributeT<CBNFNode*>*, 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<TInt>* rangeStartAttribute = REINTERPRET_CAST(CNoDeleteAttributeT<TInt>*, aRule.Attribute(iRangeStart));
+ TInt rangeStart;
+ if (rangeStartAttribute)
+ rangeStart = rangeStartAttribute->Attribute();
+ else
+ rangeStart = 0;
+
+ CNoDeleteAttributeT<TInt>* rangeEndAttribute = REINTERPRET_CAST(CNoDeleteAttributeT<TInt>*, 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<TInt>* countAttribute = REINTERPRET_CAST(CNoDeleteAttributeT<TInt>*, aRule.Attribute(iMoreCount));
+ CNoDeleteAttributeT<TInt>* maxCountAttribute = REINTERPRET_CAST(CNoDeleteAttributeT<TInt>*, aRule.Attribute(iMoreMaximum));
+
+ if (iSubRuleMatched)
+ countAttribute->SetAttribute(countAttribute->Attribute()+1);
+ else
+ {
+ performedMatch = ETrue;
+ CNoDeleteAttributeT<TInt>* minCountAttribute = REINTERPRET_CAST(CNoDeleteAttributeT<TInt>*, 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<TInt>* countAttribute = new (ELeave) CNoDeleteAttributeT<TInt>(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<TRuleCallback*>* preRuleAttribute;
+ if ((preRuleAttribute= REINTERPRET_CAST(CNoDeleteAttributeT<TRuleCallback*>*, 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<TRuleCallback*>* postRuleAttribute;
+ if ((postRuleAttribute = REINTERPRET_CAST(CNoDeleteAttributeT<TRuleCallback*>*, 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<TRuleCallback*>* ruleAttribute = new (ELeave) CNoDeleteAttributeT<TRuleCallback*>(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<CBNFNode*>* attributeNode = new (ELeave) CNoDeleteAttributeT<CBNFNode*>(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<CBNFNode*>* attributeNode = new (ELeave) CNoDeleteAttributeT<CBNFNode*>(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<TInt>* aTIntAttribute = new (ELeave) CNoDeleteAttributeT<TInt>(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);
+ }