using System;
using System.Text;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;

namespace Lexer
{

    public class LexerException : System.Exception
    {
        public LexerException(string msg)
            : base(msg)
        {
        }

    }

    public class Lexer
    {

        protected int position;
        protected char currentCh; // ��������� ��������� ������
        protected int currentCharValue; // ����� �������� ���������� ���������� �������
        protected System.IO.StringReader inputReader;
        protected string inputString;

        public Lexer(string input)
        {
            inputReader = new System.IO.StringReader(input);
            inputString = input;
        }

        public void Error()
        {
            System.Text.StringBuilder o = new System.Text.StringBuilder();
            o.Append(inputString + '\n');
            o.Append(new System.String(' ', position - 1) + "^\n");
            o.AppendFormat("Error in symbol {0}", currentCh);
            throw new LexerException(o.ToString());
        }

        protected void NextCh()
        {
            this.currentCharValue = this.inputReader.Read();
            this.currentCh = (char) currentCharValue;
            this.position += 1;
        }

        public virtual bool Parse()
        {
            return true;
        }
    }

    public class IntLexer : Lexer
    {

        protected System.Text.StringBuilder intString;
        public int parseResult = 0;

        public IntLexer(string input)
            : base(input)
        {
            intString = new System.Text.StringBuilder();
        }

        public override bool Parse()
        {
            NextCh();
			int res = 0; // ��� ����� �������� �����
			int sign = 1; // ���� �����
            if (currentCh == '+' || currentCh == '-')
            {
				if (currentCh == '-')
					sign = -1;
                NextCh();
            }
        
            if (char.IsDigit(currentCh))
            {
				res = currentCh - '0';
                NextCh();
            }
            else
            {
                Error();
            }

            while (char.IsDigit(currentCh))
            {
				res = res * 10 + currentCh - '0';
                NextCh();
            }


            if (currentCharValue != -1)
            {
                Error();
            }

			this.parseResult = res * sign;

            return true;

        }
    }
    
    public class IdentLexer : Lexer
    {
        private string parseResult;
        protected StringBuilder builder;
    
        public string ParseResult
        {
            get { return parseResult; }
        }
    
        public IdentLexer(string input) : base(input)
        {
            builder = new StringBuilder();
        }

		public override bool Parse()
		{
			NextCh();

			if (currentCharValue == -1)
				Error();

			var builder1 = new StringBuilder();

			if (char.IsLetter(currentCh) || currentCh == '_')
			{
				builder1.Append(currentCh);
				NextCh();
			}
			else
			{
				Error();
				return false;
			}

			while (char.IsLetter(currentCh) || char.IsDigit(currentCh) || currentCh == '_')
			{
				builder1.Append(currentCh);
				NextCh();
			}

			if (currentCharValue != -1)
			{
				Error();
			}

			parseResult = builder1.ToString();
			return true;
		}
       
    }

    public class IntNoZeroLexer : IntLexer
    {
        public IntNoZeroLexer(string input)
            : base(input)
        {
        }

        public override bool Parse()
        {
			NextCh();

			if (currentCharValue == -1)
			{
				Error();
			}

			if (currentCh == '0')
				Error();

			if (currentCh == '+' || currentCh == '-')
			{
				NextCh();
				if (currentCh == '0')
					Error();
			}

			while (char.IsDigit(currentCh))
				NextCh();

			if (currentCharValue != -1)
			{
				Error();
			}

			return true;
			//throw new NotImplementedException();
		}
    }

    public class LetterDigitLexer : Lexer
    {
        protected StringBuilder builder;
        protected string parseResult;

        public string ParseResult
        {
            get { return parseResult; }
        }

        public LetterDigitLexer(string input)
            : base(input)
        {
            builder = new StringBuilder();
        }

        public override bool Parse()
        {
			//throw new NotImplementedException();
			NextCh();

			if (currentCharValue == -1)
			{
				Error();
			}

			if (char.IsDigit(currentCh))
				Error();

			bool isDigit = false;
			NextCh();

			while ((char.IsDigit(currentCh) && !isDigit) || (char.IsLetter(currentCh) && isDigit))
			{
				isDigit = char.IsDigit(currentCh);
				NextCh();
				
			}

			if (currentCharValue != -1)
			{
				Error();
			}

			return true;
        }
       
    }

    public class LetterListLexer : Lexer
    {
        protected List<char> parseResult;

        public List<char> ParseResult
        {
            get { return parseResult; }
        }

        public LetterListLexer(string input)
            : base(input)
        {
            parseResult = new List<char>();
        }

        public override bool Parse()
        {
			NextCh();

			List<char> res = new List<char>();

			if (currentCharValue == -1)
			{
				Error();
			}

			if (!char.IsLetter(currentCh))
				Error();
			else
			{
				res.Add(currentCh);
				NextCh();
			}

			while (currentCh == ',' || currentCh == ';')
			{
				NextCh();
				if (char.IsLetter(currentCh))
					res.Add(currentCh);
				else
					Error();
				NextCh();
			}

			if (currentCharValue != -1)
			{
				Error();
			}

			parseResult = res;

			return true;
        }
    }

    public class DigitListLexer : Lexer
    {
        protected List<int> parseResult;

        public List<int> ParseResult
        {
            get { return parseResult; }
        }

        public DigitListLexer(string input)
            : base(input)
        {
            parseResult = new List<int>();
        }

        public override bool Parse()
        {
            NextCh();

            List<int> res = new List<int>();

            if (currentCharValue == -1)
            {
                Error();
            }

            if (!char.IsDigit(currentCh))
                Error();
            else
            {
                res.Add(currentCh - '0');
                NextCh();
            }

            while (currentCh == ' ')
            {
                NextCh();
                if (char.IsDigit(currentCh))
                {
                    res.Add(currentCh - '0');
                    NextCh();
                }  
                else if (currentCh == ' ')
                    continue;
                else
                    Error();
            }

            if (currentCharValue != -1)
            {
                Error();
            }

            parseResult = res;

            return true;
        }
    }

    public class LetterDigitGroupLexer : Lexer
    {
        protected StringBuilder builder;
        protected string parseResult;

        public string ParseResult
        {
            get { return parseResult; }
        }
        
        public LetterDigitGroupLexer(string input)
            : base(input)
        {
            builder = new StringBuilder();
        }

        public override bool Parse()
        {
            NextCh();

            StringBuilder res = new StringBuilder("");

            if (currentCharValue == -1)
            {
                Error();
            }

            while (char.IsLetterOrDigit(currentCh))
            {
                if (char.IsLetter(currentCh))
                {
                    res.Append(currentCh);
                    NextCh();
                }
                else
                    Error();
                if (char.IsLetter(currentCh))
                {
                    res.Append(currentCh);
                    NextCh();
                    if (currentCharValue == -1)
                        break;
                }
                if (char.IsDigit(currentCh))
                {
                    res.Append(currentCh);
                    NextCh();
                    if (currentCharValue == -1)
                        break;
                }
                if (char.IsDigit(currentCh))
                {
                    res.Append(currentCh);
                    NextCh();
                    if (currentCharValue == -1)
                        break;
                }
            }

            if (currentCharValue != -1)
            {
                Error();
            }

            parseResult = res.ToString();

            return true;
        }
       
    }

    public class DoubleLexer : Lexer
    {
        private StringBuilder builder;
        private double parseResult;

        public double ParseResult
        {
            get { return parseResult; }

        }

        public DoubleLexer(string input)
            : base(input)
        {
            builder = new StringBuilder();
        }

        public override bool Parse()
        {
            NextCh();

            StringBuilder res = new StringBuilder("");

            if (currentCharValue == -1)
            {
                Error();
            }

            if (char.IsDigit(currentCh))
            {
                if (currentCh == '0')
                {
                    res.Append(currentCh);
                    NextCh();
                    if (currentCharValue == -1)
                    {
                        parseResult = double.Parse(res.ToString());
                        return true;
                    }
                    else if (currentCh != '.' && currentCharValue != -1)
                        Error();
                    else if (currentCh == '.')
                    {
                        res.Append(currentCh);
                        NextCh();
                        if (!char.IsDigit(currentCh))
                            Error();
                    }
                    else
                        Error();
                }
                else
                {
                    while (char.IsDigit(currentCh))
                    {
                        res.Append(currentCh);
                        NextCh();
                    }
                    if (currentCharValue == -1)
                    {
                        parseResult = double.Parse(res.ToString());
                        return true;
                    }
                    else if (currentCh != '.' && currentCharValue != -1)
                        Error();
                    else if (currentCh == '.')
                    {
                        res.Append(currentCh);
                        NextCh();
                        if (!char.IsDigit(currentCh))
                            Error();
                    }
                    else 
                        Error();
                }
                    
            }
            else
                Error();

            while (char.IsDigit(currentCh))
            {
                res.Append(currentCh);
                NextCh();
            }

            if (currentCharValue != -1)
            {
                Error();
            }

            parseResult = double.Parse(res.ToString());
            return true;
        }
       
    }

    public class StringLexer : Lexer
    {
        private StringBuilder builder;
        private string parseResult;

        public string ParseResult
        {
            get { return parseResult; }

        }

        public StringLexer(string input)
            : base(input)
        {
            builder = new StringBuilder();
        }

        public override bool Parse()
        {
            NextCh();

            StringBuilder res = new StringBuilder("");

            if (currentCharValue == -1)
            {
                Error();
            }

            if (currentCh != '\'')
                Error();
            res.Append(currentCh);
            NextCh();

            while (currentCh != '\'')
            {
                if (currentCharValue == -1)
                    Error();
                res.Append(currentCh);
                NextCh();
            }

            if (currentCh != '\'')
                Error();
            res.Append(currentCh);
            NextCh();

            if (currentCharValue != -1)
            {
                Error();
            }

            parseResult = res.ToString();

            return true;
        }
    }

    public class CommentLexer : Lexer
    {
        private StringBuilder builder;
        private string parseResult;

        public string ParseResult
        {
            get { return parseResult; }

        }

        public CommentLexer(string input)
            : base(input)
        {
            builder = new StringBuilder();
        }

        public override bool Parse()
        {
            NextCh();

            StringBuilder res = new StringBuilder("");

            if (currentCharValue == -1)
                Error();

            if (currentCh != '/')
                Error();
            res.Append(currentCh);
            NextCh();
            if (currentCh != '*')
                Error();
            res.Append(currentCh);
            NextCh();

            while (true)
            {
                if (currentCharValue == -1)
                    Error();
                if (currentCh == '*')
                {
                    res.Append(currentCh);
                    NextCh();
                    if (currentCh == '/')
                    {
                        res.Append(currentCh);
                        NextCh();
                        if (currentCharValue != -1)
                            Error();
                        break;
                    }
                }
                res.Append(currentCh);
                NextCh();
            }

            parseResult = res.ToString();
            return true;
        }
    }

    public class IdentChainLexer : Lexer
    {
        private StringBuilder builder;
        private List<string> parseResult;

        public List<string> ParseResult
        {
            get { return parseResult; }

        }

        public IdentChainLexer(string input)
            : base(input)
        {
            builder = new StringBuilder();
            parseResult = new List<string>();
        }

        public override bool Parse()
        {
            NextCh();

            StringBuilder res = new StringBuilder("");
            StringBuilder ident = new StringBuilder("");

            if (currentCharValue == -1)
                Error();

            
            IdentLexer l = new IdentLexer("abc22");

            return true;
        }
    }

    public class Program
    {
        public static void Main()
        {
            CommentLexer l = new CommentLexer("/**/");
            l.Parse();

        }
    }
}