/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 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:ParserHeader
package $0$;

import $1$.*;
import $2$.*;
import $3$.*;
import ca.mcgill.sable.util.*;

import java.util.*;
import java.io.IOException;

public class Parser
{
    public final Analysis ignoredTokens = new AnalysisAdapter();

    protected Node node;

    private final Lexer lexer;
    private final ListIterator stack = new LinkedList().listIterator();
    private int last_shift;
    private int last_pos;
    private int last_line;
    private final TokenIndex converter = new TokenIndex();
    private final int[] action = new int[2];

    private final static int SHIFT = 0;
    private final static int REDUCE = 1;
    private final static int ACCEPT = 2;
    private final static int ERROR = 3;

    protected void filter()
    {
    }

    public Parser(Lexer lexer)
    {
        this.lexer = lexer;
    }

    private int goTo(int index)
    {
        int state = state();
        int low = 1;
        int high = gotoTable[index].length - 1;
        int value = gotoTable[index][0][1];

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

        return value;
    }

    private void push(int state, Node node, boolean filter)
    {
        this.node = node;

        if(filter)
        {
            filter();
        }

        if(!stack.hasNext())
        {
            stack.add(new State(state, this.node));
            stack.next();
            return;
        }

        State s = (State) stack.next();
        s.state = state;
        s.node = this.node;
    }

    private int state()
    {
        State s = (State) stack.previous();
        stack.next();        
        return s.state;
    }

    private Node pop()
    {
        return (Node) ((State) stack.previous()).node;
    }

    private int index(Switchable token)
    {
        converter.index = -1;
        token.apply(converter);
        return converter.index;
    }

    public Start parse() throws ParserException, LexerException, IOException
    {
        push(0, null, false);

        List ign = null;
        while(true)
        {
            while(index(lexer.peek()) == -1)
            {
                if(ign == null)
                {
                    ign = new TypedLinkedList(NodeCast.instance);
                }

                ign.add(lexer.next());
            }

            if(ign != null)
            {
                ignoredTokens.setIn(lexer.peek(), ign);
                ign = null;
            }

            last_pos = lexer.peek().getPos();
            last_line = lexer.peek().getLine();

            int index = index(lexer.peek());
            action[0] = actionTable[state()][0][1];
            action[1] = actionTable[state()][0][2];

            int low = 1;
            int high = actionTable[state()].length - 1;

            while(low <= high)
            {
                int middle = (low + high) / 2;
                
                if(index < actionTable[state()][middle][0])
                {
                    high = middle - 1;
                }
                else if(index > actionTable[state()][middle][0])
                {
                    low = middle + 1;
                }
                else
                {
                    action[0] = actionTable[state()][middle][1];
                    action[1] = actionTable[state()][middle][2];
                    break;
                }
            }

            switch(action[0])
            {
                case SHIFT:
                    push(action[1], lexer.next(), true);
                    last_shift = action[1];
                    break;
                case REDUCE:
                    switch(action[1])
                    {

$

Macro:ParserReduceFilter
                    case $0$: { Node node = new$0$(); push(goTo($1$), node, true); } break;

$

Macro:ParserReduceNoFilter
                    case $0$: { Node node = new$0$(); push(goTo($1$), node, false); } break;

$

Macro:ParserParseTail
                    }
                    break;
                case ACCEPT:
                    {
                        EOF node2 = (EOF) lexer.next();
                        $0$ node1 = ($0$) pop();
                        Start node = new Start(node1, node2);
                        return node;
                    }
                case ERROR:
                    throw new ParserException(
                        "[" + last_line + "," + last_pos + "] " +
                        errorMessages[errors[action[1]]]);
            }
        }
    }


$

Macro:ParserNewHeader
    Node new$0$()
    {

$

Macro:ParserNewBodyDecl
        $0$ node$1$ = ($0$) pop();

$

Macro:ParserNewBodyDeclNull
        $0$ node$1$ = null;

$

Macro:ParserNewBodyNew
        $0$ node = new $0$(
$

Macro:ParserNewBodyParams
$0$node$1$
$

Macro:ParserNewTail
);
        return node;
    }


$

Macro:ParserActionHeader
    private final static int[][][] actionTable =
        {

$

Macro:ParserActionTail
        };

$

Macro:ParserGotoHeader
    private final static int[][][] gotoTable =
        {

$

Macro:ParserGotoTail
        };

$

Macro:ParserErrorsHeader
    private final static String[] errorMessages =
        {

$

Macro:ParserErrorsTail
        };

$

Macro:ParserErrorIndexHeader
    private final static int[] errors =
        {

$

Macro:ParserErrorIndexTail

        };

$

Macro:ParserTail
}

$

Macro:TokenIndexHeader
package $0$;

import $1$.*;
import $2$.*;

class TokenIndex extends AnalysisAdapter
{
    int index;

$

Macro:TokenIndexBody

    public void case$0$($0$ node)
    {
        index = $1$;
    }

$

Macro:TokenIndexTail

    public void caseEOF(EOF node)
    {
        index = $0$;
    }
}

$

Macro:ParserException
package $0$;

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

$

Macro:State
package $0$;

final class State 
{
    int state;
    Object node;

    State(int state, Object node)
    {
        this.state = state;
        this.node = node;
    }
}

$

