Save This Page
Home » openjdk-7 » javax » swing » text » html » parser » [javadoc | source]
    1   /*
    2    * Copyright 1998-2000 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package javax.swing.text.html.parser;
   27   
   28   /**
   29    * A content model state. This is basically a list of pointers to
   30    * the BNF expression representing the model (the ContentModel).
   31    * Each element in a DTD has a content model which describes the
   32    * elements that may occur inside, and the order in which they can
   33    * occur.
   34    * <p>
   35    * Each time a token is reduced a new state is created.
   36    * <p>
   37    * See Annex H on page 556 of the SGML handbook for more information.
   38    *
   39    * @see Parser
   40    * @see DTD
   41    * @see Element
   42    * @see ContentModel
   43    * @author Arthur van Hoff
   44    */
   45   class ContentModelState {
   46       ContentModel model;
   47       long value;
   48       ContentModelState next;
   49   
   50       /**
   51        * Create a content model state for a content model.
   52        */
   53       public ContentModelState(ContentModel model) {
   54           this(model, null, 0);
   55       }
   56   
   57       /**
   58        * Create a content model state for a content model given the
   59        * remaining state that needs to be reduce.
   60        */
   61       ContentModelState(Object content, ContentModelState next) {
   62           this(content, next, 0);
   63       }
   64   
   65       /**
   66        * Create a content model state for a content model given the
   67        * remaining state that needs to be reduce.
   68        */
   69       ContentModelState(Object content, ContentModelState next, long value) {
   70           this.model = (ContentModel)content;
   71           this.next = next;
   72           this.value = value;
   73       }
   74   
   75       /**
   76        * Return the content model that is relevant to the current state.
   77        */
   78       public ContentModel getModel() {
   79           ContentModel m = model;
   80           for (int i = 0; i < value; i++) {
   81               if (m.next != null) {
   82                   m = m.next;
   83               } else {
   84                   return null;
   85               }
   86           }
   87           return m;
   88       }
   89   
   90       /**
   91        * Check if the state can be terminated. That is there are no more
   92        * tokens required in the input stream.
   93        * @return true if the model can terminate without further input
   94        */
   95       public boolean terminate() {
   96           switch (model.type) {
   97             case '+':
   98               if ((value == 0) && !(model).empty()) {
   99                   return false;
  100               }
  101             case '*':
  102             case '?':
  103               return (next == null) || next.terminate();
  104   
  105             case '|':
  106               for (ContentModel m = (ContentModel)model.content ; m != null ; m = m.next) {
  107                   if (m.empty()) {
  108                       return (next == null) || next.terminate();
  109                   }
  110               }
  111               return false;
  112   
  113             case '&': {
  114               ContentModel m = (ContentModel)model.content;
  115   
  116               for (int i = 0 ; m != null ; i++, m = m.next) {
  117                   if ((value & (1L << i)) == 0) {
  118                       if (!m.empty()) {
  119                           return false;
  120                       }
  121                   }
  122               }
  123               return (next == null) || next.terminate();
  124             }
  125   
  126             case ',': {
  127               ContentModel m = (ContentModel)model.content;
  128               for (int i = 0 ; i < value ; i++, m = m.next);
  129   
  130               for (; (m != null) && m.empty() ; m = m.next);
  131               if (m != null) {
  132                   return false;
  133               }
  134               return (next == null) || next.terminate();
  135             }
  136   
  137           default:
  138             return false;
  139           }
  140       }
  141   
  142       /**
  143        * Check if the state can be terminated. That is there are no more
  144        * tokens required in the input stream.
  145        * @return the only possible element that can occur next
  146        */
  147       public Element first() {
  148           switch (model.type) {
  149             case '*':
  150             case '?':
  151             case '|':
  152             case '&':
  153               return null;
  154   
  155             case '+':
  156               return model.first();
  157   
  158             case ',': {
  159                 ContentModel m = (ContentModel)model.content;
  160                 for (int i = 0 ; i < value ; i++, m = m.next);
  161                 return m.first();
  162             }
  163   
  164             default:
  165               return model.first();
  166           }
  167       }
  168   
  169       /**
  170        * Advance this state to a new state. An exception is thrown if the
  171        * token is illegal at this point in the content model.
  172        * @return next state after reducing a token
  173        */
  174       public ContentModelState advance(Object token) {
  175           switch (model.type) {
  176             case '+':
  177               if (model.first(token)) {
  178                   return new ContentModelState(model.content,
  179                           new ContentModelState(model, next, value + 1)).advance(token);
  180               }
  181               if (value != 0) {
  182                   if (next != null) {
  183                       return next.advance(token);
  184                   } else {
  185                       return null;
  186                   }
  187               }
  188               break;
  189   
  190             case '*':
  191               if (model.first(token)) {
  192                   return new ContentModelState(model.content, this).advance(token);
  193               }
  194               if (next != null) {
  195                   return next.advance(token);
  196               } else {
  197                   return null;
  198               }
  199   
  200             case '?':
  201               if (model.first(token)) {
  202                   return new ContentModelState(model.content, next).advance(token);
  203               }
  204               if (next != null) {
  205                   return next.advance(token);
  206               } else {
  207                   return null;
  208               }
  209   
  210             case '|':
  211               for (ContentModel m = (ContentModel)model.content ; m != null ; m = m.next) {
  212                   if (m.first(token)) {
  213                       return new ContentModelState(m, next).advance(token);
  214                   }
  215               }
  216               break;
  217   
  218             case ',': {
  219               ContentModel m = (ContentModel)model.content;
  220               for (int i = 0 ; i < value ; i++, m = m.next);
  221   
  222               if (m.first(token) || m.empty()) {
  223                   if (m.next == null) {
  224                       return new ContentModelState(m, next).advance(token);
  225                   } else {
  226                       return new ContentModelState(m,
  227                               new ContentModelState(model, next, value + 1)).advance(token);
  228                   }
  229               }
  230               break;
  231             }
  232   
  233             case '&': {
  234               ContentModel m = (ContentModel)model.content;
  235               boolean complete = true;
  236   
  237               for (int i = 0 ; m != null ; i++, m = m.next) {
  238                   if ((value & (1L << i)) == 0) {
  239                       if (m.first(token)) {
  240                           return new ContentModelState(m,
  241                                   new ContentModelState(model, next, value | (1L << i))).advance(token);
  242                       }
  243                       if (!m.empty()) {
  244                           complete = false;
  245                       }
  246                   }
  247               }
  248               if (complete) {
  249                   if (next != null) {
  250                       return next.advance(token);
  251                   } else {
  252                       return null;
  253                   }
  254               }
  255               break;
  256             }
  257   
  258             default:
  259               if (model.content == token) {
  260                   if (next == null && (token instanceof Element) &&
  261                       ((Element)token).content != null) {
  262                       return new ContentModelState(((Element)token).content);
  263                   }
  264                   return next;
  265               }
  266               // PENDING: Currently we don't correctly deal with optional start
  267               // tags. This can most notably be seen with the 4.01 spec where
  268               // TBODY's start and end tags are optional.
  269               // Uncommenting this and the PENDING in ContentModel will
  270               // correctly skip the omit tags, but the delegate is not notified.
  271               // Some additional API needs to be added to track skipped tags,
  272               // and this can then be added back.
  273   /*
  274               if ((model.content instanceof Element)) {
  275                   Element e = (Element)model.content;
  276   
  277                   if (e.omitStart() && e.content != null) {
  278                       return new ContentModelState(e.content, next).advance(
  279                                              token);
  280                   }
  281               }
  282   */
  283           }
  284   
  285           // We used to throw this exception at this point.  However, it
  286           // was determined that throwing this exception was more expensive
  287           // than returning null, and we could not justify to ourselves why
  288           // it was necessary to throw an exception, rather than simply
  289           // returning null.  I'm leaving it in a commented out state so
  290           // that it can be easily restored if the situation ever arises.
  291           //
  292           // throw new IllegalArgumentException("invalid token: " + token);
  293           return null;
  294       }
  295   }

Save This Page
Home » openjdk-7 » javax » swing » text » html » parser » [javadoc | source]