/jEdit/branches/4.4.x-merge-request-for-r18847-r18954-r19206-r19210/org/gjt/sp/jedit/syntax/XModeHandler.java

# · Java · 766 lines · 597 code · 60 blank · 109 comment · 139 complexity · 0fcdf660deb0ed372b88f7511209d42e MD5 · raw file

  1. /*
  2. * XModeHandler.java - XML handler for mode files
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1999 mike dillon
  7. * Portions copyright (C) 2000, 2001 Slava Pestov
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  22. */
  23. package org.gjt.sp.jedit.syntax;
  24. //{{{ Imports
  25. import java.util.*;
  26. import java.util.regex.Pattern;
  27. import java.util.regex.PatternSyntaxException;
  28. import org.xml.sax.Attributes;
  29. import org.xml.sax.InputSource;
  30. import org.xml.sax.helpers.DefaultHandler;
  31. import org.gjt.sp.jedit.Mode;
  32. import org.gjt.sp.util.Log;
  33. import org.gjt.sp.util.XMLUtilities;
  34. //}}}
  35. /**
  36. * XML handler for mode definition files.
  37. * @version $Id: XModeHandler.java 16344 2009-10-14 10:31:01Z kpouer $
  38. */
  39. public abstract class XModeHandler extends DefaultHandler
  40. {
  41. //{{{ XModeHandler constructor
  42. public XModeHandler (String modeName)
  43. {
  44. this.modeName = modeName;
  45. marker = new TokenMarker();
  46. marker.addRuleSet(new ParserRuleSet(modeName,"MAIN"));
  47. stateStack = new Stack<TagDecl>();
  48. } //}}}
  49. //{{{ resolveEntity() method
  50. public InputSource resolveEntity(String publicId, String systemId)
  51. {
  52. return XMLUtilities.findEntity(systemId, "xmode.dtd", XModeHandler.class);
  53. } //}}}
  54. //{{{ characters() method
  55. public void characters(char[] c, int off, int len)
  56. {
  57. peekElement().setText(c, off, len);
  58. } //}}}
  59. //{{{ startElement() method
  60. public void startElement(String uri, String localName,
  61. String qName, Attributes attrs)
  62. {
  63. TagDecl tag = pushElement(qName, attrs);
  64. if (qName.equals("WHITESPACE"))
  65. {
  66. Log.log(Log.WARNING,this,modeName + ": WHITESPACE rule "
  67. + "no longer needed");
  68. }
  69. else if (qName.equals("KEYWORDS"))
  70. {
  71. keywords = new KeywordMap(rules.getIgnoreCase());
  72. }
  73. else if (qName.equals("RULES"))
  74. {
  75. if(tag.lastSetName == null)
  76. tag.lastSetName = "MAIN";
  77. rules = marker.getRuleSet(tag.lastSetName);
  78. if(rules == null)
  79. {
  80. rules = new ParserRuleSet(modeName,tag.lastSetName);
  81. marker.addRuleSet(rules);
  82. }
  83. rules.setIgnoreCase(tag.lastIgnoreCase);
  84. rules.setHighlightDigits(tag.lastHighlightDigits);
  85. if(tag.lastDigitRE != null)
  86. {
  87. try
  88. {
  89. rules.setDigitRegexp(Pattern.compile(tag.lastDigitRE,
  90. tag.lastIgnoreCase
  91. ? Pattern.CASE_INSENSITIVE : 0));
  92. }
  93. catch(PatternSyntaxException e)
  94. {
  95. error("regexp",e);
  96. }
  97. }
  98. if(tag.lastEscape != null)
  99. rules.setEscapeRule(ParserRule.createEscapeRule(tag.lastEscape));
  100. rules.setDefault(tag.lastDefaultID);
  101. rules.setNoWordSep(tag.lastNoWordSep);
  102. }
  103. } //}}}
  104. //{{{ endElement() method
  105. public void endElement(String uri, String localName, String name)
  106. {
  107. TagDecl tag = popElement();
  108. if (name.equals(tag.tagName))
  109. {
  110. if(tag.lastDelegateSet != null
  111. && ! tag.tagName.equals("IMPORT")
  112. && ! tag.lastDelegateSet.getModeName().equals(modeName))
  113. {
  114. Mode mode = ModeProvider.instance.getMode(tag.lastDelegateSet.getModeName());
  115. if( ! reloadModes.contains(mode) )
  116. {
  117. reloadModes.add(mode);
  118. }
  119. }
  120. //{{{ PROPERTY
  121. if (tag.tagName.equals("PROPERTY"))
  122. {
  123. props.put(propName,propValue);
  124. } //}}}
  125. //{{{ PROPS
  126. else if (tag.tagName.equals("PROPS"))
  127. {
  128. if(peekElement().tagName.equals("RULES"))
  129. rules.setProperties(props);
  130. else
  131. modeProps = props;
  132. props = new Hashtable<String, String>();
  133. } //}}}
  134. //{{{ RULES
  135. else if (tag.tagName.equals("RULES"))
  136. {
  137. rules.setKeywords(keywords);
  138. keywords = null;
  139. rules = null;
  140. } //}}}
  141. //{{{ IMPORT
  142. else if (tag.tagName.equals("IMPORT"))
  143. {
  144. // prevent lockups
  145. if (!rules.equals(tag.lastDelegateSet))
  146. {
  147. rules.addRuleSet(tag.lastDelegateSet);
  148. }
  149. } //}}}
  150. //{{{ TERMINATE
  151. else if (tag.tagName.equals("TERMINATE"))
  152. {
  153. rules.setTerminateChar(tag.termChar);
  154. } //}}}
  155. //{{{ SEQ
  156. else if (tag.tagName.equals("SEQ"))
  157. {
  158. if(tag.lastStart == null)
  159. {
  160. error("empty-tag","SEQ");
  161. return;
  162. }
  163. rules.addRule(ParserRule.createSequenceRule(
  164. tag.lastStartPosMatch,tag.lastStart.toString(),
  165. tag.lastDelegateSet,tag.lastTokenID));
  166. } //}}}
  167. //{{{ SEQ_REGEXP
  168. else if (tag.tagName.equals("SEQ_REGEXP"))
  169. {
  170. if(tag.lastStart == null)
  171. {
  172. error("empty-tag","SEQ_REGEXP");
  173. return;
  174. }
  175. try
  176. {
  177. if (null != tag.lastHashChars)
  178. {
  179. rules.addRule(ParserRule.createRegexpSequenceRule(
  180. tag.lastStartPosMatch,tag.lastHashChars.toCharArray(),
  181. tag.lastStart.toString(),tag.lastDelegateSet,
  182. tag.lastTokenID,findParent("RULES").lastIgnoreCase));
  183. }
  184. else
  185. {
  186. rules.addRule(ParserRule.createRegexpSequenceRule(
  187. tag.lastHashChar,tag.lastStartPosMatch,
  188. tag.lastStart.toString(),tag.lastDelegateSet,
  189. tag.lastTokenID,findParent("RULES").lastIgnoreCase));
  190. }
  191. }
  192. catch(PatternSyntaxException re)
  193. {
  194. error("regexp",re);
  195. }
  196. } //}}}
  197. //{{{ SPAN
  198. else if (tag.tagName.equals("SPAN"))
  199. {
  200. if(tag.lastStart == null)
  201. {
  202. error("empty-tag","BEGIN");
  203. return;
  204. }
  205. if(tag.lastEnd == null)
  206. {
  207. error("empty-tag","END");
  208. return;
  209. }
  210. rules.addRule(ParserRule
  211. .createSpanRule(
  212. tag.lastStartPosMatch,tag.lastStart.toString(),
  213. tag.lastEndPosMatch,tag.lastEnd.toString(),
  214. tag.lastDelegateSet,
  215. tag.lastTokenID,tag.lastMatchType,
  216. tag.lastNoLineBreak,
  217. tag.lastNoWordBreak,
  218. tag.lastEscape));
  219. } //}}}
  220. //{{{ SPAN_REGEXP
  221. else if (tag.tagName.equals("SPAN_REGEXP"))
  222. {
  223. if(tag.lastStart == null)
  224. {
  225. error("empty-tag","BEGIN");
  226. return;
  227. }
  228. if(tag.lastEnd == null)
  229. {
  230. error("empty-tag","END");
  231. return;
  232. }
  233. try
  234. {
  235. if (null != tag.lastHashChars)
  236. {
  237. rules.addRule(ParserRule
  238. .createRegexpSpanRule(
  239. tag.lastStartPosMatch,tag.lastHashChars.toCharArray(),
  240. tag.lastStart.toString(),
  241. tag.lastEndPosMatch,tag.lastEnd.toString(),
  242. tag.lastDelegateSet,
  243. tag.lastTokenID,
  244. tag.lastMatchType,
  245. tag.lastNoLineBreak,
  246. tag.lastNoWordBreak,
  247. findParent("RULES").lastIgnoreCase,
  248. tag.lastEscape));
  249. }
  250. else
  251. {
  252. rules.addRule(ParserRule
  253. .createRegexpSpanRule(
  254. tag.lastHashChar,
  255. tag.lastStartPosMatch,tag.lastStart.toString(),
  256. tag.lastEndPosMatch,tag.lastEnd.toString(),
  257. tag.lastDelegateSet,
  258. tag.lastTokenID,
  259. tag.lastMatchType,
  260. tag.lastNoLineBreak,
  261. tag.lastNoWordBreak,
  262. findParent("RULES").lastIgnoreCase,
  263. tag.lastEscape));
  264. }
  265. }
  266. catch(PatternSyntaxException re)
  267. {
  268. error("regexp",re);
  269. }
  270. } //}}}
  271. //{{{ EOL_SPAN
  272. else if (tag.tagName.equals("EOL_SPAN"))
  273. {
  274. if(tag.lastStart == null)
  275. {
  276. error("empty-tag","EOL_SPAN");
  277. return;
  278. }
  279. rules.addRule(ParserRule.createEOLSpanRule(
  280. tag.lastStartPosMatch,tag.lastStart.toString(),
  281. tag.lastDelegateSet,tag.lastTokenID,
  282. tag.lastMatchType));
  283. } //}}}
  284. //{{{ EOL_SPAN_REGEXP
  285. else if (tag.tagName.equals("EOL_SPAN_REGEXP"))
  286. {
  287. if(tag.lastStart == null)
  288. {
  289. error("empty-tag","EOL_SPAN_REGEXP");
  290. return;
  291. }
  292. try
  293. {
  294. if (null != tag.lastHashChars)
  295. {
  296. rules.addRule(ParserRule.createRegexpEOLSpanRule(
  297. tag.lastStartPosMatch,tag.lastHashChars.toCharArray(),
  298. tag.lastStart.toString(),tag.lastDelegateSet,
  299. tag.lastTokenID,tag.lastMatchType,
  300. findParent("RULES").lastIgnoreCase));
  301. }
  302. else
  303. {
  304. rules.addRule(ParserRule.createRegexpEOLSpanRule(
  305. tag.lastHashChar,tag.lastStartPosMatch,
  306. tag.lastStart.toString(),tag.lastDelegateSet,
  307. tag.lastTokenID,tag.lastMatchType,
  308. findParent("RULES").lastIgnoreCase));
  309. }
  310. }
  311. catch(PatternSyntaxException re)
  312. {
  313. error("regexp",re);
  314. }
  315. } //}}}
  316. //{{{ MARK_FOLLOWING
  317. else if (tag.tagName.equals("MARK_FOLLOWING"))
  318. {
  319. if(tag.lastStart == null)
  320. {
  321. error("empty-tag","MARK_FOLLOWING");
  322. return;
  323. }
  324. rules.addRule(ParserRule
  325. .createMarkFollowingRule(
  326. tag.lastStartPosMatch,tag.lastStart.toString(),
  327. tag.lastTokenID,tag.lastMatchType));
  328. } //}}}
  329. //{{{ MARK_PREVIOUS
  330. else if (tag.tagName.equals("MARK_PREVIOUS"))
  331. {
  332. if(tag.lastStart == null)
  333. {
  334. error("empty-tag","MARK_PREVIOUS");
  335. return;
  336. }
  337. rules.addRule(ParserRule
  338. .createMarkPreviousRule(
  339. tag.lastStartPosMatch,tag.lastStart.toString(),
  340. tag.lastTokenID,tag.lastMatchType));
  341. } //}}}
  342. //{{{ Keywords
  343. else if (
  344. !tag.tagName.equals("END")
  345. && !tag.tagName.equals("BEGIN")
  346. && !tag.tagName.equals("KEYWORDS")
  347. && !tag.tagName.equals("MODE"))
  348. {
  349. byte token = Token.stringToToken(tag.tagName);
  350. if(token != -1)
  351. addKeyword(tag.lastKeyword.toString(),token);
  352. } //}}}
  353. }
  354. else
  355. {
  356. // can't happen
  357. throw new InternalError();
  358. }
  359. } //}}}
  360. //{{{ startDocument() method
  361. public void startDocument()
  362. {
  363. props = new Hashtable<String, String>();
  364. pushElement(null, null);
  365. reloadModes = new Vector<Mode>();
  366. } //}}}
  367. //{{{ endDocument() method
  368. public void endDocument()
  369. {
  370. ParserRuleSet[] rulesets = marker.getRuleSets();
  371. for(int i = 0; i < rulesets.length; i++)
  372. {
  373. rulesets[i].resolveImports();
  374. }
  375. for(Mode mode : reloadModes)
  376. {
  377. mode.setTokenMarker(null);
  378. mode.loadIfNecessary();
  379. }
  380. } //}}}
  381. //{{{ getTokenMarker() method
  382. /**
  383. * Returns the TokenMarker.
  384. *
  385. * @return a TokenMarker it cannot be null
  386. */
  387. public TokenMarker getTokenMarker()
  388. {
  389. return marker;
  390. } //}}}
  391. //{{{ getModeProperties() method
  392. public Hashtable<String, String> getModeProperties()
  393. {
  394. return modeProps;
  395. } //}}}
  396. //{{{ Protected members
  397. //{{{ error() method
  398. /**
  399. * Reports an error.
  400. * You must override this method so that the mode loader can do error
  401. * reporting.
  402. * @param msg The error type
  403. * @param subst A <code>String</code> or a <code>Throwable</code>
  404. * containing specific information
  405. * @since jEdit 4.2pre1
  406. */
  407. protected abstract void error(String msg, Object subst);
  408. //}}}
  409. //{{{ getTokenMarker() method
  410. /**
  411. * Returns the token marker for the given mode.
  412. * You must override this method so that the mode loader can resolve
  413. * delegate targets.
  414. * @param mode The mode name
  415. * @since jEdit 4.2pre1
  416. */
  417. protected abstract TokenMarker getTokenMarker(String mode);
  418. //}}}
  419. //}}}
  420. //{{{ Private members
  421. //{{{ Instance variables
  422. private String modeName;
  423. /** The token marker cannot be null. */
  424. private final TokenMarker marker;
  425. private KeywordMap keywords;
  426. /** this stack can contains null elements. */
  427. private Stack<TagDecl> stateStack;
  428. private String propName;
  429. private String propValue;
  430. private Hashtable<String, String> props;
  431. private Hashtable<String, String> modeProps;
  432. private ParserRuleSet rules;
  433. /**
  434. * A list of modes to be reloaded at the end, loaded through DELEGATEs
  435. * @see http://sourceforge.net/tracker/index.php?func=detail&aid=1742250&group_id=588&atid=100588
  436. */
  437. private Vector<Mode> reloadModes;
  438. //}}}
  439. //{{{ addKeyword() method
  440. private void addKeyword(String k, byte id)
  441. {
  442. if(k == null)
  443. {
  444. error("empty-keyword",null);
  445. return;
  446. }
  447. if (keywords == null) return;
  448. keywords.add(k,id);
  449. } //}}}
  450. //{{{ pushElement() method
  451. private TagDecl pushElement(String name, Attributes attrs)
  452. {
  453. if (name != null)
  454. {
  455. TagDecl tag = new TagDecl(name, attrs);
  456. stateStack.push(tag);
  457. return tag;
  458. }
  459. else
  460. {
  461. stateStack.push(null);
  462. return null;
  463. }
  464. } //}}}
  465. //{{{ peekElement() method
  466. private TagDecl peekElement()
  467. {
  468. return stateStack.peek();
  469. } //}}}
  470. //{{{ popElement() method
  471. private TagDecl popElement()
  472. {
  473. return stateStack.pop();
  474. } //}}}
  475. //{{{ findParent() method
  476. /**
  477. * Finds the first element whose tag matches 'tagName',
  478. * searching backwards in the stack.
  479. */
  480. private TagDecl findParent(String tagName)
  481. {
  482. for (int idx = stateStack.size() - 1; idx >= 0; idx--)
  483. {
  484. TagDecl tag = stateStack.get(idx);
  485. if (tag.tagName.equals(tagName))
  486. return tag;
  487. }
  488. return null;
  489. } //}}}
  490. //}}}
  491. /**
  492. * Hold info about what tag was read and what attributes were
  493. * set in the XML file, to be kept by the handler in a stack
  494. * (similar to the way tag names were kept in a stack before).
  495. */
  496. private class TagDecl
  497. {
  498. public TagDecl(String tagName, Attributes attrs)
  499. {
  500. this.tagName = tagName;
  501. String tmp;
  502. propName = attrs.getValue("NAME");
  503. propValue = attrs.getValue("VALUE");
  504. tmp = attrs.getValue("TYPE");
  505. if (tmp != null)
  506. {
  507. lastTokenID = Token.stringToToken(tmp);
  508. if(lastTokenID == -1)
  509. error("token-invalid",tmp);
  510. }
  511. lastMatchType = ParserRule.MATCH_TYPE_RULE;
  512. // check for the deprecated "EXCLUDE_MATCH" and
  513. // warn if found.
  514. tmp = attrs.getValue("EXCLUDE_MATCH");
  515. if (tmp != null)
  516. {
  517. Log.log(Log.WARNING, this, modeName + ": EXCLUDE_MATCH is deprecated");
  518. if ("TRUE".equalsIgnoreCase(tmp))
  519. {
  520. lastMatchType = ParserRule.MATCH_TYPE_CONTEXT;
  521. }
  522. }
  523. // override with the newer MATCH_TYPE if present
  524. tmp = attrs.getValue("MATCH_TYPE");
  525. if (tmp != null)
  526. {
  527. if ("CONTEXT".equals(tmp))
  528. {
  529. lastMatchType = ParserRule.MATCH_TYPE_CONTEXT;
  530. }
  531. else if ("RULE".equals(tmp))
  532. {
  533. lastMatchType = ParserRule.MATCH_TYPE_RULE;
  534. }
  535. else
  536. {
  537. lastMatchType = Token.stringToToken(tmp);
  538. if(lastMatchType == -1)
  539. error("token-invalid",tmp);
  540. }
  541. }
  542. lastAtLineStart = "TRUE".equals(attrs.getValue("AT_LINE_START"));
  543. lastAtWhitespaceEnd = "TRUE".equals(attrs.getValue("AT_WHITESPACE_END"));
  544. lastAtWordStart = "TRUE".equals(attrs.getValue("AT_WORD_START"));
  545. lastNoLineBreak = "TRUE".equals(attrs.getValue("NO_LINE_BREAK"));
  546. lastNoWordBreak = "TRUE".equals(attrs.getValue("NO_WORD_BREAK"));
  547. lastIgnoreCase = (attrs.getValue("IGNORE_CASE") == null ||
  548. "TRUE".equals(attrs.getValue("IGNORE_CASE")));
  549. lastHighlightDigits = "TRUE".equals(attrs.getValue("HIGHLIGHT_DIGITS"));
  550. lastDigitRE = attrs.getValue("DIGIT_RE");
  551. tmp = attrs.getValue("NO_WORD_SEP");
  552. if (tmp != null)
  553. lastNoWordSep = tmp;
  554. tmp = attrs.getValue("AT_CHAR");
  555. if (tmp != null)
  556. {
  557. try
  558. {
  559. termChar = Integer.parseInt(tmp);
  560. }
  561. catch (NumberFormatException e)
  562. {
  563. error("termchar-invalid",tmp);
  564. termChar = -1;
  565. }
  566. }
  567. lastEscape = attrs.getValue("ESCAPE");
  568. lastSetName = attrs.getValue("SET");
  569. tmp = attrs.getValue("DELEGATE");
  570. if (tmp != null)
  571. {
  572. String delegateMode, delegateSetName;
  573. int index = tmp.indexOf("::");
  574. if(index != -1)
  575. {
  576. delegateMode = tmp.substring(0,index);
  577. delegateSetName = tmp.substring(index + 2);
  578. }
  579. else
  580. {
  581. delegateMode = modeName;
  582. delegateSetName = tmp;
  583. }
  584. TokenMarker delegateMarker = getTokenMarker(delegateMode);
  585. if(delegateMarker == null)
  586. error("delegate-invalid",tmp);
  587. else
  588. {
  589. lastDelegateSet = delegateMarker
  590. .getRuleSet(delegateSetName);
  591. if(delegateMarker == marker
  592. && lastDelegateSet == null)
  593. {
  594. // stupid hack to handle referencing
  595. // a rule set that is defined later!
  596. lastDelegateSet = new ParserRuleSet(
  597. delegateMode,
  598. delegateSetName);
  599. lastDelegateSet.setDefault(Token.INVALID);
  600. marker.addRuleSet(lastDelegateSet);
  601. }
  602. else if(lastDelegateSet == null)
  603. error("delegate-invalid",tmp);
  604. }
  605. }
  606. tmp = attrs.getValue("DEFAULT");
  607. if (tmp != null)
  608. {
  609. lastDefaultID = Token.stringToToken(tmp);
  610. if(lastDefaultID == -1)
  611. {
  612. error("token-invalid",tmp);
  613. lastDefaultID = Token.NULL;
  614. }
  615. }
  616. lastHashChar = attrs.getValue("HASH_CHAR");
  617. lastHashChars = attrs.getValue("HASH_CHARS");
  618. if ((null != lastHashChar) && (null != lastHashChars))
  619. {
  620. error("hash-char-and-hash-chars-mutually-exclusive",null);
  621. lastHashChars = null;
  622. }
  623. }
  624. public void setText(char[] c, int off, int len)
  625. {
  626. if (tagName.equals("EOL_SPAN") ||
  627. tagName.equals("EOL_SPAN_REGEXP") ||
  628. tagName.equals("MARK_PREVIOUS") ||
  629. tagName.equals("MARK_FOLLOWING") ||
  630. tagName.equals("SEQ") ||
  631. tagName.equals("SEQ_REGEXP") ||
  632. tagName.equals("BEGIN")
  633. )
  634. {
  635. TagDecl target = this;
  636. if (tagName.equals("BEGIN"))
  637. target = stateStack.get(stateStack.size() - 2);
  638. if (target.lastStart == null)
  639. {
  640. target.lastStart = new StringBuffer();
  641. target.lastStart.append(c, off, len);
  642. target.lastStartPosMatch = ((target.lastAtLineStart ? ParserRule.AT_LINE_START : 0)
  643. | (target.lastAtWhitespaceEnd ? ParserRule.AT_WHITESPACE_END : 0)
  644. | (target.lastAtWordStart ? ParserRule.AT_WORD_START : 0));
  645. target.lastAtLineStart = false;
  646. target.lastAtWordStart = false;
  647. target.lastAtWhitespaceEnd = false;
  648. }
  649. else
  650. {
  651. target.lastStart.append(c, off, len);
  652. }
  653. }
  654. else if (tagName.equals("END"))
  655. {
  656. TagDecl target = stateStack.get(stateStack.size() - 2);
  657. if (target.lastEnd == null)
  658. {
  659. target.lastEnd = new StringBuffer();
  660. target.lastEnd.append(c, off, len);
  661. target.lastEndPosMatch = ((this.lastAtLineStart ? ParserRule.AT_LINE_START : 0)
  662. | (this.lastAtWhitespaceEnd ? ParserRule.AT_WHITESPACE_END : 0)
  663. | (this.lastAtWordStart ? ParserRule.AT_WORD_START : 0));
  664. target.lastAtLineStart = false;
  665. target.lastAtWordStart = false;
  666. target.lastAtWhitespaceEnd = false;
  667. }
  668. else
  669. {
  670. target.lastEnd.append(c, off, len);
  671. }
  672. }
  673. else
  674. {
  675. if (lastKeyword == null)
  676. lastKeyword = new StringBuffer();
  677. lastKeyword.append(c, off, len);
  678. }
  679. }
  680. public String tagName;
  681. public StringBuffer lastStart;
  682. public StringBuffer lastEnd;
  683. public StringBuffer lastKeyword;
  684. public String lastSetName;
  685. public String lastEscape;
  686. public ParserRuleSet lastDelegateSet;
  687. public String lastNoWordSep = "_";
  688. public ParserRuleSet rules;
  689. public byte lastDefaultID = Token.NULL;
  690. public byte lastTokenID;
  691. public byte lastMatchType;
  692. public int termChar = -1;
  693. public boolean lastNoLineBreak;
  694. public boolean lastNoWordBreak;
  695. public boolean lastIgnoreCase = true;
  696. public boolean lastHighlightDigits;
  697. public boolean lastAtLineStart;
  698. public boolean lastAtWhitespaceEnd;
  699. public boolean lastAtWordStart;
  700. public int lastStartPosMatch;
  701. public int lastEndPosMatch;
  702. public String lastDigitRE;
  703. public String lastHashChar;
  704. public String lastHashChars;
  705. }
  706. }