applayerprotocols/wapbase/bnf/CBNFParser.cpp
changeset 0 b16258d2340f
--- /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);
+	}