crashanalysercmd/PerfToolsSharedLibraries/Engine/SymBuildParsingLib/Parser/Framework/Parser/SymParserBase.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/crashanalysercmd/PerfToolsSharedLibraries/Engine/SymBuildParsingLib/Parser/Framework/Parser/SymParserBase.cs Thu Feb 11 15:50:58 2010 +0200
@@ -0,0 +1,309 @@
+#define SHOW_TOKENS/*
+* Copyright (c) 2004-2008 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:
+*
+*/
+
+using System;
+using System.Collections;
+using System.Threading;
+using System.Reflection;
+using SymBuildParsingLib.Tree;
+using SymBuildParsingLib.Utils;
+using SymBuildParsingLib.Grouper;
+using SymBuildParsingLib.Lexer;
+using SymBuildParsingLib.Token;
+using SymBuildParsingLib.Parser.Framework.Workers;
+using SymBuildParsingLib.Parser.Framework.Document;
+using SymbianTree;
+
+namespace SymBuildParsingLib.Parser.Framework.Parser
+{
+ public abstract class SymParserBase
+ {
+ #region Event enumerations
+ public enum TEvent
+ {
+ EEventStaringLexing = 0,
+ EEventStaringGrouping,
+ EEventParsingComplete
+ };
+ #endregion
+
+ #region Observer interface
+ public delegate void ParserObserver( SymParserBase aParser, TEvent aEvent );
+ #endregion
+
+ #region Events
+ public event ParserObserver ParserObservers;
+ #endregion
+
+ #region Constructors and destructor
+ public SymParserBase( SymParserDocument aDocument )
+ {
+ // Store the document and initialise the document's
+ // parser reference
+ iDocument = aDocument;
+ iDocument.Context.Parser = this;
+
+ // The lexer reads the tokens from the stream and performs minimal
+ // (very basic) grouping.
+ iLexer = new SymLexer( iDocument.Context.FileName );
+
+ // We observe the lexer in order to know when all the input data
+ // has been consumed from the source file.
+ iLexer.LexerObservers += new SymLexer.LexerObserver( HandleLexerEvent );
+
+ // The grouper performs more sophisticated grouping based upon
+ // simple C++/C rules. It observes the lexer for tokens.
+ iGrouper = new SymGrouper( iLexer );
+
+ // We observe the grouper in order to obtain the grouped tokens
+ // which we will parse to form the tree.
+ iGrouper.GrouperObservers += new SymGrouper.GrouperObserver( HandleGrouperEvent );
+
+ // Create the thread for the parser
+ iWorkerThread = new Thread( new System.Threading.ThreadStart( BuildParserTree ) );
+ PrepareWorkerThread();
+
+ // Create any initial required workers
+ PrepareInitialWorkers();
+ }
+ #endregion
+
+ #region API
+ public void Parse()
+ {
+ // Starting the lexer will implicitly start the grouper
+ // as the grouper is already awaiting the lexer's output
+ // tokens. Tokens will arrive into the iGroupedTokens data
+ // member. This call is asynchronous.
+ iLexer.Lex();
+ }
+ #endregion
+
+ #region Clone API
+ public SymParserBase CarbonCopy( object[] aArguments )
+ {
+ // NB. Should use object.Clone with custom IClonable charactersitics?
+ System.Type type = this.GetType();
+ object objectInstance = Activator.CreateInstance( type, aArguments );
+ //
+ if ( !(objectInstance is SymParserBase) )
+ {
+ throw new Exception( "Unexpected object type during Carbon Copy operation" );
+ }
+ //
+ SymParserBase parser = (SymParserBase) objectInstance;
+ return parser;
+ }
+ #endregion
+
+ #region Abstract API
+ protected virtual void PrepareInitialWorkers()
+ {
+ }
+
+ protected virtual void HandleParserToken( SymToken aToken )
+ {
+ // Try to dish the token out to the workers. Give
+ // the token to the highest priority worker initially.
+ // Keep trying to offer it until one of the workers
+ // consumes it.
+ int count = iWorkers.Count;
+ for( int i=0; i<count; i++ )
+ {
+ SymParserWorker worker = (SymParserWorker) iWorkers[ i ];
+ SymParserWorker.TTokenConsumptionType consumptionType = worker.OfferToken( aToken );
+ //
+ if ( consumptionType == SymParserWorker.TTokenConsumptionType.ETokenConsumed )
+ {
+ break;
+ }
+ }
+ }
+ #endregion
+
+ #region Abstract properties
+ protected abstract string ParserName { get; }
+ #endregion
+
+ #region Properties
+ public string FileName
+ {
+ get { return iLexer.FileName; }
+ }
+
+ public SymParserDocument Document
+ {
+ get { return iDocument; }
+ }
+ #endregion
+
+ #region Worker related
+ public int WorkerCount
+ {
+ get { return iWorkers.Count; }
+ }
+
+ public void QueueWorker( SymParserWorker aWorker )
+ {
+ // Insert into sorted order
+ int count = iWorkers.Count;
+ for( int i=0; i<count; i++ )
+ {
+ SymParserWorker worker = (SymParserWorker) iWorkers[ i ];
+ int existingPriority = worker.Priority;
+ //
+ if ( aWorker.Priority >= existingPriority )
+ {
+ iWorkers.Insert( i, aWorker );
+ return;
+ }
+ }
+
+ // First entry - just append it...
+ iWorkers.Add( aWorker );
+ }
+ #endregion
+
+ #region Internal Properties
+ protected SymTokenContainer GroupedTokens
+ {
+ get { return iGroupedTokens; }
+ }
+ #endregion
+
+ #region Internal methods
+ private void BuildParserTree()
+ {
+ // Pull a token from the source buffer
+ do
+ {
+ int tokenCount = 0;
+ //
+ do
+ {
+ SymToken token = null;
+
+ // Try to get the head token (if there is one)
+ lock( iGroupedTokens )
+ {
+ tokenCount = iGroupedTokens.Count;
+ if ( tokenCount > 0 )
+ {
+ token = iGroupedTokens.PopHead();
+ }
+ }
+
+ // Then process it
+ if ( token != null )
+ {
+#if SHOW_TOKENS
+ System.Diagnostics.Debug.WriteLine( "BuildParserTree() - next token is: [" + token.Value + "]");
+#endif
+ HandleParserToken( token );
+ }
+ }
+ while ( tokenCount > 0 );
+
+ // We've processed all the tokens we had so far... put us to sleep
+ //System.Diagnostics.Debug.WriteLine( "Parser.BuildParserTree() - no more tokens - waiting on semaphore..." );
+ iSemaphore.Wait();
+ //System.Diagnostics.Debug.WriteLine( "Parser.BuildParserTree() - AWAKE!" );
+ }
+ while( true );
+
+ }
+
+ private void PrepareWorkerThread()
+ {
+ System.Random randomNumberGen = new Random( System.Environment.TickCount );
+ int uniquePostfix = randomNumberGen.Next();
+ //
+ string workerThreadName = ParserName + uniquePostfix.ToString("d8");
+ iWorkerThread.Name = workerThreadName;
+ iWorkerThread.IsBackground = true;
+ iWorkerThread.Start();
+ }
+ private void ReportEvent( TEvent aEvent )
+ {
+ if ( ParserObservers != null )
+ {
+ ParserObservers( this, aEvent );
+ }
+ }
+ private void NewGroupedTokenArrived( SymToken aToken )
+ {
+ lock( this )
+ {
+ iGroupedTokens.Append( aToken );
+ //
+ if ( iSemaphore.Count == 0 )
+ {
+ iSemaphore.Signal();
+ }
+ }
+ }
+ #endregion
+
+ #region Event handlers
+ private void HandleLexerEvent( SymLexer aLexer, SymLexer.TEvent aEvent, SymToken aToken )
+ {
+ switch( aEvent )
+ {
+ case SymLexer.TEvent.EEventLexingStarted:
+ ReportEvent( TEvent.EEventStaringLexing );
+ break;
+ case SymLexer.TEvent.EEventLexingNewLine:
+ break;
+ case SymLexer.TEvent.EEventLexingComplete:
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void HandleGrouperEvent( SymGrouper aGrouper, SymGrouper.TEvent aEvent, SymToken aGroupedToken )
+ {
+ switch( aEvent )
+ {
+ case SymGrouper.TEvent.EEventGroupingStarted:
+ ReportEvent( TEvent.EEventStaringGrouping );
+ break;
+ case SymGrouper.TEvent.EEventGroupingPaused:
+ break;
+ case SymGrouper.TEvent.EEventGroupingComplete:
+ ReportEvent( TEvent.EEventParsingComplete );
+ break;
+ case SymGrouper.TEvent.EEventGroupingTokenReady:
+ NewGroupedTokenArrived( aGroupedToken );
+ break;
+ default:
+ break;
+ }
+ }
+ #endregion
+
+ #region Data members
+ private readonly Thread iWorkerThread;
+ private readonly SymGrouper iGrouper;
+ private readonly SymLexer iLexer;
+ private readonly SymParserDocument iDocument;
+ private SymTokenContainer iGroupedTokens = new SymTokenContainer();
+ private ArrayList iWorkers = new ArrayList( 4 );
+ private SymSemaphore iSemaphore = new SymSemaphore( 0, 1 );
+ #endregion
+ }
+}