]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/parser/generator/java/Parser.java.template
Moved SCL parser generator to platform repository.
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / parser / generator / java / Parser.java.template
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/parser/generator/java/Parser.java.template b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/parser/generator/java/Parser.java.template
new file mode 100644 (file)
index 0000000..233e7ac
--- /dev/null
@@ -0,0 +1,287 @@
+package $package$;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException;
+
+$imports$
+public abstract class $class$ {    
+    public static final boolean TRACE = false;
+
+    private static final int INITIAL_CAPACITY = 16;
+    private static final int STATE_COUNT = $stateCount$;
+    private static final int TERMINAL_COUNT = $terminalCount$;
+    private static final int NONTERMINAL_COUNT = $nonterminalCount$;
+    private static final int PRODUCT_COUNT = $productCount$;
+    
+    private static final int[] ACTION_ROW_ID = new int[STATE_COUNT];
+    private static final int[] ACTION_COLUMN_ID = new int[TERMINAL_COUNT];
+    private static final short[] ACTION_TABLE = new short[$actionTableLength$];
+    private static final int[] ERROR_TABLE = new int[$errorTableLength$];
+    private static final int[] GOTO_ROW_ID = new int[STATE_COUNT];
+    private static final int[] GOTO_COLUMN_ID = new int[NONTERMINAL_COUNT];
+    private static final short[] GOTO_TABLE = new short[$gotoTableLength$];
+    private static final int[] PRODUCT_LHS = new int[PRODUCT_COUNT];
+
+    private static final short STATE_MASK = (short)0x0fff;
+    private static final short REDUCE_MASK = (short)0x8000;
+    private static final short POP_MASK = (short)0x4000;
+    private static final short PUSH_MASK = (short)0x2000;
+    private static final short ERROR_ACTION = (short)0xffff;
+    private static final short ACCEPT_ACTION = (short)0xfffe;
+    
+    public static final String[] TERMINAL_NAMES = new String[] {
+$terminalNames$
+    };
+
+    public static final String[] NONTERMINAL_NAMES = new String[] {
+$nonterminalNames$
+    };
+        
+    static {
+        try {
+            DataInputStream input = new DataInputStream($class$.class.getResourceAsStream("$class$.dat"));
+            for(int i=0;i<ACTION_ROW_ID.length;++i)
+                ACTION_ROW_ID[i] = input.readInt();
+            for(int i=0;i<ACTION_COLUMN_ID.length;++i)
+                ACTION_COLUMN_ID[i] = input.readInt();    
+            for(int i=0;i<ACTION_TABLE.length;++i)
+                ACTION_TABLE[i] = input.readShort();
+            for(int i=0;i<ERROR_TABLE.length;++i)
+                ERROR_TABLE[i] = input.readInt();
+            for(int i=0;i<GOTO_ROW_ID.length;++i)
+                GOTO_ROW_ID[i] = input.readInt();
+            for(int i=0;i<GOTO_COLUMN_ID.length;++i)
+                GOTO_COLUMN_ID[i] = input.readInt();    
+            for(int i=0;i<GOTO_TABLE.length;++i)
+                GOTO_TABLE[i] = input.readShort();
+            for(int i=0;i<PRODUCT_LHS.length;++i)
+                PRODUCT_LHS[i] = input.readInt();
+            input.close();
+        } catch(IOException e) {
+            e.printStackTrace();
+        }
+    }
+    
+    private static short getAction(int state, int symbol) {
+        int id = TERMINAL_COUNT*state + symbol;
+        if( ((ERROR_TABLE[id>>5] >> (id&31))&1) != 0 )
+            return ERROR_ACTION;
+        return ACTION_TABLE[ACTION_ROW_ID[state] + ACTION_COLUMN_ID[symbol]];
+    }
+    
+    private static short getGoto(int state, int symbol) {
+        return GOTO_TABLE[GOTO_ROW_ID[state] + GOTO_COLUMN_ID[symbol]];
+    }
+    
+    protected abstract $Token$ nextToken();
+    
+    private $Symbol$[] symbolStack = new $Symbol$[INITIAL_CAPACITY];
+    private int symbolStackLength = 0;
+    
+    private int[] stateStack = new int[INITIAL_CAPACITY];
+    private int[] symbolStackPositionStack = new int[INITIAL_CAPACITY];
+    private int stateStackLength = 0;
+    
+    // For reduce
+    private int reductionLength;
+    
+    protected int length() {
+        return reductionLength;
+    }
+    
+    protected $Symbol$ get(int i) {
+        if(i < 0 || i >= reductionLength)
+            throw new IndexOutOfBoundsException();
+        return symbolStack[symbolStackLength+i];
+    }
+    
+    private String parseErrorDescription(int state, $Token$ token, int tokenId) {
+        StringBuilder b = new StringBuilder();
+        b.append("Unexpected token '").append(token)
+         .append("' (").append(TERMINAL_NAMES[tokenId])
+         .append("). Expected one of ");
+        ArrayList<String> possibleTerminals = new ArrayList<String>();
+        for(int i=0;i<TERMINAL_COUNT;++i)
+            if(getAction(state, i) != ERROR_ACTION)
+                possibleTerminals.add(TERMINAL_NAMES[i]);
+        Collections.sort(possibleTerminals);
+        for(int i=0;i<possibleTerminals.size();++i) {
+            if(i > 0)
+                b.append(", ");
+            b.append(possibleTerminals.get(i));
+        }
+        b.append('.');
+        return b.toString();
+    }
+    
+    protected abstract RuntimeException syntaxError($Token$ token, String description);
+    
+    private static String describeAction(boolean isGoto, int action) {
+        if(action == ERROR_ACTION)
+            return "ERROR";
+        if(action == ACCEPT_ACTION)
+            return "ACCEPT";
+        StringBuilder b = new StringBuilder();
+        if(isGoto)
+            b.append("GOTO ");
+        else {
+            if((action & REDUCE_MASK) != 0) {
+                action ^= REDUCE_MASK;
+                b.append("REDUCE");
+            }
+            else
+                b.append("SHIFT");
+        }
+        if((action & POP_MASK) != 0) {
+            action ^= POP_MASK;
+            b.append(" POP");
+        }
+        if((action & PUSH_MASK) != 0) {
+            action ^= PUSH_MASK;
+            b.append(" PUSH");
+        }
+        b.append(' ').append(action);
+        return b.toString();
+    }
+    
+    private void printState(int state) {
+        System.out.print("state=" + state + ":");
+        for(int i=symbolStackLength-1,j=stateStackLength-1;i>=0;--i) {
+            Object s = symbolStack[i];
+            if(s instanceof Token)
+                System.out.print(" " + TERMINAL_NAMES[((Token)s).id]);
+            else if(s == null)
+                System.out.print(" null");
+            else
+                System.out.print(" " + s.getClass().getSimpleName());
+            while(j>=0 && symbolStackPositionStack[j]==i)
+                System.out.print(" (" + stateStack[j--] + ")");
+        }
+        System.out.println();
+    }
+    
+    private $Symbol$ parse(int state) {
+        while(true) {
+            $Token$ token = nextToken();
+            int tokenId = token.$tokenId$;
+            if(TRACE)
+                System.out.println("---> token " + TERMINAL_NAMES[tokenId] + " \"" + token.text + "\" <---");
+            while(true) {
+                if(TRACE)
+                    printState(state);
+                short action = getAction(state, tokenId);
+                if(TRACE)
+                    System.out.println("    -> action=" + describeAction(false, action));
+                //System.out.println(STATE_DESCRIPTIONS[state]);
+                if((action & REDUCE_MASK) != 0) {
+                    if(action == ACCEPT_ACTION)
+                        return symbolStack[symbolStackLength-1];
+                    if(action == ERROR_ACTION)
+                        throw syntaxError(token, parseErrorDescription(state, token, tokenId));
+                    int popAmount = (action >>> 13)&3;
+                    if(TRACE) {
+                        if(popAmount > 0)
+                            System.out.println("    POP " + popAmount);
+                    }
+                    stateStackLength -= popAmount;
+                    action &= STATE_MASK;
+                    
+                    int reductionBegin = symbolStackPositionStack[--stateStackLength];
+                    
+                    reductionLength = symbolStackLength-reductionBegin;
+                    symbolStackLength = reductionBegin;
+                    
+                    if(symbolStackLength == symbolStack.length)
+                        symbolStack = Arrays.copyOf(symbolStack, symbolStackLength*2);
+                    $Symbol$ symbol = reduce(action);
+                    postReduce(symbol);
+                    symbolStack[symbolStackLength] = symbol;
+                    
+                    state = stateStack[stateStackLength];
+                    if(TRACE) {
+                        ++symbolStackLength;
+                        printState(state);
+                        --symbolStackLength;
+                        System.out.println("    nonterminal=" + NONTERMINAL_NAMES[PRODUCT_LHS[action]]);
+                    }
+                    action = getGoto(state, PRODUCT_LHS[action]);
+                    if(TRACE)
+                        System.out.println("    -> action=" + describeAction(true, action));
+                        
+                    // Pop state
+                    if((action & POP_MASK) != 0) {
+                        --stateStackLength;
+                    }
+                    // Push state
+                    if((action & PUSH_MASK) != 0) {
+                        if(stateStackLength == stateStack.length) {
+                            stateStack = Arrays.copyOf(stateStack, stateStackLength*2);
+                            symbolStackPositionStack = Arrays.copyOf(symbolStackPositionStack, stateStackLength*2);
+                        }
+                        symbolStackPositionStack[stateStackLength] = symbolStackLength;
+                        stateStack[stateStackLength++] = state;
+                    }
+                    state = action & STATE_MASK;
+                    ++symbolStackLength;
+                }
+                else {
+                    // Pop state
+                    if((action & POP_MASK) != 0) {
+                        --stateStackLength;
+                    }
+                    // Push state
+                    if((action & PUSH_MASK) != 0) {
+                        if(stateStackLength == stateStack.length) {
+                            stateStack = Arrays.copyOf(stateStack, stateStackLength*2);
+                            symbolStackPositionStack = Arrays.copyOf(symbolStackPositionStack, stateStackLength*2);
+                        }
+                        symbolStackPositionStack[stateStackLength] = symbolStackLength;
+                        stateStack[stateStackLength++] = state;
+                    }
+                    
+                    // New state
+                    state = action & STATE_MASK;
+                    
+                    // Push symbol
+                    if(symbolStackLength == symbolStack.length)
+                        symbolStack = Arrays.copyOf(symbolStack, symbolStackLength*2);
+                    symbolStack[symbolStackLength++] = token;
+                    break;
+                }
+            }
+        }
+    }
+    
+$parseMethods$
+
+    protected $Symbol$ reduce(int productionId) {
+        try {
+        switch(productionId) {
+$reduceCases$
+        default:
+            throw new RuntimeException("Internal parser error.");
+        }
+        } catch($Exception$ e) {
+            StringBuilder b = new StringBuilder();
+            b.append("Failed to reduce");
+            for(int i=0;i<length();++i) {
+                Object obj = get(i);
+                b.append("\n    (").append(i).append(") \"").append(obj).append('\"');
+                if(obj instanceof $Token$)
+                    b.append(" (").append(TERMINAL_NAMES[(($Token$)obj).$tokenId$]).append(")");
+                else
+                    b.append(" [").append(obj.getClass().getSimpleName()).append("]");
+            }
+            throw new RuntimeException(b.toString(), e);
+        } 
+    }
+
+$reduceMethods$
+    protected void postReduce($Symbol$ reduced) {
+    }
+
+}