core/src/lexer.cpp
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Thu, 26 Aug 2010 00:49:35 +0100
changeset 37 534b01198c2d
parent 0 7f656887cf89
child 78 b3ffff030d5c
permissions -rw-r--r--
Added ENotifyKeypresses and ECaptureCtrlC flags to CCommandBase. Commands can now get keypresses and handle ctrl-C via callbacks instead of having to implement custom active objects. As part of this extended the CCommandBase extension interface to MCommandExtensionsV2 for the new virtual functions KeyPressed(TUint aKeyCode, TUint aModifiers) and CtrlCPressed(). sudo now cleans up correctly by using ECaptureCtrlC.

// lexer.cpp
// 
// Copyright (c) 2006 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "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:
// Accenture - Initial contribution
//

#include "lexer.h"


//
// TToken
//

TToken::TToken()
	: iToken(NULL, 0), iPos(0)
	{
	}

TToken::TToken(TType aType, const TDesC& aToken, TInt aPos)
	: iType(aType), iToken(aToken), iPos(aPos)
	{
	}

TToken& TToken::operator=(const TToken& aToken)
	{
	iType = aToken.iType;
	iToken.Set(aToken.iToken);
	iPos = aToken.iPos;
	return *this;
	}

TToken::TType TToken::Type() const
	{
	return iType;
	}

TInt TToken::Position() const
	{
	return iPos;
	}

const TDesC& TToken::String() const
	{
	return iToken;
	}


//
// CReservedLookup
//

class CReservedLookup : public CBase
	{
public:
	class TResult
		{
	public:
		enum TType
			{
			ENoMatch,
			EMatch
			};
	public:
		TResult();
	public:
		TType iResultType;
		TToken::TType iTokenType;
		TInt iTokenLength;
		};
	enum TCharPos
		{
		ENotLast,
		ELast
		};
public:
	static CReservedLookup* NewL();
	~CReservedLookup();
	void DefineTokenTypeL(TToken::TType aTokenType, const TDesC& aString);
	void Reset();
	TResult Lookup(const TDesC& aDes);
private:
	class TReserved
		{
	public:
		TReserved(TToken::TType aType, const TDesC& aString);
	public:
		TToken::TType iType;
		TPtrC iString;
		};
private:
	RArray<TReserved> iList;
	};

CReservedLookup* CReservedLookup::NewL()
	{
	return new(ELeave) CReservedLookup();
	}

CReservedLookup::~CReservedLookup()
	{
	iList.Close();
	}

void CReservedLookup::DefineTokenTypeL(TToken::TType aTokenType, const TDesC& aString)
	{
	User::LeaveIfError(iList.Append(TReserved(aTokenType, aString)));
	}

CReservedLookup::TResult CReservedLookup::Lookup(const TDesC& aDes)
	{
	// Find the longest reserved word that matches from the beginning of this string.
	TResult result;
	const TInt count = iList.Count();
	for (TInt i = 0; i < count; ++i)
		{
		const TReserved& reserved = iList[i];
		if (aDes.Left(reserved.iString.Length()) == reserved.iString)
			{
			if (result.iTokenLength < reserved.iString.Length())
				{
				result.iTokenLength = reserved.iString.Length();
				result.iResultType = TResult::EMatch;
				result.iTokenType = reserved.iType;
				}
			}
		}
	return result;
	}

CReservedLookup::TReserved::TReserved(TToken::TType aType, const TDesC& aString)
	: iType(aType), iString(aString)
	{
	}

CReservedLookup::TResult::TResult()
	: iResultType(ENoMatch), iTokenType(TToken::EString), iTokenLength(0)
	{
	}


//
// CLexer
//

CLexer* CLexer::NewL()
	{
	CLexer* self = CLexer::NewLC();
	CleanupStack::Pop(self);
	return self;
	}

CLexer* CLexer::NewL(TUint aBehaviour)
	{
	CLexer* self = CLexer::NewLC(aBehaviour);
	CleanupStack::Pop(self);
	return self;
	}

CLexer* CLexer::NewLC()
	{
	CLexer* self = new(ELeave) CLexer(EHandleSingleQuotes | EHandleDoubleQuotes | EHandleComments);
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}

CLexer* CLexer::NewLC(TUint aBehaviour)
	{
	CLexer* self = new(ELeave) CLexer(aBehaviour);
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}

CLexer::~CLexer()
	{
	delete iReservedLookup;
	}

void CLexer::DefineTokenTypeL(TToken::TType aTokenType, const TDesC& aString)
	{
	iReservedLookup->DefineTokenTypeL(aTokenType, aString);
	}

void CLexer::Set(const TDesC& aDes, const TChar& aEscapeChar)
	{
	iLex = aDes;
	iEscapeChar = aEscapeChar;
	}

TToken CLexer::NextToken()
	{
	SkipWhiteSpace();
	iLex.Mark();
	TToken::TType type(TToken::ENull);

	while (!iLex.Eos())
		{
		type = TToken::EString;
		TChar c = iLex.Get();
		if (c == iEscapeChar)
			{
			iLex.Get();
			}
		else if ((c == '\'') && (iBehaviour & EHandleSingleQuotes))
			{
			SkipSingleQuotedChars();
			}
		else if ((c == '\"') && (iBehaviour & EHandleDoubleQuotes))
			{
			SkipDoubleQuotedChars();
			}
		else if ((c == '#') && (iBehaviour & EHandleComments))
			{
			if (iLex.MarkedToken().Length() > 1)
				{
				iLex.UnGet();
				break;
				}
			else
				{
				SkipComment();
				if (iLex.Eos())
					{
					type = TToken::ENull;
					break;
					}
				else
					{
					iLex.Mark();
					}
				}
			}
		else if (c.IsSpace() && (c != '\n') && (c != '\r'))
			{
			iLex.UnGet();
			break;
			}
		else
			{
			iLex.UnGet();
			CReservedLookup::TResult result = iReservedLookup->Lookup(iLex.Remainder());
			if (result.iResultType == CReservedLookup::TResult::EMatch)
				{
				if (iLex.MarkedToken().Length() > 0)
					{
					break;
					}
				else
					{
					iLex.Inc(result.iTokenLength);
					type = result.iTokenType;
					break;
					}
				}
			iLex.Get();
			}
		}

	return TToken(type, iLex.MarkedToken(), iLex.MarkedOffset());
	}

TInt CLexer::CurrentOffset() const
	{
	return iLex.Offset();
	}

TBool CLexer::More()
	{
	SkipWhiteSpace();
	return !iLex.Eos();
	}

CLexer::CLexer(TUint aBehaviour)
	: iBehaviour(aBehaviour)
	{
	}

void CLexer::ConstructL()
	{
	iReservedLookup = CReservedLookup::NewL();
	}

void CLexer::SkipSingleQuotedChars()
	{
	while (!iLex.Eos())
		{
		TChar c = iLex.Get();
		if ((c == iEscapeChar) && !iLex.Eos() && (iLex.Peek() == '\''))
			{
			// Allow quoted single quote characters. Note, the is a departure from Bash behaviour, but is in line with Perl and is generally helpful.
			iLex.Get();
			}
		else if (c == '\'')
			{
			break;
			}
		}
	}

void CLexer::SkipDoubleQuotedChars()
	{
	while (!iLex.Eos())
		{
		TChar c = iLex.Get();
		if ((c == iEscapeChar) && !iLex.Eos())
			{
			iLex.Get();
			}
		else if (c == '"')
			{
			break;
			}
		}
	}

void CLexer::SkipComment()
	{
	while (!iLex.Eos())
		{
		TChar c = iLex.Get();
		if ((c == '\n') || (c == '\r'))
			{
			iLex.UnGet();
			break;
			}
		}
	}

void CLexer::SkipWhiteSpace()
	{
	while (!iLex.Eos())
		{
		TChar c = iLex.Get();
		if (!c.IsSpace() || (c == '\n') || (c == '\r'))
			{
			iLex.UnGet();
			break;
			}
		}
	}