FileDocCategorySizeDatePackage
ContentModelState.javaAPI DocJava SE 5 API7273Fri Aug 26 14:58:20 BST 2005javax.swing.text.html.parser

ContentModelState

public class ContentModelState extends Object
A content model state. This is basically a list of pointers to the BNF expression representing the model (the ContentModel). Each element in a DTD has a content model which describes the elements that may occur inside, and the order in which they can occur.

Each time a token is reduced a new state is created.

See Annex H on page 556 of the SGML handbook for more information.

see
Parser
see
DTD
see
Element
see
ContentModel
author
Arthur van Hoff
version
1.11 12/19/03

Fields Summary
ContentModel
model
long
value
ContentModelState
next
Constructors Summary
public ContentModelState(ContentModel model)
Create a content model state for a content model.

	this(model, null, 0);
    
ContentModelState(Object content, ContentModelState next)
Create a content model state for a content model given the remaining state that needs to be reduce.

	this(content, next, 0);
    
ContentModelState(Object content, ContentModelState next, long value)
Create a content model state for a content model given the remaining state that needs to be reduce.

	this.model = (ContentModel)content;
	this.next = next;
	this.value = value;
    
Methods Summary
public javax.swing.text.html.parser.ContentModelStateadvance(java.lang.Object token)
Advance this state to a new state. An exception is thrown if the token is illegal at this point in the content model.

return
next state after reducing a token

	switch (model.type) {
	  case '+":
	    if (model.first(token)) {
		return new ContentModelState(model.content,
		        new ContentModelState(model, next, value + 1)).advance(token);
	    }
	    if (value != 0) {
		if (next != null) {
		    return next.advance(token);
		} else {
		    return null;
		}
	    }
	    break;

	  case '*":
	    if (model.first(token)) {
		return new ContentModelState(model.content, this).advance(token);
	    }
	    if (next != null) {
		return next.advance(token);
	    } else {
		return null;
	    }

	  case '?":
	    if (model.first(token)) {
		return new ContentModelState(model.content, next).advance(token);
	    }
	    if (next != null) {
		return next.advance(token);
	    } else {
		return null;
	    }

	  case '|":
	    for (ContentModel m = (ContentModel)model.content ; m != null ; m = m.next) {
		if (m.first(token)) {
		    return new ContentModelState(m, next).advance(token);
		}
	    }
	    break;

	  case ',": {
	    ContentModel m = (ContentModel)model.content;
	    for (int i = 0 ; i < value ; i++, m = m.next);

	    if (m.first(token) || m.empty()) {
		if (m.next == null) {
		    return new ContentModelState(m, next).advance(token);
		} else {
		    return new ContentModelState(m,
			    new ContentModelState(model, next, value + 1)).advance(token);
		}
	    }
	    break;
	  }

	  case '&": {
	    ContentModel m = (ContentModel)model.content;
	    boolean complete = true;

	    for (int i = 0 ; m != null ; i++, m = m.next) {
		if ((value & (1L << i)) == 0) {
		    if (m.first(token)) {
			return new ContentModelState(m,
			        new ContentModelState(model, next, value | (1L << i))).advance(token);
		    }
		    if (!m.empty()) {
			complete = false;
		    }
		}
	    }
	    if (complete) {
		if (next != null) {
		    return next.advance(token);
		} else {
		    return null;
		}
	    }
	    break;
	  }

	  default:
	    if (model.content == token) {
                if (next == null && (token instanceof Element) &&
                    ((Element)token).content != null) {
                    return new ContentModelState(((Element)token).content);
                }
		return next;
	    }
            // PENDING: Currently we don't correctly deal with optional start 
            // tags. This can most notably be seen with the 4.01 spec where
            // TBODY's start and end tags are optional.
            // Uncommenting this and the PENDING in ContentModel will
            // correctly skip the omit tags, but the delegate is not notified.
            // Some additional API needs to be added to track skipped tags,
            // and this can then be added back.
/*
            if ((model.content instanceof Element)) {
                Element e = (Element)model.content;

                if (e.omitStart() && e.content != null) {
                    return new ContentModelState(e.content, next).advance(
                                           token);
                }
            }
*/
	}

	// We used to throw this exception at this point.  However, it
	// was determined that throwing this exception was more expensive
	// than returning null, and we could not justify to ourselves why
	// it was necessary to throw an exception, rather than simply
	// returning null.  I'm leaving it in a commented out state so
	// that it can be easily restored if the situation ever arises.
	//
	// throw new IllegalArgumentException("invalid token: " + token);
	return null;
    
public javax.swing.text.html.parser.Elementfirst()
Check if the state can be terminated. That is there are no more tokens required in the input stream.

return
the only possible element that can occur next

	switch (model.type) {
	  case '*":
	  case '?":
	  case '|":
	  case '&":
	    return null;

	  case '+":
	    return model.first();

	  case ',": {
	      ContentModel m = (ContentModel)model.content;
	      for (int i = 0 ; i < value ; i++, m = m.next);
	      return m.first();
	  }

	  default:
	    return model.first();
	}
    
public javax.swing.text.html.parser.ContentModelgetModel()
Return the content model that is relevant to the current state.

	ContentModel m = model;
	for (int i = 0; i < value; i++) {
	    if (m.next != null) {
		m = m.next;
	    } else {
		return null;
	    }
	}
        return m;
    
public booleanterminate()
Check if the state can be terminated. That is there are no more tokens required in the input stream.

return
true if the model can terminate without further input

	switch (model.type) {
	  case '+":
	    if ((value == 0) && !(model).empty()) {
		return false;
	    }
	  case '*":
	  case '?":
	    return (next == null) || next.terminate();

	  case '|":
	    for (ContentModel m = (ContentModel)model.content ; m != null ; m = m.next) {
		if (m.empty()) {
		    return (next == null) || next.terminate();
		}
	    }
	    return false;

	  case '&": {
	    ContentModel m = (ContentModel)model.content;

	    for (int i = 0 ; m != null ; i++, m = m.next) {
		if ((value & (1L << i)) == 0) {
		    if (!m.empty()) {
			return false;
		    }
		}
	    }
	    return (next == null) || next.terminate();
	  }

	  case ',": {
	    ContentModel m = (ContentModel)model.content;
	    for (int i = 0 ; i < value ; i++, m = m.next);

	    for (; (m != null) && m.empty() ; m = m.next);
	    if (m != null) {
		return false;
	    }
	    return (next == null) || next.terminate();
	  }

	default:
	  return false;
	}