]> gerrit.simantics Code Review - simantics/platform.git/blob - 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
1 package $package$;
2
3 import java.io.DataInputStream;
4 import java.io.IOException;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.Collections;
8 import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException;
9
10 $imports$
11 public abstract class $class$ {    
12     public static final boolean TRACE = false;
13
14     private static final int INITIAL_CAPACITY = 16;
15     private static final int STATE_COUNT = $stateCount$;
16     private static final int TERMINAL_COUNT = $terminalCount$;
17     private static final int NONTERMINAL_COUNT = $nonterminalCount$;
18     private static final int PRODUCT_COUNT = $productCount$;
19     
20     private static final int[] ACTION_ROW_ID = new int[STATE_COUNT];
21     private static final int[] ACTION_COLUMN_ID = new int[TERMINAL_COUNT];
22     private static final short[] ACTION_TABLE = new short[$actionTableLength$];
23     private static final int[] ERROR_TABLE = new int[$errorTableLength$];
24     private static final int[] GOTO_ROW_ID = new int[STATE_COUNT];
25     private static final int[] GOTO_COLUMN_ID = new int[NONTERMINAL_COUNT];
26     private static final short[] GOTO_TABLE = new short[$gotoTableLength$];
27     private static final int[] PRODUCT_LHS = new int[PRODUCT_COUNT];
28
29     private static final short STATE_MASK = (short)0x0fff;
30     private static final short REDUCE_MASK = (short)0x8000;
31     private static final short POP_MASK = (short)0x4000;
32     private static final short PUSH_MASK = (short)0x2000;
33     private static final short ERROR_ACTION = (short)0xffff;
34     private static final short ACCEPT_ACTION = (short)0xfffe;
35     
36     public static final String[] TERMINAL_NAMES = new String[] {
37 $terminalNames$
38     };
39
40     public static final String[] NONTERMINAL_NAMES = new String[] {
41 $nonterminalNames$
42     };
43         
44     static {
45         try {
46             DataInputStream input = new DataInputStream($class$.class.getResourceAsStream("$class$.dat"));
47             for(int i=0;i<ACTION_ROW_ID.length;++i)
48                 ACTION_ROW_ID[i] = input.readInt();
49             for(int i=0;i<ACTION_COLUMN_ID.length;++i)
50                 ACTION_COLUMN_ID[i] = input.readInt();    
51             for(int i=0;i<ACTION_TABLE.length;++i)
52                 ACTION_TABLE[i] = input.readShort();
53             for(int i=0;i<ERROR_TABLE.length;++i)
54                 ERROR_TABLE[i] = input.readInt();
55             for(int i=0;i<GOTO_ROW_ID.length;++i)
56                 GOTO_ROW_ID[i] = input.readInt();
57             for(int i=0;i<GOTO_COLUMN_ID.length;++i)
58                 GOTO_COLUMN_ID[i] = input.readInt();    
59             for(int i=0;i<GOTO_TABLE.length;++i)
60                 GOTO_TABLE[i] = input.readShort();
61             for(int i=0;i<PRODUCT_LHS.length;++i)
62                 PRODUCT_LHS[i] = input.readInt();
63             input.close();
64         } catch(IOException e) {
65             e.printStackTrace();
66         }
67     }
68     
69     private static short getAction(int state, int symbol) {
70         int id = TERMINAL_COUNT*state + symbol;
71         if( ((ERROR_TABLE[id>>5] >> (id&31))&1) != 0 )
72             return ERROR_ACTION;
73         return ACTION_TABLE[ACTION_ROW_ID[state] + ACTION_COLUMN_ID[symbol]];
74     }
75     
76     private static short getGoto(int state, int symbol) {
77         return GOTO_TABLE[GOTO_ROW_ID[state] + GOTO_COLUMN_ID[symbol]];
78     }
79     
80     protected abstract $Token$ nextToken();
81     
82     private $Symbol$[] symbolStack = new $Symbol$[INITIAL_CAPACITY];
83     private int symbolStackLength = 0;
84     
85     private int[] stateStack = new int[INITIAL_CAPACITY];
86     private int[] symbolStackPositionStack = new int[INITIAL_CAPACITY];
87     private int stateStackLength = 0;
88     
89     // For reduce
90     private int reductionLength;
91     
92     protected int length() {
93         return reductionLength;
94     }
95     
96     protected $Symbol$ get(int i) {
97         if(i < 0 || i >= reductionLength)
98             throw new IndexOutOfBoundsException();
99         return symbolStack[symbolStackLength+i];
100     }
101     
102     private String parseErrorDescription(int state, $Token$ token, int tokenId) {
103         StringBuilder b = new StringBuilder();
104         b.append("Unexpected token '").append(token)
105          .append("' (").append(TERMINAL_NAMES[tokenId])
106          .append("). Expected one of ");
107         ArrayList<String> possibleTerminals = new ArrayList<String>();
108         for(int i=0;i<TERMINAL_COUNT;++i)
109             if(getAction(state, i) != ERROR_ACTION)
110                 possibleTerminals.add(TERMINAL_NAMES[i]);
111         Collections.sort(possibleTerminals);
112         for(int i=0;i<possibleTerminals.size();++i) {
113             if(i > 0)
114                 b.append(", ");
115             b.append(possibleTerminals.get(i));
116         }
117         b.append('.');
118         return b.toString();
119     }
120     
121     protected abstract RuntimeException syntaxError($Token$ token, String description);
122     
123     private static String describeAction(boolean isGoto, int action) {
124         if(action == ERROR_ACTION)
125             return "ERROR";
126         if(action == ACCEPT_ACTION)
127             return "ACCEPT";
128         StringBuilder b = new StringBuilder();
129         if(isGoto)
130             b.append("GOTO ");
131         else {
132             if((action & REDUCE_MASK) != 0) {
133                 action ^= REDUCE_MASK;
134                 b.append("REDUCE");
135             }
136             else
137                 b.append("SHIFT");
138         }
139         if((action & POP_MASK) != 0) {
140             action ^= POP_MASK;
141             b.append(" POP");
142         }
143         if((action & PUSH_MASK) != 0) {
144             action ^= PUSH_MASK;
145             b.append(" PUSH");
146         }
147         b.append(' ').append(action);
148         return b.toString();
149     }
150     
151     private void printState(int state) {
152         System.out.print("state=" + state + ":");
153         for(int i=symbolStackLength-1,j=stateStackLength-1;i>=0;--i) {
154             Object s = symbolStack[i];
155             if(s instanceof Token)
156                 System.out.print(" " + TERMINAL_NAMES[((Token)s).id]);
157             else if(s == null)
158                 System.out.print(" null");
159             else
160                 System.out.print(" " + s.getClass().getSimpleName());
161             while(j>=0 && symbolStackPositionStack[j]==i)
162                 System.out.print(" (" + stateStack[j--] + ")");
163         }
164         System.out.println();
165     }
166     
167     private $Symbol$ parse(int state) {
168         while(true) {
169             $Token$ token = nextToken();
170             int tokenId = token.$tokenId$;
171             if(TRACE)
172                 System.out.println("---> token " + TERMINAL_NAMES[tokenId] + " \"" + token.text + "\" <---");
173             while(true) {
174                 if(TRACE)
175                     printState(state);
176                 short action = getAction(state, tokenId);
177                 if(TRACE)
178                     System.out.println("    -> action=" + describeAction(false, action));
179                 //System.out.println(STATE_DESCRIPTIONS[state]);
180                 if((action & REDUCE_MASK) != 0) {
181                     if(action == ACCEPT_ACTION)
182                         return symbolStack[symbolStackLength-1];
183                     if(action == ERROR_ACTION)
184                         throw syntaxError(token, parseErrorDescription(state, token, tokenId));
185                     int popAmount = (action >>> 13)&3;
186                     if(TRACE) {
187                         if(popAmount > 0)
188                             System.out.println("    POP " + popAmount);
189                     }
190                     stateStackLength -= popAmount;
191                     action &= STATE_MASK;
192                     
193                     int reductionBegin = symbolStackPositionStack[--stateStackLength];
194                     
195                     reductionLength = symbolStackLength-reductionBegin;
196                     symbolStackLength = reductionBegin;
197                     
198                     if(symbolStackLength == symbolStack.length)
199                         symbolStack = Arrays.copyOf(symbolStack, symbolStackLength*2);
200                     $Symbol$ symbol = reduce(action);
201                     postReduce(symbol);
202                     symbolStack[symbolStackLength] = symbol;
203                     
204                     state = stateStack[stateStackLength];
205                     if(TRACE) {
206                         ++symbolStackLength;
207                         printState(state);
208                         --symbolStackLength;
209                         System.out.println("    nonterminal=" + NONTERMINAL_NAMES[PRODUCT_LHS[action]]);
210                     }
211                     action = getGoto(state, PRODUCT_LHS[action]);
212                     if(TRACE)
213                         System.out.println("    -> action=" + describeAction(true, action));
214                         
215                     // Pop state
216                     if((action & POP_MASK) != 0) {
217                         --stateStackLength;
218                     }
219                     // Push state
220                     if((action & PUSH_MASK) != 0) {
221                         if(stateStackLength == stateStack.length) {
222                             stateStack = Arrays.copyOf(stateStack, stateStackLength*2);
223                             symbolStackPositionStack = Arrays.copyOf(symbolStackPositionStack, stateStackLength*2);
224                         }
225                         symbolStackPositionStack[stateStackLength] = symbolStackLength;
226                         stateStack[stateStackLength++] = state;
227                     }
228                     state = action & STATE_MASK;
229                     ++symbolStackLength;
230                 }
231                 else {
232                     // Pop state
233                     if((action & POP_MASK) != 0) {
234                         --stateStackLength;
235                     }
236                     // Push state
237                     if((action & PUSH_MASK) != 0) {
238                         if(stateStackLength == stateStack.length) {
239                             stateStack = Arrays.copyOf(stateStack, stateStackLength*2);
240                             symbolStackPositionStack = Arrays.copyOf(symbolStackPositionStack, stateStackLength*2);
241                         }
242                         symbolStackPositionStack[stateStackLength] = symbolStackLength;
243                         stateStack[stateStackLength++] = state;
244                     }
245                     
246                     // New state
247                     state = action & STATE_MASK;
248                     
249                     // Push symbol
250                     if(symbolStackLength == symbolStack.length)
251                         symbolStack = Arrays.copyOf(symbolStack, symbolStackLength*2);
252                     symbolStack[symbolStackLength++] = token;
253                     break;
254                 }
255             }
256         }
257     }
258     
259 $parseMethods$
260
261     protected $Symbol$ reduce(int productionId) {
262         try {
263         switch(productionId) {
264 $reduceCases$
265         default:
266             throw new RuntimeException("Internal parser error.");
267         }
268         } catch($Exception$ e) {
269             StringBuilder b = new StringBuilder();
270             b.append("Failed to reduce");
271             for(int i=0;i<length();++i) {
272                 Object obj = get(i);
273                 b.append("\n    (").append(i).append(") \"").append(obj).append('\"');
274                 if(obj instanceof $Token$)
275                     b.append(" (").append(TERMINAL_NAMES[(($Token$)obj).$tokenId$]).append(")");
276                 else
277                     b.append(" [").append(obj.getClass().getSimpleName()).append("]");
278             }
279             throw new RuntimeException(b.toString(), e);
280         } 
281     }
282
283 $reduceMethods$
284     protected void postReduce($Symbol$ reduced) {
285     }
286
287 }