KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > text > html > parser > ContentModelState


1 /*
2  * @(#)ContentModelState.java 1.11 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing.text.html.parser;
9
10 /**
11  * A content model state. This is basically a list of pointers to
12  * the BNF expression representing the model (the ContentModel).
13  * Each element in a DTD has a content model which describes the
14  * elements that may occur inside, and the order in which they can
15  * occur.
16  * <p>
17  * Each time a token is reduced a new state is created.
18  * <p>
19  * See Annex H on page 556 of the SGML handbook for more information.
20  *
21  * @see Parser
22  * @see DTD
23  * @see Element
24  * @see ContentModel
25  * @author Arthur van Hoff
26  * @version 1.11 12/19/03
27  */

28 class ContentModelState {
29     ContentModel JavaDoc model;
30     long value;
31     ContentModelState JavaDoc next;
32
33     /**
34      * Create a content model state for a content model.
35      */

36     public ContentModelState(ContentModel JavaDoc model) {
37     this(model, null, 0);
38     }
39
40     /**
41      * Create a content model state for a content model given the
42      * remaining state that needs to be reduce.
43      */

44     ContentModelState(Object JavaDoc content, ContentModelState JavaDoc next) {
45     this(content, next, 0);
46     }
47
48     /**
49      * Create a content model state for a content model given the
50      * remaining state that needs to be reduce.
51      */

52     ContentModelState(Object JavaDoc content, ContentModelState JavaDoc next, long value) {
53     this.model = (ContentModel JavaDoc)content;
54     this.next = next;
55     this.value = value;
56     }
57
58     /**
59      * Return the content model that is relevant to the current state.
60      */

61     public ContentModel JavaDoc getModel() {
62     ContentModel JavaDoc m = model;
63     for (int i = 0; i < value; i++) {
64         if (m.next != null) {
65         m = m.next;
66         } else {
67         return null;
68         }
69     }
70         return m;
71     }
72
73     /**
74      * Check if the state can be terminated. That is there are no more
75      * tokens required in the input stream.
76      * @return true if the model can terminate without further input
77      */

78     public boolean terminate() {
79     switch (model.type) {
80       case '+':
81         if ((value == 0) && !(model).empty()) {
82         return false;
83         }
84       case '*':
85       case '?':
86         return (next == null) || next.terminate();
87
88       case '|':
89         for (ContentModel JavaDoc m = (ContentModel JavaDoc)model.content ; m != null ; m = m.next) {
90         if (m.empty()) {
91             return (next == null) || next.terminate();
92         }
93         }
94         return false;
95
96       case '&': {
97         ContentModel JavaDoc m = (ContentModel JavaDoc)model.content;
98
99         for (int i = 0 ; m != null ; i++, m = m.next) {
100         if ((value & (1L << i)) == 0) {
101             if (!m.empty()) {
102             return false;
103             }
104         }
105         }
106         return (next == null) || next.terminate();
107       }
108
109       case ',': {
110         ContentModel JavaDoc m = (ContentModel JavaDoc)model.content;
111         for (int i = 0 ; i < value ; i++, m = m.next);
112
113         for (; (m != null) && m.empty() ; m = m.next);
114         if (m != null) {
115         return false;
116         }
117         return (next == null) || next.terminate();
118       }
119
120     default:
121       return false;
122     }
123     }
124
125     /**
126      * Check if the state can be terminated. That is there are no more
127      * tokens required in the input stream.
128      * @return the only possible element that can occur next
129      */

130     public Element JavaDoc first() {
131     switch (model.type) {
132       case '*':
133       case '?':
134       case '|':
135       case '&':
136         return null;
137
138       case '+':
139         return model.first();
140
141       case ',': {
142           ContentModel JavaDoc m = (ContentModel JavaDoc)model.content;
143           for (int i = 0 ; i < value ; i++, m = m.next);
144           return m.first();
145       }
146
147       default:
148         return model.first();
149     }
150     }
151
152     /**
153      * Advance this state to a new state. An exception is thrown if the
154      * token is illegal at this point in the content model.
155      * @return next state after reducing a token
156      */

157     public ContentModelState JavaDoc advance(Object JavaDoc token) {
158     switch (model.type) {
159       case '+':
160         if (model.first(token)) {
161         return new ContentModelState JavaDoc(model.content,
162                 new ContentModelState JavaDoc(model, next, value + 1)).advance(token);
163         }
164         if (value != 0) {
165         if (next != null) {
166             return next.advance(token);
167         } else {
168             return null;
169         }
170         }
171         break;
172
173       case '*':
174         if (model.first(token)) {
175         return new ContentModelState JavaDoc(model.content, this).advance(token);
176         }
177         if (next != null) {
178         return next.advance(token);
179         } else {
180         return null;
181         }
182
183       case '?':
184         if (model.first(token)) {
185         return new ContentModelState JavaDoc(model.content, next).advance(token);
186         }
187         if (next != null) {
188         return next.advance(token);
189         } else {
190         return null;
191         }
192
193       case '|':
194         for (ContentModel JavaDoc m = (ContentModel JavaDoc)model.content ; m != null ; m = m.next) {
195         if (m.first(token)) {
196             return new ContentModelState JavaDoc(m, next).advance(token);
197         }
198         }
199         break;
200
201       case ',': {
202         ContentModel JavaDoc m = (ContentModel JavaDoc)model.content;
203         for (int i = 0 ; i < value ; i++, m = m.next);
204
205         if (m.first(token) || m.empty()) {
206         if (m.next == null) {
207             return new ContentModelState JavaDoc(m, next).advance(token);
208         } else {
209             return new ContentModelState JavaDoc(m,
210                 new ContentModelState JavaDoc(model, next, value + 1)).advance(token);
211         }
212         }
213         break;
214       }
215
216       case '&': {
217         ContentModel JavaDoc m = (ContentModel JavaDoc)model.content;
218         boolean complete = true;
219
220         for (int i = 0 ; m != null ; i++, m = m.next) {
221         if ((value & (1L << i)) == 0) {
222             if (m.first(token)) {
223             return new ContentModelState JavaDoc(m,
224                     new ContentModelState JavaDoc(model, next, value | (1L << i))).advance(token);
225             }
226             if (!m.empty()) {
227             complete = false;
228             }
229         }
230         }
231         if (complete) {
232         if (next != null) {
233             return next.advance(token);
234         } else {
235             return null;
236         }
237         }
238         break;
239       }
240
241       default:
242         if (model.content == token) {
243                 if (next == null && (token instanceof Element JavaDoc) &&
244                     ((Element JavaDoc)token).content != null) {
245                     return new ContentModelState JavaDoc(((Element JavaDoc)token).content);
246                 }
247         return next;
248         }
249             // PENDING: Currently we don't correctly deal with optional start
250
// tags. This can most notably be seen with the 4.01 spec where
251
// TBODY's start and end tags are optional.
252
// Uncommenting this and the PENDING in ContentModel will
253
// correctly skip the omit tags, but the delegate is not notified.
254
// Some additional API needs to be added to track skipped tags,
255
// and this can then be added back.
256
/*
257             if ((model.content instanceof Element)) {
258                 Element e = (Element)model.content;
259
260                 if (e.omitStart() && e.content != null) {
261                     return new ContentModelState(e.content, next).advance(
262                                            token);
263                 }
264             }
265 */

266     }
267
268     // We used to throw this exception at this point. However, it
269
// was determined that throwing this exception was more expensive
270
// than returning null, and we could not justify to ourselves why
271
// it was necessary to throw an exception, rather than simply
272
// returning null. I'm leaving it in a commented out state so
273
// that it can be easily restored if the situation ever arises.
274
//
275
// throw new IllegalArgumentException("invalid token: " + token);
276
return null;
277     }
278 }
279
Popular Tags