1 package org.simantics.scl.compiler.parser.grammar.input;
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;
9 public abstract class GrammarParser {
10 public static final boolean TRACE = true;
12 private static final int INITIAL_CAPACITY = 16;
13 private static final int STATE_COUNT = 19;
14 private static final int TERMINAL_COUNT = 16;
15 private static final int NONTERMINAL_COUNT = 6;
16 private static final int PRODUCT_COUNT = 8;
18 private static final int[] ACTION_ROW_ID = new int[STATE_COUNT];
19 private static final int[] ACTION_COLUMN_ID = new int[TERMINAL_COUNT];
20 private static final short[] ACTION_TABLE = new short[56];
21 private static final int[] ERROR_TABLE = new int[10];
22 private static final int[] GOTO_ROW_ID = new int[STATE_COUNT];
23 private static final int[] GOTO_COLUMN_ID = new int[NONTERMINAL_COUNT];
24 private static final short[] GOTO_TABLE = new short[12];
25 private static final int[] PRODUCT_LHS = new int[PRODUCT_COUNT];
27 private static final short STATE_MASK = (short)0x0fff;
28 private static final short REDUCE_MASK = (short)0x8000;
29 private static final short POP_MASK = (short)0x4000;
30 private static final short PUSH_MASK = (short)0x2000;
31 private static final short ERROR_ACTION = (short)0xffff;
32 private static final short ACCEPT_ACTION = (short)0xfffe;
34 public static final String[] TERMINAL_NAMES = new String[] {
53 public static final String[] NONTERMINAL_NAMES = new String[] {
64 DataInputStream input = new DataInputStream(GrammarParser.class.getResourceAsStream("GrammarParser.dat"));
65 for(int i=0;i<ACTION_ROW_ID.length;++i)
66 ACTION_ROW_ID[i] = input.readInt();
67 for(int i=0;i<ACTION_COLUMN_ID.length;++i)
68 ACTION_COLUMN_ID[i] = input.readInt();
69 for(int i=0;i<ACTION_TABLE.length;++i)
70 ACTION_TABLE[i] = input.readShort();
71 for(int i=0;i<ERROR_TABLE.length;++i)
72 ERROR_TABLE[i] = input.readInt();
73 for(int i=0;i<GOTO_ROW_ID.length;++i)
74 GOTO_ROW_ID[i] = input.readInt();
75 for(int i=0;i<GOTO_COLUMN_ID.length;++i)
76 GOTO_COLUMN_ID[i] = input.readInt();
77 for(int i=0;i<GOTO_TABLE.length;++i)
78 GOTO_TABLE[i] = input.readShort();
79 for(int i=0;i<PRODUCT_LHS.length;++i)
80 PRODUCT_LHS[i] = input.readInt();
82 } catch(IOException e) {
87 private static short getAction(int state, int symbol) {
88 int id = TERMINAL_COUNT*state + symbol;
89 if( ((ERROR_TABLE[id>>5] >> (id&31))&1) != 0 )
91 return ACTION_TABLE[ACTION_ROW_ID[state] + ACTION_COLUMN_ID[symbol]];
94 private static short getGoto(int state, int symbol) {
95 return GOTO_TABLE[GOTO_ROW_ID[state] + GOTO_COLUMN_ID[symbol]];
98 protected abstract Token nextToken();
100 private Object[] symbolStack = new Object[INITIAL_CAPACITY];
101 private int symbolStackLength = 0;
103 private int[] stateStack = new int[INITIAL_CAPACITY];
104 private int[] symbolStackPositionStack = new int[INITIAL_CAPACITY];
105 private int stateStackLength = 0;
108 private int reductionLength;
110 protected int length() {
111 return reductionLength;
114 protected Object get(int i) {
115 if(i < 0 || i >= reductionLength)
116 throw new IndexOutOfBoundsException();
117 return symbolStack[symbolStackLength+i];
120 private String parseErrorDescription(int state, Token token, int tokenId) {
121 StringBuilder b = new StringBuilder();
122 b.append("Unexpected token '").append(token)
123 .append("' (").append(TERMINAL_NAMES[tokenId])
124 .append("). Expected one of ");
125 ArrayList<String> possibleTerminals = new ArrayList<String>();
126 for(int i=0;i<TERMINAL_COUNT;++i)
127 if(getAction(state, i) != ERROR_ACTION)
128 possibleTerminals.add(TERMINAL_NAMES[i]);
129 Collections.sort(possibleTerminals);
130 for(int i=0;i<possibleTerminals.size();++i) {
133 b.append(possibleTerminals.get(i));
139 protected abstract RuntimeException syntaxError(Token token, String description);
141 private static String describeAction(boolean isGoto, int action) {
142 if(action == ERROR_ACTION)
144 if(action == ACCEPT_ACTION)
146 StringBuilder b = new StringBuilder();
150 if((action & REDUCE_MASK) != 0) {
151 action ^= REDUCE_MASK;
157 if((action & POP_MASK) != 0) {
161 if((action & PUSH_MASK) != 0) {
165 b.append(' ').append(action);
169 private void printState(int state) {
170 System.out.print("state=" + state + ":");
171 for(int i=symbolStackLength-1,j=stateStackLength-1;i>=0;--i) {
172 Object s = symbolStack[i];
173 if(s instanceof Token)
174 System.out.print(" " + TERMINAL_NAMES[((Token)s).id]);
176 System.out.print(" null");
178 System.out.print(" " + s.getClass().getSimpleName());
179 while(j>=0 && symbolStackPositionStack[j]==i)
180 System.out.print(" (" + stateStack[j--] + ")");
182 System.out.println();
185 private Object parse(int state) {
187 Token token = nextToken();
188 int tokenId = token.id;
190 System.out.println("---> token " + TERMINAL_NAMES[tokenId] + " \"" + token.text + "\" <---");
194 short action = getAction(state, tokenId);
196 System.out.println(" -> action=" + describeAction(false, action));
197 //System.out.println(STATE_DESCRIPTIONS[state]);
198 if((action & REDUCE_MASK) != 0) {
199 if(action == ACCEPT_ACTION)
200 return symbolStack[symbolStackLength-1];
201 if(action == ERROR_ACTION)
202 throw syntaxError(token, parseErrorDescription(state, token, tokenId));
203 int popAmount = (action >>> 13)&3;
206 System.out.println(" POP " + popAmount);
208 stateStackLength -= popAmount;
209 action &= STATE_MASK;
211 int reductionBegin = symbolStackPositionStack[--stateStackLength];
213 reductionLength = symbolStackLength-reductionBegin;
214 symbolStackLength = reductionBegin;
216 if(symbolStackLength == symbolStack.length)
217 symbolStack = Arrays.copyOf(symbolStack, symbolStackLength*2);
218 Object symbol = reduce(action);
220 symbolStack[symbolStackLength] = symbol;
222 state = stateStack[stateStackLength];
227 System.out.println(" nonterminal=" + NONTERMINAL_NAMES[PRODUCT_LHS[action]]);
229 action = getGoto(state, PRODUCT_LHS[action]);
231 System.out.println(" -> action=" + describeAction(true, action));
234 if((action & POP_MASK) != 0) {
238 if((action & PUSH_MASK) != 0) {
239 if(stateStackLength == stateStack.length) {
240 stateStack = Arrays.copyOf(stateStack, stateStackLength*2);
241 symbolStackPositionStack = Arrays.copyOf(symbolStackPositionStack, stateStackLength*2);
243 symbolStackPositionStack[stateStackLength] = symbolStackLength;
244 stateStack[stateStackLength++] = state;
246 state = action & STATE_MASK;
251 if((action & POP_MASK) != 0) {
255 if((action & PUSH_MASK) != 0) {
256 if(stateStackLength == stateStack.length) {
257 stateStack = Arrays.copyOf(stateStack, stateStackLength*2);
258 symbolStackPositionStack = Arrays.copyOf(symbolStackPositionStack, stateStackLength*2);
260 symbolStackPositionStack[stateStackLength] = symbolStackLength;
261 stateStack[stateStackLength++] = state;
265 state = action & STATE_MASK;
268 if(symbolStackLength == symbolStack.length)
269 symbolStack = Arrays.copyOf(symbolStack, symbolStackLength*2);
270 symbolStack[symbolStackLength++] = token;
277 public Object parseFile() {
282 protected Object reduce(int productionId) {
284 switch(productionId) {
288 return reduceProduction();
290 return reduceInitial();
292 return reduceProductionRhs();
294 return reduceConcatenation();
296 return reduceTerminal();
298 return reduceUnion();
301 throw new RuntimeException("Internal parser error.");
303 } catch(RuntimeException e) {
304 StringBuilder b = new StringBuilder();
305 b.append("Failed to reduce");
306 for(int i=0;i<length();++i) {
308 b.append("\n (").append(i).append(") \"").append(obj).append('\"');
309 if(obj instanceof Token)
310 b.append(" (").append(TERMINAL_NAMES[((Token)obj).id]).append(")");
312 b.append(" [").append(obj.getClass().getSimpleName()).append("]");
314 throw new RuntimeException(b.toString(), e);
319 * file ::= declaration declaration*
321 protected abstract Object reduceFile();
323 * declaration ::= NONTERMINAL EQUALS prod (BAR prod)* SEMICOLON
325 protected abstract Object reduceProduction();
327 * declaration ::= INITIAL NONTERMINAL SEMICOLON
329 protected abstract Object reduceInitial();
331 * prod ::= regexps HASH (TERMINAL COMMA (SHIFT | REDUCE))* TERMINAL
333 protected abstract Object reduceProductionRhs();
335 * regexps ::= (regexp (regexp | STAR | PLUS | OPTIONAL)*)?
337 protected abstract Object reduceConcatenation();
339 * regexp ::= NONTERMINAL | INITIAL | TERMINAL | SHIFT | REDUCE
341 protected abstract Object reduceTerminal();
343 * regexp ::= LPAREN regexps (BAR regexps)* RPAREN
345 protected abstract Object reduceUnion();
347 protected void postReduce(Object reduced) {