/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * SableCC version 2.1                                                     *
 * Copyright (C) 1997, 1998 Etienne Gagnon (gagnon@sable.mcgill.ca).  All  *
 * rights reserved.                                                        *
 *                                                                         *
 * This program is free software; you can redistribute it and/or modify    *
 * it under the terms of the GNU General Public License as published by    *
 * the Free Software Foundation; either version 2 of the License, or       *
 * (at your option) any later version.                                     *
 *                                                                         *
 * This program is distributed in the hope that it will be useful,         *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
 * GNU General Public License for more details.                            *
 *                                                                         *
 * You should have received a copy of the GNU General Public License along *
 * with this program; if not, write to the Free Software Foundation, Inc., *
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                 *
 *                                                                         *
 * The GNU General Public License does not permit incorporating this       *
 * program into proprietary programs. If you would like to obtain a        *
 * different license for a version that has not been modified in any way   *
 * from a version released by Etienne Gagnon, please write to:             *
 * Etienne Gagnon, 11348 Brunet, Montreal-Nord, Quebec, H1G 5G1, CANADA.   *
 * e-mail: gagnon@sable.mcgill.ca.                                         *
 *                                                                         *
 * To submit a bug, send a comment or get the latest news on SableCC and   *
 * other Sable Research Group projects, please visit the web site:         *
 * http://www.sable.mcgill.ca/                                             *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

Macro:LexerException
package $0$;

public class LexerException extends Exception
{
    LexerException(String message)
    {
        super(message);
    }
}

$

Macro:LexerHeader
package $0$;

import java.io.*;
import ca.mcgill.sable.util.*;
import $1$.*;

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

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

    protected void filter()
    {
    }

    public Lexer(PushbackReader in)
    {
        this.in = in;
    }
    
    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;
    }
    
    private 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;

        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 low = 0;
                    int high = gotoTable[oldState].length - 1;

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

            if(dfa_state >= 0)
            {
                if(accept[state.id()][dfa_state] != -1)
                {
                    accept_state = dfa_state;
                    accept_token = accept[state.id()][dfa_state];
                    accept_length = text.length();
                    accept_pos = pos;
                    accept_line = line;
                }
            }
            else
            {
                if(accept_state != -1)
                {
                    switch(accept_token)
                    {

$

Macro:LexerVariableToken
                    case $0$:
                        {
                            Token token = new$0$(
                                getText(accept_length),
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;

$

Macro:LexerFixedToken
                    case $0$:
                        {
                            Token token = new$0$(
                                start_line + 1,
                                start_pos + 1);
                            pushBack(accept_length);
                            pos = accept_pos;
                            line = accept_line;

$

Macro:TokenSwitchHeader
                            switch(state.id())
                            {

$

Macro:TokenCase
                                case $0$: state = State.$1$; break;

$

Macro:TokenSwitchTail
                            }

$

Macro:LexerTokenTail
                            return token;
                        }

$

Macro:LexerBody1
                    }
                }
                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;
                    }
                }
            }
        }
    }


$

Macro:LexerNewVariableToken
    Token new$0$(String text, int line, int pos) { return new $1$(text, line, pos); }

$

Macro:LexerNewFixedToken
    Token new$0$(int line, int pos) { return new $1$(line, pos); }

$

Macro:LexerBody2

    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--)
        {
            in.unread(text.charAt(i));
        }
    }

    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 =
    {

$

Macro:LexerAcceptHeader
    };
    
    private static int[][] accept =
    {

$

Macro:LexerAcceptTail
    };


$

Macro:LexerStateHeader
    public static class State
    {

$

Macro:LexerStateBody
        public final static State $0$ = new State($1$);

$

Macro:LexerStateTail

        private int id;

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

$

Macro:LexerTail
}

$

