using System;
using System.IO;
using System.Text;

public class EndOfFileException: ApplicationException {}


public class Token
{
	public enum Type  { LParen, RParen, LBrace, RBrace, Colon, Ampersand,
                        Semicolon, Comma, SwungDash, Star, Equals,
						Minus, Scope,
    				    IntegerLiteral, HexLiteral, OctalLiteral,
					    Ident, Unknown, End };	

						
	private Type value;
	private object attribute;
	
	public Token(Type value, object attribute)
	{
		this.value = value;
		this.attribute = attribute;
	}
	
	
	public Token(Type value): this(value, null) {}
	
	
	public bool IsIdentifier(string identifier)
	{
		if ( this.value == Type.Ident && (string) this.attribute == identifier)
			return true;
		else
			return false;
	}

			
	public Type Value
	{
		get { return this.value; }
	}
	
	
	public object Attribute
 	{
 		get { return this.attribute; }
 	}	
	
}



public class Lexan
{
	private StreamReader reader;
	private Token currentToken = null;
	private Token nextToken = null;
	private int lineNumber = 1;

		
	private char GetChar()
	{
		int ch;
		
		ch = reader.Read();
		if ( ch == -1 )
			throw new EndOfFileException();
		else return (char) ch;
	}
	
	
	private char Peek()
	{
		return (char) reader.Peek();
	}
	
	
	private void AdvanceToNextChar()
	{
		int ch;
		
		ch = reader.Read();
		if ( ch == -1 )
			throw new EndOfStreamException();
		else
			return;
	}

	
	private bool IsHexDigit(char ch)
	{
		if ( Char.IsDigit(ch) )
			return true;
		else
			switch ( Char.ToUpper(ch) )
			{
				case 'A':
				case 'B':
				case 'C':
				case 'D':
				case 'E':
				case 'F': return true;
				default:  return false;
			}
	}	
	
	
	private Token GetNextToken()
	{
		char ch;
		
		try
		{
			SkipWhiteSpace();
			
			ch = GetChar();
			
			// Is it the start of an identifier?
			if ( Char.IsLetter(ch) || ch == '_' )
			{
				StringBuilder ident = new StringBuilder();
				ident.Append(ch);
				
				while ( Char.IsLetterOrDigit(Peek()) || Peek() == '_' )
					ident.Append( GetChar() );
				return new Token( Token.Type.Ident, ident.ToString() );
			}
			
			// Is it a numeric literal?
			else if ( Char.IsDigit(ch) )
			{
				// Yes, now let's classify it
				
				if ( ch != '0' )
				{
					// Must be decimal
					StringBuilder number = new StringBuilder();
					number.Append(ch);
					while ( Char.IsDigit(Peek()) )
						number.Append( GetChar() );
					return new Token( Token.Type.IntegerLiteral,
						Convert.ToUInt32(number.ToString() ) );
				}
			
				else // The first character is zero
				{
					ch = Peek();
					if ( ch == 'x' )
					{
						StringBuilder number = new StringBuilder();
						AdvanceToNextChar();
						if ( ! IsHexDigit(Peek()) )
							return new Token( Token.Type.Unknown );
						while ( IsHexDigit( Peek()) )
							number.Append( GetChar() );
						return new Token(Token.Type.HexLiteral,
							Convert.ToUInt32(number.ToString(), 16) );
					}
					else if ( Char.IsDigit(ch) )
					{
						StringBuilder number = new StringBuilder();
						number.Append( GetChar() );
						while ( Char.IsDigit( Peek()) )
							number.Append( GetChar() );
						return new Token(Token.Type.OctalLiteral,
							Convert.ToUInt32(number.ToString(), 8) );
					}
					else
						return new Token( Token.Type.IntegerLiteral, 0u );
					
				
				}
			}	
			else
				switch( ch )
				{
					case '(': return new Token( Token.Type.LParen );
					case ')': return new Token( Token.Type.RParen );
					case '&': return new Token( Token.Type.Ampersand );
					case ';': return new Token( Token.Type.Semicolon );
					case ',': return new Token( Token.Type.Comma );
					case '~': return new Token( Token.Type.SwungDash );
					case '{': return new Token( Token.Type.LBrace );
					case '}': return new Token( Token.Type.RBrace );	
					case '*': return new Token( Token.Type.Star );
					case '=': return new Token( Token.Type.Equals );
					case '-': return new Token( Token.Type.Minus );
					case ':':
						if ( Peek() == ':' )
						{
							AdvanceToNextChar();
							return new Token( Token.Type.Scope );
						}
						else
							return new Token( Token.Type.Colon );
					default:
						return new Token( Token.Type.Unknown );
				}
		}
		catch ( EndOfFileException )
		{
			return new Token( Token.Type.End );
		}
		catch
		{
			return new Token( Token.Type.End );
		}
	}
	
	
	private void SkipWhiteSpace()
	// Skips over zero or more whitespace characters
	// Tries to keep track of line count. Assumes that
	// a LF, CR, or CR+LF terminates a line
	{
		while ( Char.IsWhiteSpace( Peek() ) )
		{
			if ( Peek() == '\n' )
			{
				lineNumber++;
				AdvanceToNextChar();
			}
			else if ( Peek() == '\r' )
			{
				lineNumber++;
				AdvanceToNextChar();
				if ( Peek() == '\n' )
					AdvanceToNextChar();
			}
			else
				AdvanceToNextChar();
		}
	}
	
	
	public Lexan( StreamReader reader )
	{
		this.reader = reader;
		currentToken = GetNextToken();
		nextToken = GetNextToken();
	}

		
	public Lexan(): this( (StreamReader) Console.In ) {}
	
	
	public Token CurrentToken
	{
		get { return currentToken; }
	}
	
	
	public Token NextToken
	{
		get { return nextToken; }
	}
	
	
	public int LineNumber
	{
		get { return lineNumber; }
	}
	
		
	public void Advance()
	{
		currentToken = nextToken;
		nextToken = GetNextToken();
	}
		
}
