KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > chaperon > build > ParserAutomatonBuilder


1 /*
2  * Copyright (C) Chaperon. All rights reserved.
3  * -------------------------------------------------------------------------
4  * This software is published under the terms of the Apache Software License
5  * version 1.1, a copy of which has been included with this distribution in
6  * the LICENSE file.
7  */

8
9 package net.sourceforge.chaperon.build;
10
11 import net.sourceforge.chaperon.build.conflict.ConflictList;
12 import net.sourceforge.chaperon.build.conflict.ReduceReduceConflict;
13 import net.sourceforge.chaperon.build.conflict.ShiftReduceConflict;
14 import net.sourceforge.chaperon.common.IntegerSet;
15 import net.sourceforge.chaperon.model.Violations;
16 import net.sourceforge.chaperon.model.grammar.Associativity;
17 import net.sourceforge.chaperon.model.grammar.Error;
18 import net.sourceforge.chaperon.model.grammar.Grammar;
19 import net.sourceforge.chaperon.model.symbol.SymbolSet;
20 import net.sourceforge.chaperon.model.symbol.Terminal;
21 import net.sourceforge.chaperon.process.ParserAutomaton;
22
23 import org.apache.commons.logging.Log;
24
25 /**
26  * This class represents a builder for parser automata.
27  *
28  * @author <a HREF="mailto:stephan@apache.org">Stephan Michels</a>
29  * @version CVS $Id: ParserAutomatonBuilder.java,v 1.27 2003/12/14 09:48:33 benedikta Exp $
30  */

31 public class ParserAutomatonBuilder
32 {
33   private static final EndOfFile EOF = new EndOfFile();
34   private Grammar grammar;
35   private SymbolSet tsymbols;
36   private SymbolSet ntsymbols;
37   private FirstSetCollection firstsets;
38   private ItemSetCollection itemsets;
39   private ParserAutomaton automaton;
40   private ConflictList conflicts = new ConflictList();
41   private Log log;
42
43   /**
44    * Create a builder for an parser automaton.
45    *
46    * @param grammar Grammar, which should be used to build the automaton.
47    */

48   public ParserAutomatonBuilder(Grammar grammar)
49   {
50     this(grammar, null);
51   }
52
53   /**
54    * Create a builder for an parser automaton.
55    *
56    * @param grammar Grammar, which should be used to build the automaton.
57    * @param log Log, which should be used.
58    */

59   public ParserAutomatonBuilder(Grammar grammar, Log log)
60   {
61     this.grammar = (Grammar)grammar.clone();
62     this.log = log;
63
64     Violations violations = grammar.validate();
65
66     if ((violations!=null) && (violations.getViolationCount()>0))
67       throw new IllegalArgumentException JavaDoc("Grammar is not valid: "+violations.getViolation(0));
68
69     SymbolSet symbols = grammar.getSymbols();
70
71     tsymbols = symbols.getTerminals();
72     ntsymbols = symbols.getNonterminals();
73
74     //long time = System.currentTimeMillis();
75
// generate all first sets
76
if ((log!=null) && (log.isDebugEnabled()))
77       log.debug("Generating first sets");
78
79     firstsets = new FirstSetCollection(grammar, log);
80     if ((log!=null) && (log.isDebugEnabled()))
81       log.debug(firstsets.toString());
82
83     // calculation of alle states and transitions
84
if ((log!=null) && (log.isDebugEnabled()))
85       log.debug("Building states and transitions");
86
87     itemsets = new ItemSetCollection(grammar, firstsets, log);
88     if ((log!=null) && (log.isDebugEnabled()))
89       log.debug(itemsets.toString());
90
91     if ((log!=null) && (log.isDebugEnabled()))
92       log.debug("Building parser automaton");
93
94     automaton =
95       new ParserAutomaton(tsymbols.getSymbolCount(), ntsymbols.getSymbolCount(),
96                           grammar.getProductionCount(), 0, itemsets.getItemSetCount());
97
98     // for alle terminal symbols
99
for (int i = 0; i<tsymbols.getSymbolCount(); i++)
100       automaton.setTerminal(i, tsymbols.getSymbol(i).getName());
101
102     // for the non terminal symbols
103
for (int i = 0; i<ntsymbols.getSymbolCount(); i++)
104       automaton.setNonterminal(i, ntsymbols.getSymbol(i).getName());
105
106     // for all productions
107
for (int i = 0; i<grammar.getProductionCount(); i++)
108     {
109       automaton.setProductionSymbol(i, ntsymbols.indexOf(grammar.getProduction(i).getSymbol()));
110       automaton.setProductionLength(i, grammar.getProduction(i).getLength());
111     }
112
113     // for all itemsets I in itemsets C
114
for (int state = 0; state<itemsets.getItemSetCount(); state++)
115     {
116       ItemSet I = itemsets.getItemSet(state);
117
118       SymbolSet shiftsymbols = I.getShiftSymbols(); // Transition symbols for shift actions
119
SymbolSet reducesymbols = I.getReduceSymbols(); // Lookahead symbols for reduce actions
120

121       for (int symbol = 0; symbol<tsymbols.getSymbolCount(); symbol++)
122       {
123         IntegerSet reduceproductions = I.getReduceProductions(tsymbols.getSymbol(symbol));
124         int productionpriority = -1;
125         int highestproduction = -1;
126         for (int k = 0; k<reduceproductions.getCount(); k++)
127         {
128           ReduceReduceConflict reduceconflict = null;
129
130           if (k>0)
131           {
132             reduceconflict =
133               new ReduceReduceConflict(grammar, itemsets, state,
134                                        (Terminal)tsymbols.getSymbol(symbol),
135                                        reduceproductions.get(k-1), reduceproductions.get(k));
136
137             conflicts.addConflict(reduceconflict);
138           }
139
140           if (grammar.getPriority(grammar.getProduction(reduceproductions.get(k)))>productionpriority)
141           {
142             highestproduction = reduceproductions.get(k);
143             productionpriority = grammar.getPriority(grammar.getProduction(highestproduction));
144
145             if ((log!=null) && (reduceconflict!=null))
146               log.info(reduceconflict.toString());
147           }
148           else if (grammar.getPriority(grammar.getProduction(reduceproductions.get(k)))==productionpriority)
149           {
150             if (log!=null)
151               log.warn(reduceconflict.toString());
152           }
153         }
154
155         if (reduceproductions.getCount()>1)
156           if ((log!=null) && (log.isInfoEnabled()))
157             log.info("The parser will reduce the production "+
158                      grammar.getProduction(highestproduction));
159
160         boolean errorreduce = reducesymbols.contains(Error.instance);
161
162         if (shiftsymbols.contains(tsymbols.getSymbol(symbol)))
163         {
164           if ((errorreduce) || (reducesymbols.contains(tsymbols.getSymbol(symbol))))
165           {
166             int tokenpriority = grammar.getPriority((Terminal)tsymbols.getSymbol(symbol));
167
168             ShiftReduceConflict shiftconflict =
169               new ShiftReduceConflict(grammar, itemsets, state,
170                                       (Terminal)tsymbols.getSymbol(symbol), highestproduction);
171
172             if (tokenpriority>productionpriority)
173             {
174               automaton.setShiftAction(state, symbol, I.getTransition(tsymbols.getSymbol(symbol)));
175
176               if (log!=null)
177               {
178                 log.info(shiftconflict.toString());
179                 log.info("The parser will shift");
180               }
181             }
182             else if (tokenpriority<productionpriority)
183             {
184               automaton.setReduceAction(state, symbol, highestproduction);
185
186               if (log!=null)
187               {
188                 log.info(shiftconflict.toString());
189                 log.info("The parser will reduce");
190               }
191             }
192             else
193             {
194               if (log!=null)
195                 log.warn(shiftconflict.toString());
196
197               Associativity associativity =
198                 grammar.getAssociativity((Terminal)tsymbols.getSymbol(symbol));
199               if (associativity.equals(Associativity.RIGHT))
200               {
201                 // if the terminal has a right associativity
202
automaton.setShiftAction(state, symbol, I.getTransition(tsymbols.getSymbol(symbol)));
203
204                 if (log!=null)
205                   log.warn("The parser will shift");
206               }
207               else if (associativity.equals(Associativity.LEFT))
208               {
209                 // if the terminal has a left associativity
210
automaton.setReduceAction(state, symbol, highestproduction);
211
212                 if (log!=null)
213                   log.warn("The parser will reduce");
214               }
215               else
216               {
217                 // SHIFT should be always prefered
218
automaton.setShiftAction(state, symbol, I.getTransition(tsymbols.getSymbol(symbol)));
219
220                 if (log!=null)
221                   log.warn("The parser will shift");
222               }
223             }
224           }
225           else
226             automaton.setShiftAction(state, symbol, I.getTransition(tsymbols.getSymbol(symbol)));
227         }
228         else if ((errorreduce) || (reducesymbols.contains(tsymbols.getSymbol(symbol))))
229           automaton.setReduceAction(state, symbol, highestproduction);
230         else
231           for (int i = 0; i<shiftsymbols.getSymbolCount(); i++)
232             if (shiftsymbols.getSymbol(i) instanceof Error JavaDoc)
233               automaton.setErrorAction(state, symbol, I.getTransition(shiftsymbols.getSymbol(i)));
234       }
235
236       // create all actions for the end of file.
237
if (reducesymbols.contains(EOF))
238       {
239         IntegerSet reduceproductions = I.getReduceProductions(EOF);
240         int productionpriority = -1;
241         int highestproduction = -1;
242         for (int k = 0; k<reduceproductions.getCount(); k++)
243         {
244           if (grammar.getPriority(grammar.getProduction(reduceproductions.get(k)))>productionpriority)
245           {
246             highestproduction = reduceproductions.get(k);
247             productionpriority = grammar.getPriority(grammar.getProduction(highestproduction));
248           }
249         }
250
251         if ((grammar.getProduction(highestproduction).getSymbol().equals(grammar.getStartSymbol())))
252           automaton.setAcceptAction(state, highestproduction);
253         else
254           automaton.setReduceAction(state, highestproduction);
255       }
256       else
257         for (int i = 0; i<shiftsymbols.getSymbolCount(); i++)
258           if (shiftsymbols.getSymbol(i) instanceof Error JavaDoc)
259             automaton.setErrorAction(state, I.getTransition(shiftsymbols.getSymbol(i)));
260
261       // create all entries for the goto table
262
for (int symbol = 0; symbol<ntsymbols.getSymbolCount(); symbol++)
263         if (shiftsymbols.contains(ntsymbols.getSymbol(symbol)))
264           automaton.setTransition(state, symbol, I.getTransition(ntsymbols.getSymbol(symbol)));
265     }
266
267     if ((log!=null) && (log.isDebugEnabled()))
268       log.debug("Parser automaton:\n"+automaton.toString());
269   }
270
271   /**
272    * Returns the generated parser automaton. If a error occurs the method will return null.
273    *
274    * @return The parser automaton.
275    */

276   public ParserAutomaton getParserAutomaton()
277   {
278     return automaton;
279   }
280 }
281
Popular Tags