1. /*
  2. * $Id: ContentModelState.java,v 1.1.1.1 2000/11/23 01:53:33 edwingo Exp $
  3. *
  4. * The Apache Software License, Version 1.1
  5. *
  6. *
  7. * Copyright (c) 2000 The Apache Software Foundation. All rights
  8. * reserved.
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions
  12. * are met:
  13. *
  14. * 1. Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. *
  17. * 2. Redistributions in binary form must reproduce the above copyright
  18. * notice, this list of conditions and the following disclaimer in
  19. * the documentation and/or other materials provided with the
  20. * distribution.
  21. *
  22. * 3. The end-user documentation included with the redistribution,
  23. * if any, must include the following acknowledgment:
  24. * "This product includes software developed by the
  25. * Apache Software Foundation (http://www.apache.org/)."
  26. * Alternately, this acknowledgment may appear in the software itself,
  27. * if and wherever such third-party acknowledgments normally appear.
  28. *
  29. * 4. The names "Crimson" and "Apache Software Foundation" must
  30. * not be used to endorse or promote products derived from this
  31. * software without prior written permission. For written
  32. * permission, please contact apache@apache.org.
  33. *
  34. * 5. Products derived from this software may not be called "Apache",
  35. * nor may "Apache" appear in their name, without prior written
  36. * permission of the Apache Software Foundation.
  37. *
  38. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  39. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  40. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  41. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  42. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  43. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  44. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  45. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  46. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  47. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  48. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  49. * SUCH DAMAGE.
  50. * ====================================================================
  51. *
  52. * This software consists of voluntary contributions made by many
  53. * individuals on behalf of the Apache Software Foundation and was
  54. * originally based on software copyright (c) 1999, Sun Microsystems, Inc.,
  55. * http://www.sun.com. For more information on the Apache Software
  56. * Foundation, please see <http://www.apache.org/>.
  57. */
  58. package org.apache.crimson.parser;
  59. /**
  60. * A content model state. This is basically an index into a content
  61. * model node, emulating an automaton with primitives to consume tokens.
  62. * It may create new content model states as a consequence of that
  63. * consumption, or modify the current state. "Next" is used to track
  64. * states that are pending completion after the "current automaton"
  65. * completes its task.
  66. *
  67. * @see ContentModel
  68. * @see ValidatingParser
  69. *
  70. * @author David Brownell
  71. * @author Arthur van Hoff
  72. * @version $Revision: 1.1.1.1 $
  73. */
  74. class ContentModelState
  75. {
  76. private ContentModel model;
  77. private boolean sawOne;
  78. private ContentModelState next;
  79. /**
  80. * Create a content model state for a content model. When
  81. * the state advances to null, this automaton has finished.
  82. */
  83. ContentModelState (ContentModel model)
  84. {
  85. this (model, null);
  86. }
  87. /**
  88. * Create a content model state for a content model, stacking
  89. * a state for subsequent processing.
  90. */
  91. private ContentModelState (Object content, ContentModelState next)
  92. {
  93. this.model = (ContentModel)content;
  94. this.next = next;
  95. this.sawOne = false;
  96. }
  97. /**
  98. * Check if the state can be terminated. That is, there are no more
  99. * tokens required in the input stream.
  100. * @return true if the model can terminate without further input
  101. */
  102. boolean terminate ()
  103. {
  104. switch (model.type) {
  105. case '+':
  106. if (!sawOne && !((ContentModel)model).empty ())
  107. return false;
  108. // FALLTHROUGH
  109. case '*':
  110. case '?':
  111. return (next == null) || next.terminate ();
  112. case '|':
  113. return model.empty () && (next == null || next.terminate ());
  114. case ',':
  115. ContentModel m;
  116. for (m = model; (m != null) && m.empty () ; m = m.next)
  117. continue;
  118. if (m != null)
  119. return false;
  120. return (next == null) || next.terminate ();
  121. case 0:
  122. return false;
  123. default:
  124. throw new InternalError ();
  125. }
  126. }
  127. /**
  128. * Advance this state to a new state, or throw an
  129. * exception (use a more appropriate one?) if the
  130. * token is illegal at this point in the content model.
  131. * The current state is modified if possible, conserving
  132. * memory that's already been allocated.
  133. * @return next state after reducing a token
  134. */
  135. ContentModelState advance (String token)
  136. throws EndOfInputException
  137. {
  138. switch (model.type) {
  139. case '+':
  140. case '*':
  141. if (model.first (token)) {
  142. sawOne = true;
  143. if (model.content instanceof String)
  144. return this;
  145. return new ContentModelState (model.content, this)
  146. .advance (token);
  147. }
  148. if ((model.type == '*' || sawOne) && next != null)
  149. return next.advance (token);
  150. break;
  151. case '?':
  152. if (model.first (token)) {
  153. if (model.content instanceof String)
  154. return next;
  155. return new ContentModelState (model.content, next)
  156. .advance (token);
  157. }
  158. if (next != null)
  159. return next.advance (token);
  160. break;
  161. case '|':
  162. for (ContentModel m = model; m != null; m = m.next) {
  163. if (m.content instanceof String) {
  164. if (token == m.content)
  165. return next;
  166. continue;
  167. }
  168. if (((ContentModel)m.content).first (token))
  169. return new ContentModelState (m.content, next)
  170. .advance (token);
  171. }
  172. if (model.empty () && next != null)
  173. return next.advance (token);
  174. break;
  175. case ',':
  176. if (model.first (token)) {
  177. ContentModelState nextState;
  178. if (model.type == 0)
  179. return next;
  180. if (model.next == null)
  181. nextState = new ContentModelState (model.content, next);
  182. else {
  183. nextState = new ContentModelState (model.content, this);
  184. model = model.next;
  185. }
  186. return nextState.advance (token);
  187. } else if (model.empty () && next != null) {
  188. return next.advance (token);
  189. }
  190. break;
  191. case 0:
  192. if (model.content == token)
  193. return next;
  194. // FALLTHROUGH
  195. default:
  196. // FALLTHROUGH
  197. }
  198. throw new EndOfInputException ();
  199. }
  200. }