KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > chaperon > process > extended > ExtendedBacktrackingParserProcessor


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.process.extended;
10
11 import net.sourceforge.chaperon.common.Decoder;
12 import net.sourceforge.chaperon.model.extended.ExtendedGrammar;
13
14 import org.apache.commons.logging.Log;
15
16 import org.xml.sax.Attributes JavaDoc;
17 import org.xml.sax.ContentHandler JavaDoc;
18 import org.xml.sax.Locator JavaDoc;
19 import org.xml.sax.SAXException JavaDoc;
20 import org.xml.sax.ext.LexicalHandler JavaDoc;
21 import org.xml.sax.helpers.AttributesImpl JavaDoc;
22 import org.xml.sax.helpers.LocatorImpl JavaDoc;
23
24 /**
25  * This class represents a simulation of a pushdown automata using the parser automaton class.
26  *
27  * @author <a HREF="mailto:stephan@apache.org">Stephan Michels</a>
28  * @version CVS $Id: ExtendedBacktrackingParserProcessor.java,v 1.1 2004/01/04 16:49:12 benedikta Exp $
29  */

30 public class ExtendedBacktrackingParserProcessor implements ContentHandler JavaDoc, LexicalHandler JavaDoc
31 {
32   /** Namespace and element names for the consumed SAX events. */
33   public static final String JavaDoc NS = "http://chaperon.sourceforge.net/schema/text/1.0";
34   public static final String JavaDoc TEXT = "text";
35
36   /** Namespace and element names for the generated SAX events. */
37   public static final String JavaDoc NS_OUTPUT = "http://chaperon.sourceforge.net/schema/syntaxtree/2.0";
38   public static final String JavaDoc OUTPUT = "output";
39   public static final String JavaDoc ERROR = "error";
40
41   /** Content handler and locator facilities */
42   private ContentHandler JavaDoc contentHandler = null;
43   private LexicalHandler JavaDoc lexicalHandler = null;
44   private Locator JavaDoc locator = null;
45   private LocatorImpl JavaDoc locatorImpl = null;
46
47   /** State of consumed input */
48   private static final int STATE_OUTER = 0;
49   private static final int STATE_INNER = 1;
50   private int state = STATE_OUTER;
51
52   /** Internals */
53   private ExtendedParserAutomaton automaton;
54   private ExtendedGrammar grammar;
55   private boolean flatten = false;
56   private StackNode stackNode = null;
57   private Log log;
58   private CharBuffer buffer = new CharBuffer();
59   private StackNode topmost = null;
60
61   /**
62    * Create a new parser processor.
63    */

64   public ExtendedBacktrackingParserProcessor() {}
65
66   /**
67    * Create a new parser processor.
68    *
69    * @param automaton Parser automaton, which the processor should ues.
70    * @param handler Handler, which should receives the parser events.
71    * @param log Log, which should used.
72    */

73   public ExtendedBacktrackingParserProcessor(ExtendedParserAutomaton automaton, Log log)
74   {
75     this.automaton = automaton;
76     this.log = log;
77   }
78
79   /**
80    * Set the parser automaton for the processor.
81    *
82    * @param automaton Parser automaton.
83    */

84   public void setExtendedParserAutomaton(ExtendedParserAutomaton automaton)
85   {
86     this.automaton = automaton;
87     this.grammar = automaton.getExtendedGrammar();
88   }
89
90   /**
91    * Set the <code>ContentHandler</code> that will receive XML data.
92    */

93   public void setContentHandler(ContentHandler JavaDoc handler)
94   {
95     this.contentHandler = handler;
96   }
97
98   /**
99    * Set the <code>LexicalHandler</code> that will receive XML data.
100    */

101   public void setLexicalHandler(LexicalHandler JavaDoc handler)
102   {
103     this.lexicalHandler = handler;
104   }
105
106   /**
107    * Provide processor with a log.
108    *
109    * @param log The log.
110    */

111   public void setLog(Log log)
112   {
113     this.log = log;
114   }
115
116   /**
117    * If the adapter should produce a more flatten XML hirachy, which means elements which the same
118    * name will be collapsed
119    *
120    * @param flatten True, if a more flatten hirachy should be produced.
121    */

122   public void setFlatten(boolean flatten)
123   {
124     this.flatten = flatten;
125   }
126
127   /**
128    * Receive an object for locating the origin of SAX document events.
129    */

130   public void setDocumentLocator(Locator JavaDoc locator)
131   {
132     this.locator = locator;
133
134     if (locator!=null)
135     {
136       this.locatorImpl = new LocatorImpl JavaDoc(locator);
137       contentHandler.setDocumentLocator(locatorImpl);
138     }
139   }
140
141   /**
142    * Receive notification of the beginning of a document.
143    */

144   public void startDocument() throws SAXException JavaDoc
145   {
146     locatorImpl.setLineNumber(locator.getLineNumber());
147     locatorImpl.setColumnNumber(locator.getColumnNumber());
148     contentHandler.startDocument();
149     state = STATE_OUTER;
150   }
151
152   /**
153    * Receive notification of the beginning of an element.
154    */

155   public void startElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qName, Attributes JavaDoc atts)
156     throws SAXException JavaDoc
157   {
158     locatorImpl.setLineNumber(locator.getLineNumber());
159     locatorImpl.setColumnNumber(locator.getColumnNumber());
160
161     if (state==STATE_INNER)
162       throw new SAXException JavaDoc("Unexpected element "+qName);
163
164     if (state==STATE_OUTER)
165     {
166       if ((namespaceURI!=null) && (namespaceURI.equals(NS)))
167       {
168         if (!localName.equals(TEXT))
169           throw new SAXException JavaDoc("Unknown element "+qName);
170       }
171       else
172       {
173         contentHandler.startElement(namespaceURI, localName, qName, atts);
174         return;
175       }
176     }
177
178     state = STATE_INNER;
179
180     // ======================= Start Text Document =======================
181
buffer.clear();
182     stackNode = new TerminalStackNode('\u0000', automaton.first, null);
183     topmost = stackNode;
184   }
185
186   /**
187    * Receive notification of character data.
188    */

189   public void characters(char[] text, int textstart, int textlength)
190     throws SAXException JavaDoc
191   {
192     locatorImpl.setLineNumber(locator.getLineNumber());
193     locatorImpl.setColumnNumber(locator.getColumnNumber());
194
195     if (state==STATE_OUTER)
196     {
197       contentHandler.characters(text, textstart, textlength);
198
199       return;
200     }
201
202     if ((log!=null) && (log.isDebugEnabled()))
203       log.debug("getting text "+Decoder.toString(new String JavaDoc(text, textstart, textlength)));
204
205     buffer.push(text, textstart, textlength);
206   }
207
208   /**
209    * Receive notification of the end of an element.
210    */

211   public void endElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qName)
212     throws SAXException JavaDoc
213   {
214     locatorImpl.setLineNumber(locator.getLineNumber());
215     locatorImpl.setColumnNumber(locator.getColumnNumber());
216
217     if (state==STATE_OUTER)
218       contentHandler.endElement(namespaceURI, localName, qName);
219
220     if (state==STATE_INNER)
221     {
222       if ((namespaceURI!=null) && (namespaceURI.equals(NS)))
223       {
224         if (!localName.equals(TEXT))
225           throw new SAXException JavaDoc("Unknown element "+qName);
226       }
227       else
228         throw new SAXException JavaDoc("Unexpected element "+qName);
229     }
230
231     // ======================= End Text Document =======================
232
while (stackNode!=null)
233     {
234       if ((log!=null) && (log.isDebugEnabled()) && (buffer.available()))
235         log.debug("process "+Decoder.toChar(buffer.peek()));
236
237       //log.debug("State "+automaton.indexOf(stackNode.state)+" "+stackNode.toCanonicalString(automaton));
238

239       /* ============================ Reduce =================================== */
240       ShiftAction shiftAction = null;
241       ReduceAction[] reduceActions;
242
243       if (buffer.available())
244       {
245 outer:
246         while (((shiftAction = stackNode.state.getShiftAction(buffer.peek()))==null) &&
247                ((reduceActions = stackNode.state.getReduceActions()).length>0))
248         {
249           reduceActions = stackNode.state.getReduceActions();
250
251           for (int index = 0; index<=reduceActions.length; index++)
252           {
253             if (index==reduceActions.length)
254               break outer;
255
256             ReduceAction reduceAction = reduceActions[index];
257
258             StackNode second = (reduceAction.length==2) ? stackNode : null;
259             StackNode first = (reduceAction.length==2) ? second.ancestor : null;
260             StackNode previousStackNode = (reduceAction.length==2) ? first.ancestor : stackNode;
261
262             GotoAction gotoAction =
263               (reduceAction.symbol!=null)
264               ? previousStackNode.state.getGotoAction(reduceAction.symbol)
265               : previousStackNode.state.getGotoAction(reduceAction.pattern);
266
267             if (gotoAction!=null)
268             {
269               if ((log!=null) && (log.isDebugEnabled()))
270                 log.debug("State "+automaton.indexOf(stackNode.state)+" "+reduceAction);
271
272               stackNode =
273                 new DefinitionStackNode(reduceAction, index, first, second, gotoAction.state,
274                                         previousStackNode);
275
276               topmost = topmost.getTopMost(stackNode);
277
278               break;
279             }
280           }
281         }
282       }
283       else
284       {
285         while ((reduceActions = stackNode.state.getReduceActions()).length>0)
286         {
287           ReduceAction reduceAction = reduceActions[0];
288
289           StackNode second = (reduceAction.length==2) ? stackNode : null;
290           StackNode first = (reduceAction.length==2) ? second.ancestor : null;
291           StackNode previousStackNode = (reduceAction.length==2) ? first.ancestor : stackNode;
292
293           GotoAction gotoAction =
294             (reduceAction.symbol!=null)
295             ? previousStackNode.state.getGotoAction(reduceAction.symbol)
296             : previousStackNode.state.getGotoAction(reduceAction.pattern);
297
298           if ((automaton.first==previousStackNode.state) &&
299               (grammar.getStartSymbol().equals(reduceAction.symbol)))
300           {
301             if ((log!=null) && (log.isDebugEnabled()))
302               log.debug("State "+automaton.indexOf(stackNode.state)+" accept");
303
304             stackNode =
305               new DefinitionStackNode(reduceAction, 0, first, second, null, previousStackNode);
306             fireEvents();
307
308             state = STATE_OUTER;
309
310             return;
311           }
312           else
313           {
314             if ((log!=null) && (log.isDebugEnabled()))
315               log.debug("State "+automaton.indexOf(stackNode.state)+" "+reduceAction);
316
317             stackNode =
318               new DefinitionStackNode(reduceAction, 0, first, second, gotoAction.state,
319                                       previousStackNode);
320           }
321         }
322       }
323
324       /* ==================================== Shift =================================== */
325       if (shiftAction!=null)
326       {
327         if ((log!=null) && (log.isDebugEnabled()))
328           log.debug("State "+automaton.indexOf(stackNode.state)+" "+shiftAction);
329
330         stackNode = new TerminalStackNode(buffer.read(), shiftAction.state, stackNode);
331
332         topmost = topmost.getTopMost(stackNode);
333       }
334       else
335       {
336         if ((log!=null) && (log.isDebugEnabled()))
337           if (buffer.available())
338             log.debug("State "+automaton.indexOf(stackNode.state)+" error "+
339                       Decoder.toChar(buffer.peek()));
340           else
341             log.debug("State "+automaton.indexOf(stackNode.state)+" error EOF");
342
343         //if (buffer.available())
344
// buffer.back(); // push character back into buffer
345
backtrack();
346       }
347     }
348
349     if (buffer.available())
350       throw new IllegalArgumentException JavaDoc("Character "+Decoder.toChar(buffer.peek())+
351                                          " is not expected");
352     else
353       throw new IllegalArgumentException JavaDoc("Eon of file is not expected");
354   }
355
356   private void backtrack() throws SAXException JavaDoc
357   {
358     while (automaton.first!=stackNode.state)
359     {
360       if ((log!=null) && (log.isDebugEnabled()))
361         log.debug("State "+automaton.indexOf(stackNode.state)+" backtracking");
362
363       if (stackNode instanceof DefinitionStackNode)
364       {
365         DefinitionStackNode definitionStackNode = (DefinitionStackNode)stackNode;
366         stackNode =
367           (definitionStackNode.action.length==0) ? stackNode.ancestor : definitionStackNode.second;
368
369         ReduceAction[] reduceActions = stackNode.state.getReduceActions();
370
371         if (reduceActions.length>(definitionStackNode.index+1))
372         {
373           // another reduction is possible
374
ReduceAction reduceAction = reduceActions[definitionStackNode.index+1];
375
376           StackNode second = (reduceAction.length==2) ? stackNode : null;
377           StackNode first = (reduceAction.length==2) ? second.ancestor : null;
378           StackNode previousStackNode = (reduceAction.length==2) ? first.ancestor : stackNode;
379
380           GotoAction gotoAction =
381             (reduceAction.symbol!=null)
382             ? previousStackNode.state.getGotoAction(reduceAction.symbol)
383             : previousStackNode.state.getGotoAction(reduceAction.pattern);
384
385           if ((log!=null) && (log.isDebugEnabled()))
386             log.debug("State "+automaton.indexOf(stackNode.state)+" "+reduceAction);
387
388           stackNode =
389             new DefinitionStackNode(reduceAction, definitionStackNode.index+1, first, second,
390                                     gotoAction.state, previousStackNode);
391
392           // reparse text
393
return;
394         }
395
396         // else no other action is possible, going deeper
397
}
398       else
399       {
400         TerminalStackNode terminalStackNode = (TerminalStackNode)stackNode;
401         stackNode = stackNode.ancestor;
402
403         ReduceAction[] reduceActions = stackNode.state.getReduceActions();
404
405         buffer.back();
406
407         if (reduceActions.length>0)
408         {
409           // reduction is possible instead of shift action
410
ReduceAction reduceAction = reduceActions[0];
411
412           StackNode second = (reduceAction.length==2) ? stackNode : null;
413           StackNode first = (reduceAction.length==2) ? second.ancestor : null;
414           StackNode previousStackNode = (reduceAction.length==2) ? first.ancestor : stackNode;
415
416           GotoAction gotoAction =
417             (reduceAction.symbol!=null)
418             ? previousStackNode.state.getGotoAction(reduceAction.symbol)
419             : previousStackNode.state.getGotoAction(reduceAction.pattern);
420
421           if ((log!=null) && (log.isDebugEnabled()))
422             log.debug("State "+automaton.indexOf(stackNode.state)+" "+reduceAction);
423
424           stackNode =
425             new DefinitionStackNode(reduceAction, 0, first, second, gotoAction.state,
426                                     previousStackNode);
427
428           return;
429         }
430
431         // else no other action is possible, going deeper
432
}
433     }
434
435     throw new SAXException JavaDoc("Could not recognize text at ["+topmost.lineNumber+":"+
436                            topmost.columnNumber+"]");
437   }
438
439   private void fireEvents() throws SAXException JavaDoc
440   {
441     contentHandler.startPrefixMapping("", NS_OUTPUT);
442     contentHandler.startElement(NS_OUTPUT, OUTPUT, OUTPUT, new AttributesImpl JavaDoc());
443
444     stackNode.toXML(contentHandler);
445
446     contentHandler.endElement(NS_OUTPUT, OUTPUT, OUTPUT);
447     contentHandler.endPrefixMapping("");
448   }
449
450   /**
451    * Receive notification of ignorable whitespace in element content.
452    */

453   public void ignorableWhitespace(char[] ch, int start, int length)
454     throws SAXException JavaDoc
455   {
456     locatorImpl.setLineNumber(locator.getLineNumber());
457     locatorImpl.setColumnNumber(locator.getColumnNumber());
458
459     if (state==STATE_OUTER)
460       contentHandler.ignorableWhitespace(ch, start, length);
461   }
462
463   /**
464    * Begin the scope of a prefix-URI Namespace mapping.
465    */

466   public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri)
467     throws SAXException JavaDoc
468   {
469     locatorImpl.setLineNumber(locator.getLineNumber());
470     locatorImpl.setColumnNumber(locator.getColumnNumber());
471
472     contentHandler.startPrefixMapping(prefix, uri);
473   }
474
475   /**
476    * End the scope of a prefix-URI mapping.
477    */

478   public void endPrefixMapping(String JavaDoc prefix) throws SAXException JavaDoc
479   {
480     locatorImpl.setLineNumber(locator.getLineNumber());
481     locatorImpl.setColumnNumber(locator.getColumnNumber());
482
483     contentHandler.endPrefixMapping(prefix);
484   }
485
486   /**
487    * Receive notification of a processing instruction.
488    */

489   public void processingInstruction(String JavaDoc target, String JavaDoc data)
490     throws SAXException JavaDoc
491   {
492     locatorImpl.setLineNumber(locator.getLineNumber());
493     locatorImpl.setColumnNumber(locator.getColumnNumber());
494
495     if (state==STATE_OUTER)
496       contentHandler.processingInstruction(target, data);
497   }
498
499   /**
500    * Receive notification of a skipped entity.
501    */

502   public void skippedEntity(String JavaDoc name) throws SAXException JavaDoc
503   {
504     locatorImpl.setLineNumber(locator.getLineNumber());
505     locatorImpl.setColumnNumber(locator.getColumnNumber());
506
507     if (state==STATE_OUTER)
508       contentHandler.skippedEntity(name);
509   }
510
511   /**
512    * Receive notification of the end of a document.
513    */

514   public void endDocument() throws SAXException JavaDoc
515   {
516     locatorImpl.setLineNumber(locator.getLineNumber());
517     locatorImpl.setColumnNumber(locator.getColumnNumber());
518
519     contentHandler.endDocument();
520   }
521
522   /**
523    * Report the start of DTD declarations, if any.
524    */

525   public void startDTD(String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId)
526     throws SAXException JavaDoc
527   {
528     if (lexicalHandler!=null)
529       lexicalHandler.startDTD(name, publicId, systemId);
530   }
531
532   /**
533    * Report the end of DTD declarations.
534    */

535   public void endDTD() throws SAXException JavaDoc
536   {
537     if (lexicalHandler!=null)
538       lexicalHandler.endDTD();
539   }
540
541   /**
542    * Report the beginning of an entity.
543    */

544   public void startEntity(String JavaDoc name) throws SAXException JavaDoc
545   {
546     if (lexicalHandler!=null)
547       lexicalHandler.startEntity(name);
548   }
549
550   /**
551    * Report the end of an entity.
552    */

553   public void endEntity(String JavaDoc name) throws SAXException JavaDoc
554   {
555     if (lexicalHandler!=null)
556       lexicalHandler.endEntity(name);
557   }
558
559   /**
560    * Report the start of a CDATA section.
561    */

562   public void startCDATA() throws SAXException JavaDoc
563   {
564     if (lexicalHandler!=null)
565       lexicalHandler.startCDATA();
566   }
567
568   /**
569    * Report the end of a CDATA section.
570    */

571   public void endCDATA() throws SAXException JavaDoc
572   {
573     if (lexicalHandler!=null)
574       lexicalHandler.endCDATA();
575   }
576
577   /**
578    * Report an XML comment anywhere in the document.
579    */

580   public void comment(char[] ch, int start, int len) throws SAXException JavaDoc
581   {
582     if (lexicalHandler!=null)
583       lexicalHandler.comment(ch, start, len);
584   }
585 }
586
Popular Tags