/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * This file is part of SableCC.                             *
 * See the file "LICENSE" for copyright information and the  *
 * terms and conditions for copying, distribution and        *
 * modification of SableCC.                                  *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

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

package $0$parser;

import java.io.DataInputStream;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

import de.hhu.stups.sablecc.patch.IParser;
import de.hhu.stups.sablecc.patch.PositionedNode;

import $0$lexer.Lexer;
import $0$lexer.LexerException;
import $0$node.*;

@SuppressWarnings({"unchecked", "unused"})
public class Parser implements IParser
{
    private final Lexer lexer;
    private final ListIterator<State> stack = new LinkedList<State>().listIterator();
    private final TokenIndex converter = new TokenIndex();

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

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

    private static void computePositions(PositionedNode node, List<?> beginNodeList, List<?> endNodeList) {
        // This method should only ever be called for newly created AST nodes (that are not tokens).
        assert !(node instanceof Token);
        assert node.getStartPos() == null;
        assert node.getEndPos() == null;

        PositionedNode beginNode = findBeginNode(beginNodeList);
        node.setStartPos(beginNode.getStartPos());

        PositionedNode endNode = findEndNode(endNodeList);
        node.setEndPos(endNode.getEndPos());
    }

    private static PositionedNode findBeginNode(final List<?> list) {
        Object first = list.get(0);
        if (first instanceof List<?>) {
            List<?> list2 = (List<?>) first;
            return (PositionedNode)list2.get(0);
        }

        return (PositionedNode)first;
    }

    private static PositionedNode findEndNode(final List<?> list) {
        Object last = list.get(list.size() - 1);
        if (last instanceof List<?>) {
            final List<?> list2 = (List<?>) last;
            return (PositionedNode)list2.get(list2.size() - 1);
        }

        return (PositionedNode)last;
    }

    private void push(int numstate, List<?> listNode)
    {
        if(!this.stack.hasNext())
        {
            this.stack.add(new State(numstate, listNode));
            return;
        }

        State s = this.stack.next();
        s.state = numstate;
        s.nodes = listNode;
    }

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

        while(low <= high)
        {
            int middle = (low + high) >>> 1;

            if(state < table[middle][0])
            {
                high = middle - 1;
            }
            else if(state > table[middle][0])
            {
                low = middle + 1;
            }
            else
            {
                value = table[middle][1];
                break;
            }
        }

        return value;
    }

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

    private List<?> pop()
    {
        return this.stack.previous().nodes;
    }

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


    public Start parse() throws ParserException, LexerException, IOException
    {
        push(0, null);
        while(true)
        {
            Token lastToken = this.lexer.peek();
            int index = index(lastToken);
            while(index == -1)
            {
                // this is an ignored token
                this.lexer.next();
                lastToken = this.lexer.peek();
                index = index(lastToken);
            }

            int state = state();
            int[][] table = actionTable[state];
            int action = table[0][1];
            int destination = table[0][2];

            int low = 1;
            int high = table.length - 1;

            while(low <= high)
            {
                int middle = (low + high) >>> 1;

                if(index < table[middle][0])
                {
                    high = middle - 1;
                }
                else if(index > table[middle][0])
                {
                    low = middle + 1;
                }
                else
                {
                    action = table[middle][1];
                    destination = table[middle][2];
                    break;
                }
            }

            switch(action)
            {
                case SHIFT:
                    push(destination, Collections.singletonList(this.lexer.next()));
                    break;

                case REDUCE:
                    switch(destination)
                    {

$

Macro:ParserParseReduce
                        case $0$: /* reduce $2$ */
                        {
                            List<?> list = new$0$();
                            push(goTo($1$), list);
                        }
                        break;

$

Macro:ParserParseTail
                        default:
                            throw new ParserException(lastToken, "[" + lastToken.getLine() + "," + lastToken.getPos() + "] Internal parser error: invalid action table REDUCE destination " + destination + ", current state " + state());
                    }
                    break;

                case ACCEPT:
                    EOF eof = (EOF) this.lexer.next();
                    $0$ top = ($0$) pop().get(0);
                    return new Start(top, eof);

                case ERROR:
                    throw new ParserException(lastToken,
                        "[" + lastToken.getLine() + "," + lastToken.getPos() + "] " ,
                        Parser.errorMessages[Parser.errors[destination]]);

                default:
                    throw new ParserException(lastToken, "[" + lastToken.getLine() + "," + lastToken.getPos() + "] Internal parser error: invalid action table entry " + action + ", destination " + destination + ", current state " + state());
            }
        }
    }


$

Macro:ParserNewHeader

    private List<?> new$0$() /* reduce $1$ */
    {

$

Macro:ParserNewBodyDecl
        List<?> popped$0$ = pop();

$

Macro:ParserSimpleTerm
        $0$ $1$ = ($0$)popped$2$.get($3$);

$

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

Macro:ParserNewBodyParam
$0$
$

Macro:ParserNewBodyNewTail
);

$

Macro:ParserTypedSingleElementList
        $0$ $1$;
        if($2$ != null) {
            $1$ = Collections.singletonList($2$);
        } else {
            $1$ = Collections.emptyList();
        }

$

Macro:ParserTypedListAssign
        $0$ $1$ = $2$;

$

Macro:ParserTypedLinkedListInit
        $0$ $1$ = new LinkedList<>();

$

Macro:ParserTypedLinkedListInitAddAll
        $0$ $1$;
        if ($2$ instanceof LinkedList<?>) {
            $1$ = $2$;
        } else {
            $1$ = new LinkedList<>($2$);
        }

$

Macro:ParserTypedLinkedListAdd
        if($1$ != null)
        {
            $0$.add($1$);
        }

$

Macro:ParserTypedLinkedListAddAll
        if ($0$.isEmpty() && $1$ instanceof LinkedList<?>) {
            $0$ = $1$;
        } else {
            $0$.addAll($1$);
        }

$

Macro:ParserNewComputePositions
        computePositions($0$, popped1, popped$1$);

$

Macro:ParserNewTailEmpty
        return Collections.emptyList();
    }

$

Macro:ParserNewTailSingle
        return Collections.singletonList($0$);
    }

$

Macro:ParserNewTailMultiHead
        return Arrays.asList(new Object[] {

$

Macro:ParserNewTailMultiElement
            $0$,

$

Macro:ParserNewTailMultiTail
        });
    }

$

Macro:ParserActionHeader


    private static final int[][][] actionTable;
/*      {

$

Macro:ParserActionTail
        };*/

$

Macro:ParserGotoHeader
    private static final int[][][] gotoTable;
/*      {

$

Macro:ParserGotoTail
        };*/

$

Macro:ParserErrorsHeader
    private static final String[] errorMessages;
/*      {

$

Macro:ParserErrorsTail
        };*/

$

Macro:ParserErrorIndexHeader
    private static final int[] errors;
/*      {

$

Macro:ParserErrorIndexTail

        };*/

$

Macro:ParserTail

    static
    {
        try
        {
            InputStream resStream = Parser.class.getResourceAsStream("parser.dat");
            if(resStream == null)
            {
                throw new RuntimeException("The file \"parser.dat\" is missing.");
            }
            DataInputStream s = new DataInputStream(new BufferedInputStream(resStream));

            // read actionTable
            int actionTableLength1 = s.readInt();
            actionTable = new int[actionTableLength1][][];
            for(int i = 0; i < actionTableLength1; i++)
            {
                int actionTableLength2 = s.readInt();
                actionTable[i] = new int[actionTableLength2][3];
                for(int j = 0; j < actionTableLength2; j++)
                {
                    for(int k = 0; k < 3; k++)
                    {
                        actionTable[i][j][k] = s.readInt();
                    }
                }
            }

            // read gotoTable
            int gotoTableLength1 = s.readInt();
            gotoTable = new int[gotoTableLength1][][];
            for(int i = 0; i < gotoTableLength1; i++)
            {
                int gotoTableLength2 = s.readInt();
                gotoTable[i] = new int[gotoTableLength2][2];
                for(int j = 0; j < gotoTableLength2; j++)
                {
                    for(int k = 0; k < 2; k++)
                    {
                        gotoTable[i][j][k] = s.readInt();
                    }
                }
            }

            // read errorMessages
            int errorMessagesLength = s.readInt();
            errorMessages = new String[errorMessagesLength];
            for(int i = 0; i < errorMessagesLength; i++)
            {
                int errorMessageLength = s.readInt();
                StringBuilder buffer = new StringBuilder();

                for(int j = 0; j < errorMessageLength; j++)
                {
                    buffer.append(s.readChar());
                }
                errorMessages[i] = buffer.toString();
            }

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

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

$

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

package $0$parser;

import $0$analysis.AnalysisAdapter;
import $0$node.*;

class TokenIndex extends AnalysisAdapter
{
    int index;

$

Macro:TokenIndexBody

    @Override
    public void case$0$($0$ node)
    {
        this.index = $1$;
    }

$

Macro:TokenIndexTail

    @Override
    public void caseEOF(EOF node)
    {
        this.index = $0$;
    }
}

$

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

package $0$parser;

import $0$node.*;

@SuppressWarnings("serial")
public class ParserException extends Exception
{
    Token token;
    String realMsg;

    public ParserException(Token token, String message)
    {
        super(message);
        this.token = token;
    }

    public ParserException(Token token, String prefix, String message)
    {
        super(prefix+message);
        this.realMsg = message;
        this.token = token;
    }

    public Token getToken()
    {
        return this.token;
    }

    public String getRealMsg()
    {
        return this.realMsg;
    }
}

$

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

package $0$parser;

import java.util.List;

final class State
{
    int state;
    List<?> nodes; // elements are of type Node or List<Node>

    State(int state, List<?> nodes)
    {
        this.state = state;
        this.nodes = nodes;
    }
}

$
