DTDAutomata.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. //
  2. // Mono.Xml.DTDAutomata
  3. //
  4. // Author:
  5. // Atsushi Enomoto ([email protected])
  6. //
  7. // (C)2003 Atsushi Enomoto
  8. //
  9. using System;
  10. using System.Collections;
  11. using System.Text;
  12. using System.Xml;
  13. using System.Xml.Schema;
  14. using Mono.Xml.Schema;
  15. namespace Mono.Xml
  16. {
  17. public class DTDAutomataFactory
  18. {
  19. public DTDAutomataFactory (DTDObjectModel root)
  20. {
  21. this.root = root;
  22. }
  23. DTDObjectModel root;
  24. Hashtable choiceTable = new Hashtable ();
  25. Hashtable sequenceTable = new Hashtable ();
  26. public DTDChoiceAutomata Choice (DTDAutomata left, DTDAutomata right)
  27. {
  28. Hashtable rightPool = choiceTable [left] as Hashtable;
  29. if (rightPool == null) {
  30. rightPool = new Hashtable ();
  31. choiceTable [left] = rightPool;
  32. }
  33. DTDChoiceAutomata result = rightPool [right] as DTDChoiceAutomata;
  34. if (result == null) {
  35. result = new DTDChoiceAutomata (root, left, right);
  36. rightPool [right] = result;
  37. }
  38. return result;
  39. }
  40. public DTDSequenceAutomata Sequence (DTDAutomata left, DTDAutomata right)
  41. {
  42. Hashtable rightPool = sequenceTable [left] as Hashtable;
  43. if (rightPool == null) {
  44. rightPool = new Hashtable ();
  45. sequenceTable [left] = rightPool;
  46. }
  47. DTDSequenceAutomata result = rightPool [right] as DTDSequenceAutomata;
  48. if (result == null) {
  49. result = new DTDSequenceAutomata (root, left, right);
  50. rightPool [right] = result;
  51. }
  52. return result;
  53. }
  54. }
  55. public abstract class DTDAutomata
  56. {
  57. public DTDAutomata (DTDObjectModel root)
  58. {
  59. this.root = root;
  60. }
  61. private DTDObjectModel root;
  62. public DTDObjectModel Root {
  63. get { return root; }
  64. }
  65. public DTDAutomata MakeChoice (DTDAutomata other)
  66. {
  67. if (this == Root.Invalid)
  68. return other;
  69. if (other == Root.Invalid)
  70. return this;
  71. if (this == Root.Empty && other == Root.Empty)
  72. return this;
  73. if (this == Root.Any && other == Root.Any)
  74. return this;
  75. else if (other == Root.Empty)
  76. return Root.Factory.Choice (other, this);
  77. else
  78. return Root.Factory.Choice (this, other);
  79. }
  80. public DTDAutomata MakeSequence (DTDAutomata other)
  81. {
  82. if (this == Root.Invalid || other == Root.Invalid)
  83. return Root.Invalid;
  84. if (this == Root.Empty)
  85. return other;
  86. if (other == Root.Empty)
  87. return this;
  88. else
  89. return Root.Factory.Sequence (this, other);
  90. }
  91. public abstract DTDAutomata TryStartElement (string name);
  92. public virtual DTDAutomata TryEndElement ()
  93. {
  94. return Root.Invalid;
  95. }
  96. public virtual bool Emptiable {
  97. get { return false; }
  98. }
  99. }
  100. public class DTDElementAutomata : DTDAutomata
  101. {
  102. public DTDElementAutomata (DTDObjectModel root, string name)
  103. : base (root)
  104. {
  105. this.name = name;
  106. }
  107. private string name;
  108. public string Name {
  109. get { return name; }
  110. }
  111. public override DTDAutomata TryStartElement (string name)
  112. {
  113. if (name == Name)
  114. return Root.Empty;
  115. else
  116. return Root.Invalid;
  117. }
  118. }
  119. public class DTDChoiceAutomata : DTDAutomata
  120. {
  121. public DTDChoiceAutomata (DTDObjectModel root,
  122. DTDAutomata left, DTDAutomata right)
  123. : base (root)
  124. {
  125. this.left = left;
  126. this.right = right;
  127. }
  128. private DTDAutomata left;
  129. private DTDAutomata right;
  130. public DTDAutomata Left {
  131. get { return left; }
  132. }
  133. public DTDAutomata Right {
  134. get { return right; }
  135. }
  136. public override DTDAutomata TryStartElement (string name)
  137. {
  138. return left.TryStartElement (name).MakeChoice (
  139. right.TryStartElement (name));
  140. }
  141. public override DTDAutomata TryEndElement ()
  142. {
  143. return left.TryEndElement ().MakeChoice (right.TryEndElement ());
  144. }
  145. bool hasComputedEmptiable;
  146. bool cachedEmptiable;
  147. public override bool Emptiable {
  148. get {
  149. if (!hasComputedEmptiable) {
  150. cachedEmptiable = left.Emptiable ||
  151. right.Emptiable;
  152. hasComputedEmptiable = true;
  153. }
  154. return cachedEmptiable;
  155. }
  156. }
  157. }
  158. public class DTDSequenceAutomata : DTDAutomata
  159. {
  160. public DTDSequenceAutomata (DTDObjectModel root,
  161. DTDAutomata left, DTDAutomata right)
  162. : base (root)
  163. {
  164. this.left = left;
  165. this.right = right;
  166. }
  167. private DTDAutomata left;
  168. private DTDAutomata right;
  169. public DTDAutomata Left {
  170. get { return left; }
  171. }
  172. public DTDAutomata Right {
  173. get { return right; }
  174. }
  175. public override DTDAutomata TryStartElement (string name)
  176. {
  177. DTDAutomata afterL = left.TryStartElement (name);
  178. DTDAutomata afterR = right.TryStartElement (name);
  179. if (afterL == Root.Invalid)
  180. return (left.Emptiable) ? afterR : afterL;
  181. // else
  182. DTDAutomata whenLeftConsumed = afterL.MakeSequence (right);
  183. if (left.Emptiable)
  184. return afterR.MakeChoice (whenLeftConsumed);
  185. else
  186. return whenLeftConsumed;
  187. }
  188. public override DTDAutomata TryEndElement ()
  189. {
  190. return left.Emptiable ? right : Root.Invalid;
  191. }
  192. bool hasComputedEmptiable;
  193. bool cachedEmptiable;
  194. public override bool Emptiable {
  195. get {
  196. if (!hasComputedEmptiable) {
  197. cachedEmptiable = left.Emptiable &&
  198. right.Emptiable;
  199. hasComputedEmptiable = true;
  200. }
  201. return cachedEmptiable;
  202. }
  203. }
  204. }
  205. public class DTDOneOrMoreAutomata : DTDAutomata
  206. {
  207. public DTDOneOrMoreAutomata (DTDObjectModel root,
  208. DTDAutomata children)
  209. : base (root)
  210. {
  211. this.children = children;
  212. }
  213. private DTDAutomata children;
  214. public DTDAutomata Children {
  215. get { return children; }
  216. }
  217. public override DTDAutomata TryStartElement (string name)
  218. {
  219. DTDAutomata afterC = children.TryStartElement (name);
  220. if (afterC != Root.Invalid)
  221. return afterC.MakeSequence (
  222. Root.Empty.MakeChoice (this));
  223. else
  224. return Root.Invalid;
  225. }
  226. public override DTDAutomata TryEndElement ()
  227. {
  228. return Emptiable ? children.TryEndElement () : Root.Invalid;
  229. }
  230. }
  231. public class DTDEmptyAutomata : DTDAutomata
  232. {
  233. public DTDEmptyAutomata (DTDObjectModel root)
  234. : base (root)
  235. {
  236. }
  237. public override DTDAutomata TryEndElement ()
  238. {
  239. return this;
  240. }
  241. public override DTDAutomata TryStartElement (string name)
  242. {
  243. return Root.Invalid;
  244. }
  245. public override bool Emptiable {
  246. get { return true; }
  247. }
  248. }
  249. public class DTDAnyAutomata : DTDAutomata
  250. {
  251. public DTDAnyAutomata (DTDObjectModel root)
  252. : base (root)
  253. {
  254. }
  255. public override DTDAutomata TryEndElement ()
  256. {
  257. return this;
  258. }
  259. public override DTDAutomata TryStartElement (string name)
  260. {
  261. return this;
  262. }
  263. public override bool Emptiable {
  264. get { return true; }
  265. }
  266. }
  267. public class DTDInvalidAutomata : DTDAutomata
  268. {
  269. public DTDInvalidAutomata (DTDObjectModel root)
  270. : base (root)
  271. {
  272. }
  273. public override DTDAutomata TryEndElement ()
  274. {
  275. return this;
  276. }
  277. public override DTDAutomata TryStartElement (string name)
  278. {
  279. return this;
  280. }
  281. }
  282. }