crashanalysercmd/PerfToolsSharedLibraries/Engine/SymBuildParsingLib/Token/SymTokenBalancer.cs
changeset 0 818e61de6cd1
equal deleted inserted replaced
-1:000000000000 0:818e61de6cd1
       
     1 /*
       
     2 * Copyright (c) 2004-2008 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 using System;
       
    19 using System.Text;
       
    20 using System.Collections;
       
    21 using SymBuildParsingLib.Tree;
       
    22 using SymbianTree;
       
    23 
       
    24 namespace SymBuildParsingLib.Token
       
    25 {
       
    26 	public class SymTokenBalancer
       
    27 	{
       
    28 		#region Observer interface
       
    29 		public delegate void LevelsBalancedEventHandler();
       
    30 		public delegate void LevelsImbalancedEventHandler();
       
    31 		public delegate void LevelChangeEventHandler( int aLevelCount, SymNode aOldLevel, SymNode aNewLevel );
       
    32 		#endregion
       
    33 
       
    34 		#region Events
       
    35 		public event LevelChangeEventHandler EventLevelStarted;
       
    36 		public event LevelChangeEventHandler EventLevelFinished;
       
    37 		public event LevelsBalancedEventHandler EventLevelsBalanced;
       
    38 		public event LevelsImbalancedEventHandler EventLevelsImbalanced;
       
    39 		#endregion
       
    40 		
       
    41 		#region Constructors & destructor
       
    42 		public SymTokenBalancer()
       
    43 		{
       
    44 			Reset();
       
    45 			System.Diagnostics.Debug.IndentSize = 1;
       
    46 		}
       
    47 		#endregion
       
    48 
       
    49 		#region API
       
    50 		public void RegisterBalancerTokens()
       
    51 		{
       
    52 			RegisterBalancerTokens( false );
       
    53 		}
       
    54 
       
    55 		public virtual void RegisterBalancerTokens( bool aEmitLevelZeroBrackets )
       
    56 		{
       
    57 			// These are the important tokens relating to function arguments
       
    58 			SymToken bracketTokenOpening = new SymToken( "(", SymToken.TClass.EClassSymbol, SymToken.TType.ETypeUnidentified );
       
    59 			SymToken bracketTokenClosing = new SymToken( ")", SymToken.TClass.EClassSymbol, SymToken.TType.ETypeUnidentified );
       
    60 
       
    61 			// When parsing a function name and arguments, we want to start a new level when we see the first opening
       
    62 			// brace, but we don't want to emit the token.
       
    63 			RegisterOpeningToken( bracketTokenOpening, bracketTokenClosing, aEmitLevelZeroBrackets, true, TLevelExpectations.ELevelExpectationsAtLevel, 0, TAssociatedBehaviour.EBehaviourRemoveReduntantBracketing );
       
    64 			RegisterClosingToken( bracketTokenClosing, bracketTokenOpening, aEmitLevelZeroBrackets, true, TLevelExpectations.ELevelExpectationsAtLevel, 0, TAssociatedBehaviour.EBehaviourRemoveReduntantBracketing );
       
    65 			
       
    66 			// For other brackets, we want to reduce the complexity by removing any redundant entries
       
    67 			RegisterOpeningToken( bracketTokenOpening, bracketTokenClosing, true, true, TLevelExpectations.ELevelExpectationsAboveLevelNumber, 0, TAssociatedBehaviour.EBehaviourRemoveReduntantBracketing );
       
    68 			RegisterClosingToken( bracketTokenClosing, bracketTokenOpening, true, true, TLevelExpectations.ELevelExpectationsAboveLevelNumber, 0, TAssociatedBehaviour.EBehaviourRemoveReduntantBracketing );
       
    69 		}
       
    70 
       
    71 		public virtual bool OfferToken( SymToken aToken )
       
    72 		{
       
    73 			bool consumed = false;
       
    74 			int currentLevelNumber = CurrentLevelNumber;
       
    75 			SymTokenBalancerMatchCriteria tokenExtendedInfo;
       
    76 
       
    77 			// Check for bracket matches
       
    78 			if	( IsOpeningTokenMatch( aToken, out tokenExtendedInfo, currentLevelNumber ) )
       
    79 			{
       
    80 				LevelStarted( aToken, tokenExtendedInfo );
       
    81 				consumed = true;
       
    82 			}
       
    83 			else if ( IsClosingTokenMatch( aToken, out tokenExtendedInfo, currentLevelNumber ) )
       
    84 			{
       
    85 				LevelFinished( aToken, tokenExtendedInfo );
       
    86 				consumed = true;
       
    87 			}
       
    88 
       
    89 			// Always consume the token if it didn't match
       
    90 			if	( ! consumed )
       
    91 			{
       
    92 				AddToCurrentLevel( aToken );
       
    93 				consumed = true;
       
    94 			}
       
    95 			//
       
    96 			return consumed;
       
    97 		}
       
    98 
       
    99 		public virtual void Reset()
       
   100 		{
       
   101 			iTree = new SymTokenBalancerDocument();
       
   102 		}
       
   103 		#endregion
       
   104 
       
   105 		#region API - registration
       
   106 		public void RegisterOpeningToken( SymToken aToken, SymToken aDiametricToken, bool aEmit, bool aStartsNewLevel, TLevelExpectations aLevelExpectations, int aAssociatedLevel, TAssociatedBehaviour aBehaviour  )
       
   107 		{
       
   108 			SymTokenBalancerMatchCriteria criteria = new SymTokenBalancerMatchCriteria( aDiametricToken, aEmit, aStartsNewLevel, aLevelExpectations, aAssociatedLevel, aBehaviour );
       
   109 			RegisterOpeningToken( aToken, criteria );
       
   110 		}
       
   111 
       
   112 		public void RegisterOpeningToken( SymToken aToken, SymTokenBalancerMatchCriteria aCriteria )
       
   113 		{
       
   114 			SymToken copy = new SymToken( aToken );
       
   115 			copy.Tag = aCriteria;
       
   116 			//
       
   117 			if	( IsTokenExactMatch( copy, iOpeningTokens ) == false )
       
   118 			{
       
   119 				iOpeningTokens.Append( copy );
       
   120 			}
       
   121 		}
       
   122 
       
   123 		public void RegisterClosingToken( SymToken aToken, SymToken aDiametricToken, bool aEmit, bool aStartsNewLevel, TLevelExpectations aLevelExpectations, int aAssociatedLevel, TAssociatedBehaviour aBehaviour )
       
   124 		{
       
   125 			SymTokenBalancerMatchCriteria criteria = new SymTokenBalancerMatchCriteria( aDiametricToken, aEmit, aStartsNewLevel, aLevelExpectations, aAssociatedLevel, aBehaviour );
       
   126 			RegisterClosingToken( aToken, criteria );
       
   127 		}
       
   128 
       
   129         public void RegisterClosingToken( SymToken aToken, SymTokenBalancerMatchCriteria aCriteria )
       
   130 		{
       
   131 			SymToken copy = new SymToken( aToken );
       
   132 			copy.Tag = aCriteria;
       
   133 			//
       
   134 			if	( IsTokenExactMatch( copy, iClosingTokens ) == false )
       
   135 			{
       
   136 				iClosingTokens.Append( copy );
       
   137 			}
       
   138 		}
       
   139 		#endregion
       
   140 
       
   141 		#region Properties - level related
       
   142 		public int CurrentLevelNumber
       
   143 		{
       
   144 			get
       
   145 			{
       
   146 				int depth = iTree.CurrentNode.Depth;
       
   147 				return depth;
       
   148 			}
       
   149 		}
       
   150 
       
   151 		public SymNode CurrentNode
       
   152 		{
       
   153 			get { return iTree.CurrentNode; }
       
   154 		}
       
   155 
       
   156 		public SymTokenBalancerDocument DocumentTree
       
   157 		{
       
   158 			get { return iTree; }
       
   159 		}
       
   160 		#endregion
       
   161 
       
   162 		#region Notification framework
       
   163 		protected virtual void NotifyEventLevelStarted( int aLevelCount, SymNode aOldLevel, SymNode aNewLevel )
       
   164 		{
       
   165 			if	( EventLevelStarted != null )
       
   166 			{
       
   167 				EventLevelStarted( aLevelCount, aOldLevel, aNewLevel );
       
   168 			}
       
   169 		}
       
   170 
       
   171 		protected virtual void NotifyEventLevelFinished( int aLevelCount, SymNode aOldLevel, SymNode aNewLevel )
       
   172 		{
       
   173 			if	( EventLevelFinished != null )
       
   174 			{
       
   175 				EventLevelFinished( aLevelCount, aOldLevel, aNewLevel );
       
   176 			}
       
   177 		}
       
   178 
       
   179 		protected virtual void NotifyEventLevelsImbalanced()
       
   180 		{
       
   181 			if	( EventLevelsImbalanced != null )
       
   182 			{
       
   183 				EventLevelsImbalanced();
       
   184 			}
       
   185 		}
       
   186 		#endregion
       
   187 
       
   188 		#region Utility methods
       
   189 		protected bool IsTokenExactMatch( SymToken aToken, SymTokenContainer aContainerToSearch )
       
   190 		{
       
   191 			bool ret = false;
       
   192 			//
       
   193 			foreach( SymToken t in aContainerToSearch )
       
   194 			{
       
   195 				if	( t.Equals( aToken ) )
       
   196 				{
       
   197 					if	( aToken.Tag != null && t.Tag != null )
       
   198 					{
       
   199 						if	( ( aToken.Tag is SymTokenBalancerMatchCriteria ) && ( t.Tag is SymTokenBalancerMatchCriteria ) )
       
   200 						{
       
   201 							SymTokenBalancerMatchCriteria extendedInfo1 = (SymTokenBalancerMatchCriteria) aToken.Tag;
       
   202 							SymTokenBalancerMatchCriteria extendedInfo2 = (SymTokenBalancerMatchCriteria) t.Tag;
       
   203 							//
       
   204 							if	( extendedInfo1.Equals( extendedInfo2 ) )
       
   205 							{
       
   206 								ret = true;
       
   207 								break;
       
   208 							}
       
   209 						}
       
   210 					}
       
   211 				}
       
   212 			}
       
   213 			//
       
   214 			return ret;
       
   215 		}
       
   216 
       
   217 		protected bool IsOpeningTokenMatch( SymToken aToken, out SymTokenBalancerMatchCriteria aCriteria, int aLevelNumber )
       
   218 		{
       
   219 			aCriteria = null;
       
   220 			bool matchFound = false;
       
   221 			//
       
   222 			int index = iOpeningTokens.IndexOf( aToken );
       
   223 			while( index >= 0 && matchFound == false )
       
   224 			{
       
   225 				SymToken token = iOpeningTokens[ index ];
       
   226 				System.Diagnostics.Debug.Assert ( token.Tag != null && token.Tag is SymTokenBalancerMatchCriteria );
       
   227 				SymTokenBalancerMatchCriteria criteria = (SymTokenBalancerMatchCriteria) token.Tag;
       
   228 
       
   229 				if	( criteria.Matches( aLevelNumber ) )
       
   230 				{
       
   231 					aCriteria = criteria;
       
   232 					matchFound = true;
       
   233 				}
       
   234 				else
       
   235 				{
       
   236 					index = iOpeningTokens.IndexOf( aToken, index+1 );
       
   237 				}
       
   238 			}
       
   239 
       
   240 			return matchFound;
       
   241 		}
       
   242 
       
   243 		protected bool IsClosingTokenMatch( SymToken aToken, out SymTokenBalancerMatchCriteria aCriteria, int aLevelNumber )
       
   244 		{
       
   245 			aCriteria = null;
       
   246 			bool matchFound = false;
       
   247 			//
       
   248 			int index = iClosingTokens.IndexOf( aToken );
       
   249 			while( index >= 0 && matchFound == false )
       
   250 			{
       
   251 				SymToken token = iClosingTokens[ index ];
       
   252 				System.Diagnostics.Debug.Assert ( token.Tag != null && token.Tag is SymTokenBalancerMatchCriteria );
       
   253 				SymTokenBalancerMatchCriteria criteria = (SymTokenBalancerMatchCriteria) token.Tag;
       
   254 
       
   255 				if	( criteria.Matches( aLevelNumber ) )
       
   256 				{
       
   257 					aCriteria = criteria;
       
   258 					matchFound = true;
       
   259 				}
       
   260 				else
       
   261 				{
       
   262 					index = iClosingTokens.IndexOf( aToken, index+1 );
       
   263 				}
       
   264 			}
       
   265 
       
   266 			return matchFound;
       
   267 		}
       
   268 
       
   269 		protected static int CountTokenByType( SymNode aNodeWithChildren, SymToken.TClass aClass )
       
   270 		{
       
   271 			int count = 0;
       
   272 			//
       
   273 			foreach( SymNode n in aNodeWithChildren )
       
   274 			{
       
   275 				bool isNodeToken = ( n is SymNodeToken );
       
   276 				//
       
   277 				if	( isNodeToken )
       
   278 				{
       
   279 					bool isSpecial = ( ( n is SymTokenBalancerNode ) || ( n is SymTokenBalancerNodeEmittedElement ) );
       
   280 					//
       
   281 					if	( isSpecial == false )
       
   282 					{
       
   283 						SymToken t = ((SymNodeToken) n).Token;
       
   284 						//
       
   285 						if	( t.Class == aClass )
       
   286 						{
       
   287 							++count;
       
   288 						}
       
   289 					}
       
   290 				}
       
   291 			}
       
   292 			//
       
   293 			return count;
       
   294 		}
       
   295 
       
   296 		protected bool LevelCanBeMergedWithParent( SymTokenBalancerMarkerLevelNode aLevelNode )
       
   297 		{
       
   298 			#region Example
       
   299 			// We can replace the opening bracket, the level marker and the closing bracket
       
   300 			// with the level marker's child.
       
   301 			//
       
   302 			// E.g. 
       
   303 			// ( = opening bracket
       
   304 			// * = level marker
       
   305 			// ) = closing bracket
       
   306 			// V = 'real' node value
       
   307 			//
       
   308 			// This:
       
   309 			//
       
   310 			//             ( -- * -- )
       
   311 			//                  |
       
   312 			//                  V
       
   313 			// 
       
   314 			// Can become:
       
   315 			//
       
   316 			//                  V
       
   317 			//
       
   318 			//
       
   319 			// Or this:
       
   320 			//
       
   321 			//             ( -- * -- )
       
   322 			//                  |
       
   323 			//             [ -- * -- ]
       
   324 			//					|
       
   325 			//                  V
       
   326 			// 
       
   327 			// Can become:
       
   328 			//
       
   329 			//             [ -- * -- ]
       
   330 			//					|
       
   331 			//                  V
       
   332 			//
       
   333 			#endregion
       
   334 			System.Diagnostics.Debug.Assert( aLevelNode.HasPrevious && aLevelNode.HasNext );
       
   335 			System.Diagnostics.Debug.Assert( aLevelNode.Previous is SymTokenBalancerNodeEmittedElement && aLevelNode.Next is SymTokenBalancerNodeEmittedElement );
       
   336 			//
       
   337 			bool ret = false;
       
   338 			//
       
   339 			SymTokenBalancerNodeEmittedElement previous = (SymTokenBalancerNodeEmittedElement) aLevelNode.Previous;
       
   340 			SymTokenBalancerNodeEmittedElement next = (SymTokenBalancerNodeEmittedElement) aLevelNode.Next;
       
   341 
       
   342 			// We should be able to remove these brackets, providing they are diametrically oposites.
       
   343 			SymTokenBalancerMatchCriteria matchInfo;
       
   344 			if	( IsOpeningTokenMatch( previous.Token, out matchInfo, CurrentLevelNumber ) )
       
   345 			{
       
   346 				// We've now got the match info for this opening token. We can compare the
       
   347 				// match info's diametric token against the closing token to check that they 
       
   348 				// really are equal and oposite.
       
   349 				if	( matchInfo.DiametricToken.Equals( next.Token ) )
       
   350 				{
       
   351 					// Check whether the children are suitable for coalescing
       
   352 					int grandChildCount = aLevelNode.ChildCount;
       
   353 					int numberOfWhiteSpaceGrandChildren = CountTokenByType( aLevelNode, SymToken.TClass.EClassWhiteSpace );
       
   354 					int nonWhiteSpaceGrandChildrenCount = grandChildCount - numberOfWhiteSpaceGrandChildren;
       
   355 
       
   356 					if	( nonWhiteSpaceGrandChildrenCount == 1 )
       
   357 					{
       
   358 						// If there is just a single non-whitespace token then we are able to
       
   359 						// coalesce this branch
       
   360 						ret = true;
       
   361 					}
       
   362 					else if ( nonWhiteSpaceGrandChildrenCount == 3 )
       
   363 					{
       
   364 						// Branch contains several non-whitespace children. Must check further
       
   365 						// to see if they are simply bracketed regions themselves
       
   366 						object levelObject = aLevelNode.ChildByType( typeof( SymTokenBalancerMarkerLevelNode ) );
       
   367 						if	( levelObject != null )
       
   368 						{
       
   369 							SymTokenBalancerMarkerLevelNode childLevel = (SymTokenBalancerMarkerLevelNode) levelObject;
       
   370 							//
       
   371 							if	( childLevel.HasPrevious && childLevel.HasNext )
       
   372 							{
       
   373 								ret = ( childLevel.Previous is SymTokenBalancerNodeEmittedElement && childLevel.Next is SymTokenBalancerNodeEmittedElement );
       
   374 							}
       
   375 						}
       
   376 						else
       
   377 						{
       
   378 							ret = true;
       
   379 						}
       
   380 					}
       
   381 				}
       
   382 			}
       
   383 			//
       
   384 			return ret;
       
   385 		}
       
   386 
       
   387 		protected void SimplifyLevel( SymTokenBalancerMarkerLevelNode aLevel )
       
   388 		{
       
   389 			System.Diagnostics.Debug.Assert( aLevel.IsRoot == false && aLevel.HasParent );
       
   390 			SymNode parent = aLevel.Parent;
       
   391 			int levelNumber = parent.Depth;
       
   392 			//
       
   393 			int childCount = parent.ChildCount;
       
   394 			while( --childCount >= 0 )
       
   395 			{
       
   396 				SymNode possibleLevelNode = parent[ childCount ];
       
   397 
       
   398 				// We're looking to remove redundant bracketing from either side of the level
       
   399 				// node. First check if we have a level node...
       
   400 				if	( possibleLevelNode is SymTokenBalancerMarkerLevelNode )
       
   401 				{
       
   402 					// Then check whether it has a previous and a next node. These should
       
   403 					// be the SymTokenBalancerNodeEmittedElement nodes
       
   404 					if	( possibleLevelNode.HasPrevious && possibleLevelNode.HasNext )
       
   405 					{
       
   406 						if	( possibleLevelNode.Previous is SymTokenBalancerNodeEmittedElement && possibleLevelNode.Next is SymTokenBalancerNodeEmittedElement )
       
   407 						{
       
   408 							if	( LevelCanBeMergedWithParent( possibleLevelNode as SymTokenBalancerMarkerLevelNode ) )
       
   409 							{
       
   410 								SymTokenBalancerNodeEmittedElement previous = (SymTokenBalancerNodeEmittedElement) possibleLevelNode.Previous;
       
   411 								SymTokenBalancerNodeEmittedElement next = (SymTokenBalancerNodeEmittedElement) possibleLevelNode.Next;
       
   412 
       
   413 								// Insert value node prior to previous node (which is the opening bracket token).
       
   414 								parent.InsertChildrenFrom( possibleLevelNode, previous.Previous );
       
   415 
       
   416 								// Remove the opening bracket token
       
   417 								previous.Remove();
       
   418 
       
   419 								// Remove the level marker token
       
   420 								possibleLevelNode.Remove();
       
   421 
       
   422 								// Remove the closing bracket token.
       
   423 								next.Remove();
       
   424 							}
       
   425 						}
       
   426 					}
       
   427 				}
       
   428 			}
       
   429 		}
       
   430 		#endregion
       
   431 
       
   432 		#region Internal level manipulation methods
       
   433 		protected virtual void LevelStarted( SymToken aToken, SymTokenBalancerMatchCriteria aMatchCriteria )
       
   434 		{
       
   435 			System.Diagnostics.Debug.Write( System.Environment.NewLine + aToken.Value );
       
   436 
       
   437 			// Always store the node element so that we can balance brackets
       
   438 			SymTokenBalancerNodeEmittedElement node = new SymTokenBalancerNodeEmittedElement( aToken, aMatchCriteria );
       
   439 			iTree.CurrentNode.Add( node );
       
   440 
       
   441 			// Store the token (with the level) so we can check for open/close mis-matches
       
   442 			SymTokenBalancerMarkerLevelNode levelNode = new SymTokenBalancerMarkerLevelNode( aMatchCriteria );
       
   443 			iTree.CurrentNode.Add( levelNode );
       
   444 
       
   445 			SymNode oldLevel = iTree.CurrentNode;
       
   446 			SymNode newLevel = levelNode;
       
   447 			NotifyEventLevelStarted( CurrentLevelNumber, oldLevel, newLevel  );
       
   448 
       
   449 			iTree.CurrentNode = levelNode;
       
   450 		}
       
   451 
       
   452 		protected virtual void LevelFinished( SymToken aToken, SymTokenBalancerMatchCriteria aMatchCriteria )
       
   453 		{
       
   454 			#region Example
       
   455 
       
   456 			// #define TEST1((( B )+( C ))+(E)) 
       
   457 
       
   458 			#region Key
       
   459 			// |y| = level y
       
   460 			// [x] = token of value 'x'
       
   461 			// [*] = level marker node
       
   462 			// [@] = (current) level marker node
       
   463 			// [,] = argument node
       
   464 			// [(] = opening level emitted token node
       
   465 			// [)] = closing level emitted token node
       
   466 			#endregion
       
   467 
       
   468 			#region 1) First wave of opening level tokens processed...
       
   469 			//
       
   470 			//  |0|                    [ROOT]
       
   471 			//                           |
       
   472 			//  |1|          [TEST] [(] [*]
       
   473 			//                           |
       
   474 			//  |2|                 [(] [*]
       
   475 			//                           |
       
   476 			//  |3|                 [(] [@]
       
   477 			//                           |
       
   478 			//  |4|                      B
       
   479 			//
       
   480 			#endregion
       
   481 
       
   482 			#region 2) Add closing level token to level |3|, which means that we can now
       
   483 			//    attempt to simplify level |4|. Level |4| does not contain any child
       
   484 			//    level nodes, so there is nothing to do here.
       
   485 			//
       
   486 			//  |0|                    [ROOT]
       
   487 			//                           |
       
   488 			//  |1|          [TEST] [(] [*]
       
   489 			//                           |
       
   490 			//  |2|                 [(] [@]
       
   491 			//                           |
       
   492 			//  |3|                 [(] [*] [)]
       
   493 			//                           |
       
   494 			//  |4|                 [ ] [B] [ ]
       
   495 			//
       
   496 			#endregion
       
   497 
       
   498 			#region 3) Add plus symbol. This obviously becomes a child of the current node,
       
   499 			//    i.e. a child of level |2|.
       
   500 			//
       
   501 			//  |0|                            [ROOT]
       
   502 			//                                   |
       
   503 			//  |1|                  [TEST] [(] [*]
       
   504 			//                                   |
       
   505 			//  |2|                         [(] [@]
       
   506 			//                                   |
       
   507 			//  |3|                 [(] [*] [)] [+]
       
   508 			//                           |
       
   509 			//  |4|                 [ ] [B] [ ]
       
   510 			//
       
   511 			#endregion
       
   512 
       
   513 			#region 4) Start new opening level node on level |3|. The newly added level node
       
   514 			//    on level |3| becomes the current node.
       
   515 			//
       
   516 			//  |0|                            [ROOT]
       
   517 			//                                   |
       
   518 			//  |1|                  [TEST] [(] [*]
       
   519 			//                                   |
       
   520 			//  |2|                         [(] [*]
       
   521 			//                                   |
       
   522 			//  |3|                 [(] [*] [)] [+] [(] [@] 
       
   523 			//                           |               |
       
   524 			//  |4|                 [ ] [B] [ ]
       
   525 			//
       
   526 			#endregion
       
   527 		
       
   528 			#region 5) Add the tokens near the 'C' to level |4|
       
   529 			//
       
   530 			//  |0|                            [ROOT]
       
   531 			//                                   |
       
   532 			//  |1|                  [TEST] [(] [*]
       
   533 			//                                   |
       
   534 			//  |2|                         [(] [*]
       
   535 			//                                   |
       
   536 			//  |3|                 [(] [*] [)] [+] [(] [@] 
       
   537 			//                           |               |
       
   538 			//  |4|                 [ ] [B] [ ]     [ ] [C] [ ]
       
   539 			//
       
   540 			#endregion
       
   541 
       
   542 			#region 6) Add closing level token to level |3|, which means that we can now
       
   543 			//    attempt to simplify level |4|, this time the [C] branch.
       
   544 			//    Since this branch does not contain any sub-level nodes, there is nothing 
       
   545 			//    to be done and therefore levels |3| and |4| remain unchanged. 
       
   546 			//    The level node at level |2| becomes the current node.
       
   547 			//
       
   548 			//  |0|                            [ROOT]
       
   549 			//                                   |
       
   550 			//  |1|                  [TEST] [(] [*]
       
   551 			//                                   |
       
   552 			//  |2|                         [(] [@]
       
   553 			//                                   |
       
   554 			//  |3|                 [(] [*] [)] [+] [(] [*] [)]
       
   555 			//                           |               |
       
   556 			//  |4|                 [ ] [B] [ ]     [ ] [C] [ ]
       
   557 			//
       
   558 			#endregion
       
   559 
       
   560 			#region 7a) Add closing level token to level |2|, which means that we can now
       
   561 			//     attempt to simplify level |3|.
       
   562 			//
       
   563 			//  |0|                            [ROOT]
       
   564 			//                                   |
       
   565 			//  |1|                  [TEST] [(] [*]
       
   566 			//                                   |
       
   567 			//  |2|                         [(] [@] [)]
       
   568 			//                                   |
       
   569 			//  |3|                 [(] [*] [)] [+] [(] [*] [)]
       
   570 			//                           |               |
       
   571 			//  |4|                 [ ] [B] [ ]     [ ] [C] [ ]
       
   572 			//
       
   573 			#endregion
       
   574 
       
   575 			#region 7b) We iterate through all the child level nodes of level |3| looking
       
   576 			//     to see if any of their children are simple enough to merge up into level
       
   577 			//     |3| itself. There are two level nodes in level |3| and both contain
       
   578 			//     children that are considered simple enough to merge up. This is because
       
   579 			//     they contain only a single non-whitespace node so we can simplify the level by
       
   580 			//     merging [B] from level |4| into level |3|. Likewise for [C].
       
   581 			//
       
   582 			//     This means that the bracketry on level |3| is redundant since level 
       
   583 			//     |4| contains two sets of only a single non-whitespace token. Level |4|
       
   584 			//     is therefore entirely removed.
       
   585 			//
       
   586 			//     The node at level |1| becomes the current node now.
       
   587 			//
       
   588 			//  |0|                            [ROOT]
       
   589 			//                                   |
       
   590 			//  |1|                  [TEST] [(] [@]
       
   591 			//                                   |
       
   592 			//  |2|                         [(] [*] [)]
       
   593 			//                                   |
       
   594 			//  |3|                 [ ] [B] [ ] [+] [ ] [C] [ ]
       
   595 			//
       
   596 			#endregion
       
   597 
       
   598 			#region 8) Add the plus symbol to level |2|. Then we start a new level
       
   599 			//    as a result of adding the opening bracket prior to 'E.'
       
   600 			//    This new level node at level |2| now becomes the current node.
       
   601 			//
       
   602 			//  |0|                                 [ROOT]
       
   603 			//                                         |
       
   604 			//  |1|                  [TEST]   [(]     [*]
       
   605 			//                                         |
       
   606 			//  |2|             [(] [*] [)]           [+] [(] [@]
       
   607 			//                       |                         |
       
   608 			//  |3|     [ ] [B] [ ] [+] [ ] [C] [ ]
       
   609 			//
       
   610 			#endregion
       
   611 
       
   612 			#region 9) Now add the 'E' token to level |3|.
       
   613 			//
       
   614 			//  |0|                                 [ROOT]
       
   615 			//                                         |
       
   616 			//  |1|                  [TEST]   [(]     [*]
       
   617 			//                                         |
       
   618 			//  |2|             [(] [*] [)]           [+] [(] [@]
       
   619 			//                       |                         |
       
   620 			//  |3|     [ ] [B] [ ] [+] [ ] [C] [ ]           [E]
       
   621 			#endregion
       
   622 
       
   623 			#region 10) We then add the closing bracket to level |2| which means
       
   624 			//  that we can attempt to simplify level |3|'s 'E' branch. There's nothing
       
   625 			//  to do though, since it doesn't contain any child level nodes.
       
   626 			//  The level node at level |1| again becomes current.
       
   627 			//
       
   628 			//  |0|                                 [ROOT]
       
   629 			//                                         |
       
   630 			//  |1|                  [TEST]   [(]     [@]
       
   631 			//                                         |
       
   632 			//  |2|             [(] [*] [)]           [+] [(] [*] [)]
       
   633 			//                       |                         |
       
   634 			//  |3|     [ ] [B] [ ] [+] [ ] [C] [ ]           [E]
       
   635 			#endregion
       
   636 
       
   637 			#region 11a) We then add the closing bracket to level |1| which means
       
   638 			//  that we can attempt to simplify level |2| entirely. This is the
       
   639 			//  situation prior to simplification.
       
   640 			//
       
   641 			//  |0|                                 [ROOT]
       
   642 			//                                         |
       
   643 			//  |1|                  [TEST]   [(]     [@] [)]
       
   644 			//                                         |
       
   645 			//  |2|             [(] [*] [)]           [+] [(] [*] [)]
       
   646 			//                       |                         |
       
   647 			//  |3|     [ ] [B] [ ] [+] [ ] [C] [ ]           [E]
       
   648 			#endregion
       
   649 
       
   650 			#region 11b) The two level nodes have been taged as *1 and *2 to make it
       
   651 			//  easier to explain the process. First we attempt to simplify level *1.
       
   652 			//  However, since its children consist of more than a single non-whitespace 
       
   653 			//  token, we cannot make level |3|'s " B + C " branch as a replacement
       
   654 			//  for the bracket *1 tokens. Therefore this remains unchanged
       
   655 			//  
       
   656 			//
       
   657 			//  |0|                                [ROOT]
       
   658 			//                                        |
       
   659 			//  |1|                  [TEST]   [(]    [@]     [)]
       
   660 			//                                        |
       
   661 			//  |2|            [(] [*1] [)]          [+] [(] [*2] [)]
       
   662 			//                       |                         |
       
   663 			//  |3|     [ ] [B] [ ] [+] [ ] [C] [ ]           [E]
       
   664 			#endregion
       
   665 			
       
   666 			#region 11c) The level *2 node, however, contains only a single non-whitespace
       
   667 			//  child token, so it can be simplified. The level *2 node is replaced by
       
   668 			//  its child (E).
       
   669 			//
       
   670 			// The final tree looks like this, with the root as the current node once more:
       
   671 			//  
       
   672 			//
       
   673 			//  |0|                                 [@ROOT@]
       
   674 			//                                         |
       
   675 			//  |1|        [TEST] [(]                 [*]                         [)]
       
   676 			//                                         |
       
   677 			//  |2|                   [(]             [*]             [)] [+] [E]
       
   678 			//                                         |               
       
   679 			//  |3|                       [ ] [B] [ ] [+] [ ] [C] [ ]   
       
   680 			#endregion
       
   681 			
       
   682 			#endregion
       
   683 
       
   684 			System.Diagnostics.Debug.Write( aToken.Value );
       
   685 			System.Diagnostics.Debug.WriteLine( " " );
       
   686 
       
   687 			// First of all, check if the current node has a parent. If we're at the root
       
   688 			// node and we see a closing token, then we've got an imbalanced stack.
       
   689 			if	( iTree.CurrentNode.IsRoot )
       
   690 			{
       
   691 				NotifyEventLevelsImbalanced();
       
   692 			}
       
   693 			else
       
   694 			{
       
   695 				// We expect the parent to be a level node
       
   696 				System.Diagnostics.Debug.Assert( iTree.CurrentNode is SymTokenBalancerMarkerLevelNode );
       
   697 
       
   698 				// Notify that we're about to change levels
       
   699 				SymTokenBalancerMarkerLevelNode currentLevel = (SymTokenBalancerMarkerLevelNode) iTree.CurrentNode;
       
   700 				SymNode newLevel = currentLevel.Parent;
       
   701 				
       
   702 				// The new level should not be null in this case
       
   703 				System.Diagnostics.Debug.Assert( newLevel != null );
       
   704 
       
   705 				// Check whether the closing token type is the same type as was used to start
       
   706 				// the level. E.g. for this case is "([ANDMORE)]" which has a mis-match
       
   707 				// between the opening and closing braces on each level. We can't simplify this
       
   708 				// during the 'end level behaviour' stage.
       
   709 				bool levelsBalanced = currentLevel.MatchCriteria.DiametricToken.Equals( aToken );
       
   710 
       
   711 				// Switch levels
       
   712 				iTree.CurrentNode = newLevel;
       
   713 
       
   714 				// We have to refetch up-to-date match info, since we've changed levels, and the match
       
   715 				// info that was used to enter this method is associated with the previous level
       
   716 				// (not the new level number, which is now one less).
       
   717 				SymTokenBalancerMatchCriteria matchCriteria;
       
   718 				if	( IsClosingTokenMatch( aToken, out matchCriteria, CurrentLevelNumber ) == false )
       
   719 				{
       
   720 					matchCriteria = aMatchCriteria;
       
   721 				}
       
   722 
       
   723 				// Always store the node element so that we can balance brackets
       
   724 				SymTokenBalancerNodeEmittedElement node = new SymTokenBalancerNodeEmittedElement( aToken, matchCriteria );
       
   725 				iTree.CurrentNode.Add( node );
       
   726 
       
   727 				// We have finished the current level. E.g. see step 6. Need to simplify level |2|, where possible.
       
   728 				PerformEndLevelBehaviour( currentLevel );
       
   729 
       
   730 				if	( levelsBalanced )
       
   731 				{
       
   732 					// Notify that we've finished some level
       
   733 					NotifyEventLevelFinished( CurrentLevelNumber, currentLevel, newLevel  );
       
   734 				}
       
   735 				else
       
   736 				{
       
   737 					// Imbalance
       
   738 					NotifyEventLevelsImbalanced();
       
   739 				}
       
   740 			}
       
   741 		}
       
   742 
       
   743 		protected virtual void AddToCurrentLevel( SymToken aToken )
       
   744 		{
       
   745 			System.Diagnostics.Debug.Write( aToken.Value );
       
   746 
       
   747 			SymNodeToken node = new SymNodeToken( aToken );
       
   748 			iTree.CurrentNode.Add( node );
       
   749 		}
       
   750 
       
   751 		#endregion
       
   752 
       
   753 		#region End level behaviour related
       
   754 		protected void PerformEndLevelBehaviour( SymTokenBalancerMarkerLevelNode aLevel )
       
   755 		{
       
   756 			PerformEndLevelBehaviour( aLevel, aLevel.MatchCriteria );
       
   757 		}
       
   758 		
       
   759 		protected virtual void PerformEndLevelBehaviour( SymNode aLevel, SymTokenBalancerMatchCriteria aCriteria )
       
   760 		{
       
   761 			#region Example step (11a) from LevelFinished method 
       
   762 			//
       
   763 			// We then add the closing bracket to level |1| which means
       
   764 			// that we can attempt to simplify level |2| entirely. This is the
       
   765 			// situation prior to simplification.
       
   766 			//
       
   767 			//  |0|                                 [ROOT]
       
   768 			//                                         |
       
   769 			//  |1|                  [TEST]   [(]     [@] [)]
       
   770 			//                                         |
       
   771 			//  |2|             [(] [*] [)]           [+] [(] [*] [)]
       
   772 			//                       |                         |
       
   773 			//  |3|     [ ] [B] [ ] [+] [ ] [C] [ ]           [E]
       
   774 			//
       
   775 			// aLevel would be the @ node at level |1|.
       
   776 			//
       
   777 			// We remove redundant bracketing from our children, i.e. those on level |2|, not from our own level. 
       
   778 			// Our parent takes care of removing this level's redundant bracketing (when it's level is completed)
       
   779 			// or then when an argument separator token is handled.
       
   780 			//
       
   781 			// We must iterate through level |1|'s children to find other level nodes. We check whether each
       
   782 			// child level node can be simplified by checking its children (i.e. our grandchildren).
       
   783 			//
       
   784 			#endregion
       
   785 
       
   786 			if	( aCriteria.IsAssociatedBehaviourRemoveRedundantBracketing )
       
   787 			{
       
   788 				int index = 0;
       
   789 				object childLevelNodeObject = aLevel.ChildByType( typeof(SymTokenBalancerMarkerLevelNode), ref index );
       
   790 				while( childLevelNodeObject != null )
       
   791 				{
       
   792 					SymTokenBalancerMarkerLevelNode childLevelNode = (SymTokenBalancerMarkerLevelNode) childLevelNodeObject;
       
   793 					if	( childLevelNode.CanBeSubsumed )
       
   794 					{
       
   795 						childLevelNode.Subsume();
       
   796 					}
       
   797 
       
   798 					// Try to find next level node
       
   799 					++index;
       
   800 					childLevelNodeObject = aLevel.ChildByType( typeof(SymTokenBalancerMarkerLevelNode), ref index );
       
   801 				}
       
   802 			}
       
   803 		}
       
   804 		#endregion
       
   805 
       
   806 		#region Data members
       
   807 		private SymTokenBalancerDocument iTree;
       
   808 		private SymTokenContainer iOpeningTokens = new SymTokenContainer();
       
   809 		private SymTokenContainer iClosingTokens = new SymTokenContainer();
       
   810 		#endregion
       
   811 	}
       
   812 }