KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > beaver > comp > ParsingTables


1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * This file is part of Beaver Parser Generator. *
3  * Copyright (C) 2003,2004 Alexander Demenchuk <alder@softanvil.com>. *
4  * All rights reserved. *
5  * See the file "LICENSE" for the terms and conditions for copying, *
6  * distribution and modification of Beaver. *
7  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

8
9 package beaver.comp;
10
11 import java.io.DataOutputStream JavaDoc;
12 import java.io.IOException JavaDoc;
13 import java.util.ArrayList JavaDoc;
14 import java.util.Arrays JavaDoc;
15
16 import beaver.spec.Grammar;
17 import beaver.spec.GrammarSymbol;
18 import beaver.spec.Terminal;
19
20 /**
21  * Action tables of the automaton.
22  */

23 class ParsingTables
24 {
25     /** Start of the list of all states. */
26     public final State first_state;
27
28     /** Number of terminals in a grammar */
29     final int n_term;
30
31     /** Actions lookup "table" to be used with terminal lookahead symbols */
32     short[] actions;
33
34     /** A table with "actions" lookaheads. Is used to detect "collisions". */
35     short[] lookaheads;
36
37     /**
38      * For each state, the offset into "actions" table that is used to find action for a terminal that has been fetched
39      * from the scanner.
40      */

41     int[] terminal_offsets;
42
43     /**
44      * For each state, the offset into "actions" table that is used to find action for a nonterminal that has been
45      * created by a reduced production.
46      */

47     int[] nonterminal_offsets;
48
49     /** An index of the last action in the table, i.e. the rest (tail) of the table is unused. */
50     int last_action_index;
51
52     /** Default action for each state */
53     short[] default_actions;
54     
55     /** Indicates whether tables are compressed - states may have default action */
56     boolean compressed;
57
58     ParsingTables(Grammar grammar, State first_state)
59     {
60         int num_states = countStates(first_state);
61
62         this.first_state = first_state;
63         this.n_term = grammar.terminals.length;
64
65         default_actions = new short[num_states + 1];
66         terminal_offsets = new int[num_states + 1];
67         nonterminal_offsets = new int[num_states + 1];
68
69         Arrays.fill(terminal_offsets, UNUSED_OFFSET);
70         Arrays.fill(nonterminal_offsets, UNUSED_OFFSET);
71
72         actions = new short[16384]; // compressed Java 1.2 grammar uses less than 10k
73
lookaheads = new short[actions.length];
74
75         Arrays.fill(lookaheads, (short) -1);
76
77         ArrayList JavaDoc list_of_action_lists = new ArrayList JavaDoc(num_states * 2);
78         for (State state = first_state; state != null; state = state.next)
79         {
80             if (state.default_action != null)
81             {
82                 default_actions[state.id] = state.default_action.getId();
83                 compressed = true;
84             }
85
86             if (state.terminal_lookahead_actions.num_actions > 0)
87             {
88                 list_of_action_lists.add(state.terminal_lookahead_actions);
89             }
90
91             if (state.nonterminal_lookahead_actions.num_actions > 0)
92             {
93                 list_of_action_lists.add(state.nonterminal_lookahead_actions);
94             }
95         }
96         Action.List[] action_lists = (Action.List[]) list_of_action_lists.toArray(new Action.List[list_of_action_lists.size()]);
97         Arrays.sort(action_lists, Action.List.NUM_ACTIONS_CMP);
98
99         renumberSymbols(grammar, action_lists);
100
101         int start_index = 0;
102         for (int i = 0; i < action_lists.length; i++)
103         {
104             Action.List list = action_lists[i];
105             int offset = findOffset(list, start_index);
106             if (list.first.lookahead instanceof Terminal)
107             {
108                 if (terminal_offsets[list.state.id] != UNUSED_OFFSET)
109                     throw new IllegalStateException JavaDoc("terminal offset " + list.state.id + " is used");
110                 terminal_offsets[list.state.id] = offset;
111             }
112             else
113             {
114                 if (nonterminal_offsets[list.state.id] != UNUSED_OFFSET)
115                     throw new IllegalStateException JavaDoc("nonterminal offset " + list.state.id + " is used");
116                 nonterminal_offsets[list.state.id] = offset;
117             }
118             last_action_index = Math.max(last_action_index, offset + list.last.lookahead.id);
119             start_index = advanceStartIndex(start_index);
120         }
121     }
122
123     private void renumberSymbols(Grammar grammar, Action.List[] action_lists)
124     {
125         for (int i = 0; i < action_lists.length; i++)
126         {
127             for (Action act = action_lists[i].first; act != null; act = act.next)
128             {
129                 act.lookahead.nrefs++;
130             }
131         }
132         Arrays.sort(grammar.terminals, 1, grammar.terminals.length, GrammarSymbol.NUMBER_OF_REFERENCES_COMPARATOR);
133         Arrays.sort(grammar.nonterminals, GrammarSymbol.NUMBER_OF_REFERENCES_COMPARATOR);
134
135         for (int i = 1 /* leave EOF alone */; i < grammar.terminals.length; i++)
136         {
137             grammar.terminals[i].id = (short) i;
138         }
139         for (int i = 0; i < grammar.nonterminals.length; i++)
140         {
141             grammar.nonterminals[i].id = (short) (i + grammar.terminals.length);
142         }
143         for (int i = 0; i < action_lists.length; i++)
144         {
145             action_lists[i].sort();
146         }
147     }
148
149     private int advanceStartIndex(int start_index)
150     {
151         while (start_index < actions.length && actions[start_index] != 0)
152             start_index++;
153         return start_index;
154     }
155
156     private int findOffset(Action.List action_list, int start_index)
157     {
158         int min_lookahead_id = action_list.first.lookahead.id;
159         int max_lookahead_id = action_list.last.lookahead.id;
160         int range = max_lookahead_id - min_lookahead_id + 1;
161         
162         while (true) // typically loops once, but may do it several time if initial tables are too small and need expansion
163
{
164             int last_index = actions.length - range;
165     
166             for (int index = start_index; index <= last_index; index++)
167             {
168                 if (actions[index] != 0)
169                     continue;
170     
171                 int offset = index - min_lookahead_id;
172                 if (tryInsertActions(action_list, offset))
173                 {
174                     insertActions(action_list, offset);
175                     return offset;
176                 }
177             }
178             
179             if (actions.length >= 1024 * 1024) // the end of table grows has a very arbitrary limit - need to stop somewhere, and... 1M should be enough for everyone ;-)
180
throw new IllegalStateException JavaDoc("cannot find place for some actions in parsing tables");
181
182             actions = expand(actions);
183             int len = lookaheads.length;
184             lookaheads = expand(lookaheads);
185             Arrays.fill(lookaheads, len, lookaheads.length, (short) -1);
186         }
187     }
188
189     private void insertActions(Action.List action_list, int offset)
190     {
191         for (Action act = action_list.first; act != null; act = act.next)
192         {
193             int index = offset + act.lookahead.id;
194             if (actions[index] != 0)
195                 throw new IllegalStateException JavaDoc("inserting action in occupied slot");
196             actions[index] = act.getId();
197         }
198     }
199
200     private boolean tryInsertActions(Action.List action_list, int offset)
201     {
202         if (canInsertActions(action_list, offset))
203         {
204             insertLookaheads(action_list, offset);
205
206             if (action_list.first.lookahead.id >= n_term || !hasCollisions())
207                 return true;
208
209             removeLookaheads(action_list, offset);
210         }
211         return false;
212     }
213
214     private boolean canInsertActions(Action.List action_list, int offset)
215     {
216         for (Action act = action_list.first; act != null; act = act.next)
217         {
218             if (actions[offset + act.lookahead.id] != 0)
219                 return false;
220         }
221         return true;
222     }
223
224     private void insertLookaheads(Action.List action_list, int offset)
225     {
226         for (Action act = action_list.first; act != null; act = act.next)
227         {
228             int index = offset + act.lookahead.id;
229             if (lookaheads[index] >= 0)
230                 throw new IllegalStateException JavaDoc("lookahead collision during initial insert");
231             lookaheads[index] = act.lookahead.id;
232         }
233     }
234
235     private void removeLookaheads(Action.List action_list, int offset)
236     {
237         for (Action act = action_list.first; act != null; act = act.next)
238         {
239             lookaheads[offset + act.lookahead.id] = -1;
240         }
241     }
242
243     private boolean hasCollisions()
244     {
245         for (State state = first_state; state != null; state = state.next)
246         {
247             int offset = terminal_offsets[state.id];
248             if (offset == UNUSED_OFFSET)
249                 continue;
250
251             Action act = state.terminal_lookahead_actions.first;
252             for (int la = 0; la < n_term; la++)
253             {
254                 if (act != null && act.lookahead.id == la)
255                 {
256                     act = act.next;
257                     continue;
258                 }
259                 int index = offset + la;
260                 if (0 <= index && index < lookaheads.length && lookaheads[index] == la)
261                     return true;
262             }
263         }
264         return false;
265     }
266
267     void writeTo(DataOutputStream JavaDoc data_stream) throws IOException JavaDoc
268     {
269         int len;
270         
271         data_stream.writeInt(len = last_action_index + 1);
272         for (int i = 0; i < len; i++)
273         {
274             data_stream.writeShort(actions[i]);
275         }
276         for (int i = 0; i < len; i++)
277         {
278             data_stream.writeShort(lookaheads[i]);
279         }
280         
281         data_stream.writeInt(len = terminal_offsets.length);
282         for (int i = 0; i < len; i++)
283         {
284             data_stream.writeInt(terminal_offsets[i]);
285         }
286         for (int i = 0; i < len; i++)
287         {
288             data_stream.writeInt(nonterminal_offsets[i]);
289         }
290         
291         data_stream.writeInt(compressed ? len : (len = 0));
292         for (int i = 0; i < len; i++)
293         {
294             data_stream.writeShort(default_actions[i]);
295         }
296     }
297     
298     static final int UNUSED_OFFSET = Integer.MIN_VALUE;
299     
300     static int countStates(State state)
301     {
302         while (state.next != null)
303             state = state.next;
304         return state.id;
305     }
306     
307     static short[] expand(short[] array)
308     {
309         short[] temp = new short[array.length * 2];
310         System.arraycopy(array, 0, temp, 0, array.length);
311         return temp;
312     }
313 }
Popular Tags