/* This file was generated by SableCC (http://www.sablecc.org/). */

package uk.co.zonetora.fj.ast.lexer;

import java.io.*;
import java.util.*;
import uk.co.zonetora.fj.ast.node.*;

public class Lexer
{
    protected Token token;
    protected State state = State.INITIAL;

    private PushbackReader in;
    private int line;
    private int pos;
    private boolean cr;
    private boolean eof;
    private final StringBuffer text = new StringBuffer();

    protected void filter() throws LexerException, IOException
    {
    }

    public Lexer(PushbackReader in)
    {
        this.in = in;

        if(gotoTable == null)
        {
            try
            {
                DataInputStream s = new DataInputStream(
                    new BufferedInputStream(
                    Lexer.class.getResourceAsStream("lexer.dat")));

                // read gotoTable
                int length = s.readInt();
                gotoTable = new int[length][][][];
                for(int i = 0; i < gotoTable.length; i++)
                {
                    length = s.readInt();
                    gotoTable[i] = new int[length][][];
                    for(int j = 0; j < gotoTable[i].length; j++)
                    {
                        length = s.readInt();
                        gotoTable[i][j] = new int[length][3];
                        for(int k = 0; k < gotoTable[i][j].length; k++)
                        {
                            for(int l = 0; l < 3; l++)
                            {
                                gotoTable[i][j][k][l] = s.readInt();
                            }
                        }
                    }
                }

                // read accept
                length = s.readInt();
                accept = new int[length][];
                for(int i = 0; i < accept.length; i++)
                {
                    length = s.readInt();
                    accept[i] = new int[length];
                    for(int j = 0; j < accept[i].length; j++)
                    {
                        accept[i][j] = s.readInt();
                    }
                }

                s.close();
            }
            catch(Exception e)
            {
                throw new RuntimeException("The file \"lexer.dat\" is either missing or corrupted.");
            }
        }
    }

    public Token peek() throws LexerException, IOException
    {
        while(token == null)
        {
            token = getToken();
            filter();
        }

        return token;
    }

    public Token next() throws LexerException, IOException
    {
        while(token == null)
        {
            token = getToken();
            filter();
        }

        Token result = token;
        token = null;
        return result;
    }

    protected Token getToken() throws IOException, LexerException
    {
        int dfa_state = 0;

        int start_pos = pos;
        int start_line = line;

        int accept_state = -1;
        int accept_token = -1;
        int accept_length = -1;
        int accept_pos = -1;
        int accept_line = -1;

        int[][][] gotoTable = this.gotoTable[state.id()];
        int[] accept = this.accept[state.id()];
        text.setLength(0);

        while(true)
        {
            int c = getChar();

            if(c != -1)
            {
                switch(c)
                {
                case 10:
                    if(cr)
                    {
                        cr = false;
                    }
                    else
                    {
                        line++;
                        pos = 0;
                    }
                    break;
                case 13:
                    line++;
                    pos = 0;
                    cr = true;
                    break;
                default:
                    pos++;
                    cr = false;
                    break;
                };

                text.append((char) c);

                do
                {
                    int oldState = (dfa_state < -1) ? (-2 -dfa_state) : dfa_state;

                    dfa_state = -1;

                    int[][] tmp1 =  gotoTable[oldState];
                    int low = 0;
                    int high = tmp1.length - 1;

                    while(low <= high)
                    {
                        int middle = (low + high) / 2;
                        int[] tmp2 = tmp1[middle];

                        if(c < tmp2[0])
                        {
                            high = middle - 1;
                        }
                        else if(c > tmp2[1])
                        {
                            low = middle + 1;
                        }
                        else
                        {
                            dfa_state = tmp2[2];
                            break;
                        }
                    }
                }while(dfa_state < -1);
            }
            else
            {
                dfa_state = -1;
            }

            if(dfa_state >= 0)
            {
                if(accept[dfa_state] != -1)
                {
                    accept_state = dfa_state;
                    accept_token = accept[dfa_state];
                    accept_length = text.length();
                    accept_pos = pos;
                    accept_line = line;
                }
            }
            else
            {
                if(accept_state != -1)
                {
                    switch(accept_token)
                    {
                    case 0:
                        {
                            Token token = new0(
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    case 1:
                        {
                            Token token = new1(
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    case 2:
                        {
                            Token token = new2(
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    case 3:
                        {
                            Token token = new3(
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    case 4:
                        {
                            Token token = new4(
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    case 5:
                        {
                            Token token = new5(
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    case 6:
                        {
                            Token token = new6(
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    case 7:
                        {
                            Token token = new7(
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    case 8:
                        {
                            Token token = new8(
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    case 9:
                        {
                            Token token = new9(
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    case 10:
                        {
                            Token token = new10(
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    case 11:
                        {
                            Token token = new11(
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    case 12:
                        {
                            Token token = new12(
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    case 13:
                        {
                            Token token = new13(
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    case 14:
                        {
                            Token token = new14(
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    case 15:
                        {
                            Token token = new15(
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    case 16:
                        {
                            Token token = new16(
                                getText(accept_length),
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    case 17:
                        {
                            Token token = new17(
                                getText(accept_length),
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    case 18:
                        {
                            Token token = new18(
                                getText(accept_length),
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;
                            return token;
                        }
                    }
                }
                else
                {
                    if(text.length() > 0)
                    {
                        throw new LexerException(
                            "[" + (start_line + 1) + "," + (start_pos + 1) + "]" +
                            " Unknown token: " + text);
                    }
                    else
                    {
                        EOF token = new EOF(
                            start_line + 1,
                            start_pos + 1);
                        return token;
                    }
                }
            }
        }
    }

    Token new0(int line, int pos) { return new TTclass(line, pos); }
    Token new1(int line, int pos) { return new TExtends(line, pos); }
    Token new2(int line, int pos) { return new TSuper(line, pos); }
    Token new3(int line, int pos) { return new TThis(line, pos); }
    Token new4(int line, int pos) { return new TNew(line, pos); }
    Token new5(int line, int pos) { return new TReturn(line, pos); }
    Token new6(int line, int pos) { return new TLBrace(line, pos); }
    Token new7(int line, int pos) { return new TRBrace(line, pos); }
    Token new8(int line, int pos) { return new TSemicolon(line, pos); }
    Token new9(int line, int pos) { return new TComma(line, pos); }
    Token new10(int line, int pos) { return new TLPar(line, pos); }
    Token new11(int line, int pos) { return new TRPar(line, pos); }
    Token new12(int line, int pos) { return new TLSq(line, pos); }
    Token new13(int line, int pos) { return new TRSq(line, pos); }
    Token new14(int line, int pos) { return new TPeriod(line, pos); }
    Token new15(int line, int pos) { return new TEq(line, pos); }
    Token new16(String text, int line, int pos) { return new TNewLine(text, line, pos); }
    Token new17(String text, int line, int pos) { return new TBlank(text, line, pos); }
    Token new18(String text, int line, int pos) { return new TIdentifier(text, line, pos); }

    private int getChar() throws IOException
    {
        if(eof)
        {
            return -1;
        }

        int result = in.read();

        if(result == -1)
        {
            eof = true;
        }

        return result;
    }

    private void pushBack(int acceptLength) throws IOException
    {
        int length = text.length();
        for(int i = length - 1; i >= acceptLength; i--)
        {
            eof = false;

            in.unread(text.charAt(i));
        }
    }

    protected void unread(Token token) throws IOException
    {
        String text = token.getText();
        int length = text.length();

        for(int i = length - 1; i >= 0; i--)
        {
            eof = false;

            in.unread(text.charAt(i));
        }

        pos = token.getPos() - 1;
        line = token.getLine() - 1;
    }

    private String getText(int acceptLength)
    {
        StringBuffer s = new StringBuffer(acceptLength);
        for(int i = 0; i < acceptLength; i++)
        {
            s.append(text.charAt(i));
        }

        return s.toString();
    }

    private static int[][][][] gotoTable;
/*  {
        { // INITIAL
            {{9, 9, 1}, {10, 10, 2}, {13, 13, 3}, {32, 32, 4}, {40, 40, 5}, {41, 41, 6}, {44, 44, 7}, {46, 46, 8}, {59, 59, 9}, {61, 61, 10}, {65, 90, 11}, {91, 91, 12}, {92, 92, 13}, {93, 93, 14}, {95, 95, 15}, {97, 98, 16}, {99, 99, 17}, {100, 100, 16}, {101, 101, 18}, {102, 109, 16}, {110, 110, 19}, {111, 113, 16}, {114, 114, 20}, {115, 115, 21}, {116, 116, 22}, {117, 122, 16}, {123, 123, 23}, {125, 125, 24}, },
            {{9, 9, 1}, {32, 32, 4}, {92, 92, 13}, },
            {},
            {{10, 10, 25}, },
            {{9, 92, -3}, },
            {},
            {},
            {},
            {},
            {},
            {},
            {{48, 57, 26}, {65, 90, 27}, {95, 95, 28}, {97, 122, 29}, },
            {},
            {{110, 110, 30}, },
            {},
            {{48, 122, -13}, },
            {{48, 122, -13}, },
            {{48, 95, -13}, {97, 107, 29}, {108, 108, 31}, {109, 122, 29}, },
            {{48, 95, -13}, {97, 119, 29}, {120, 120, 32}, {121, 122, 29}, },
            {{48, 95, -13}, {97, 100, 29}, {101, 101, 33}, {102, 122, 29}, },
            {{48, 100, -21}, {101, 101, 34}, {102, 122, 29}, },
            {{48, 95, -13}, {97, 116, 29}, {117, 117, 35}, {118, 122, 29}, },
            {{48, 95, -13}, {97, 103, 29}, {104, 104, 36}, {105, 122, 29}, },
            {},
            {},
            {},
            {{48, 122, -13}, },
            {{48, 122, -13}, },
            {{48, 122, -13}, },
            {{48, 122, -13}, },
            {{9, 92, -3}, },
            {{48, 95, -13}, {97, 97, 37}, {98, 122, 29}, },
            {{48, 95, -13}, {97, 115, 29}, {116, 116, 38}, {117, 122, 29}, },
            {{48, 95, -13}, {97, 118, 29}, {119, 119, 39}, {120, 122, 29}, },
            {{48, 115, -34}, {116, 116, 40}, {117, 122, 29}, },
            {{48, 95, -13}, {97, 111, 29}, {112, 112, 41}, {113, 122, 29}, },
            {{48, 95, -13}, {97, 104, 29}, {105, 105, 42}, {106, 122, 29}, },
            {{48, 95, -13}, {97, 114, 29}, {115, 115, 43}, {116, 122, 29}, },
            {{48, 100, -21}, {101, 101, 44}, {102, 122, 29}, },
            {{48, 122, -13}, },
            {{48, 116, -23}, {117, 117, 45}, {118, 122, 29}, },
            {{48, 100, -21}, {101, 101, 46}, {102, 122, 29}, },
            {{48, 114, -39}, {115, 115, 47}, {116, 122, 29}, },
            {{48, 114, -39}, {115, 115, 48}, {116, 122, 29}, },
            {{48, 95, -13}, {97, 109, 29}, {110, 110, 49}, {111, 122, 29}, },
            {{48, 95, -13}, {97, 113, 29}, {114, 114, 50}, {115, 122, 29}, },
            {{48, 113, -47}, {114, 114, 51}, {115, 122, 29}, },
            {{48, 122, -13}, },
            {{48, 122, -13}, },
            {{48, 95, -13}, {97, 99, 29}, {100, 100, 52}, {101, 122, 29}, },
            {{48, 109, -46}, {110, 110, 53}, {111, 122, 29}, },
            {{48, 122, -13}, },
            {{48, 114, -39}, {115, 115, 54}, {116, 122, 29}, },
            {{48, 122, -13}, },
            {{48, 122, -13}, },
        }
    };*/

    private static int[][] accept;
/*  {
        // INITIAL
        {-1, 17, 16, 16, 17, 10, 11, 9, 14, 8, 15, 18, 12, -1, 13, 18, 18, 18, 18, 18, 18, 18, 18, 6, 7, 16, 18, 18, 18, 18, 17, 18, 18, 18, 18, 18, 18, 18, 18, 4, 18, 18, 18, 18, 18, 18, 18, 3, 0, 18, 18, 2, 18, 5, 1, },

    };*/

    public static class State
    {
        public final static State INITIAL = new State(0);

        private int id;

        private State(int id)
        {
            this.id = id;
        }

        public int id()
        {
            return id;
        }
    }
}
