PageRenderTime 50ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/servers/jain-sip-ext/src/main/java/gov/nist/javax/sip/parser/chars/LexerCore.java

http://mobicents.googlecode.com/
Java | 800 lines | 552 code | 57 blank | 191 comment | 127 complexity | e3b1cf446ca84986c8ee93348f74735c MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0, LGPL-2.1, GPL-2.0, CC-BY-SA-3.0, CC0-1.0, Apache-2.0, BSD-3-Clause
  1. /*
  2. * JBoss, Home of Professional Open Source
  3. * Copyright 2011, Red Hat, Inc. and individual contributors
  4. * by the @authors tag. See the copyright.txt in the distribution for a
  5. * full listing of individual contributors.
  6. *
  7. * This is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation; either version 2.1 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This software is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this software; if not, write to the Free
  19. * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  20. * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  21. */
  22. /*
  23. * Conditions Of Use
  24. *
  25. * This software was developed by employees of the National Institute of
  26. * Standards and Technology (NIST), an agency of the Federal Government.
  27. * Pursuant to title 15 Untied States Code Section 105, works of NIST
  28. * employees are not subject to copyright protection in the United States
  29. * and are considered to be in the public domain. As a result, a formal
  30. * license is not needed to use the software.
  31. *
  32. * This software is provided by NIST as a service and is expressly
  33. * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
  34. * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
  35. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
  36. * AND DATA ACCURACY. NIST does not warrant or make any representations
  37. * regarding the use of the software or the results thereof, including but
  38. * not limited to the correctness, accuracy, reliability or usefulness of
  39. * the software.
  40. *
  41. * Permission to use this software is contingent upon your acceptance
  42. * of the terms of this agreement
  43. *
  44. * .
  45. *
  46. */
  47. package gov.nist.javax.sip.parser.chars;
  48. import gov.nist.core.Debug;
  49. import java.text.ParseException;
  50. import java.util.Map;
  51. import java.util.concurrent.ConcurrentHashMap;
  52. /** A lexical analyzer that is used by all parsers in our implementation.
  53. *
  54. *@version 1.2
  55. *@since 1.1
  56. *
  57. *@author M. Ranganathan
  58. */
  59. public class LexerCore extends StringTokenizer {
  60. // IMPORTANT - All keyword matches should be between START and END
  61. public static final int START = 2048;
  62. public static final int END = START + 2048;
  63. // IMPORTANT -- This should be < END
  64. public static final int ID = END - 1;
  65. public static final int SAFE = END - 2;
  66. // Individial token classes.
  67. public static final int WHITESPACE = END + 1;
  68. public static final int DIGIT = END + 2;
  69. public static final int ALPHA = END + 3;
  70. public static final int BACKSLASH = (int) '\\';
  71. public static final int QUOTE = (int) '\'';
  72. public static final int AT = (int) '@';
  73. public static final int SP = (int) ' ';
  74. public static final int HT = (int) '\t';
  75. public static final int COLON = (int) ':';
  76. public static final int STAR = (int) '*';
  77. public static final int DOLLAR = (int) '$';
  78. public static final int PLUS = (int) '+';
  79. public static final int POUND = (int) '#';
  80. public static final int MINUS = (int) '-';
  81. public static final int DOUBLEQUOTE = (int) '\"';
  82. public static final int TILDE = (int) '~';
  83. public static final int BACK_QUOTE = (int) '`';
  84. public static final int NULL = (int) '\0';
  85. public static final int EQUALS = (int) '=';
  86. public static final int SEMICOLON = (int) ';';
  87. public static final int SLASH = (int) '/';
  88. public static final int L_SQUARE_BRACKET = (int) '[';
  89. public static final int R_SQUARE_BRACKET = (int) ']';
  90. public static final int R_CURLY = (int) '}';
  91. public static final int L_CURLY = (int) '{';
  92. public static final int HAT = (int) '^';
  93. public static final int BAR = (int) '|';
  94. public static final int DOT = (int) '.';
  95. public static final int EXCLAMATION = (int) '!';
  96. public static final int LPAREN = (int) '(';
  97. public static final int RPAREN = (int) ')';
  98. public static final int GREATER_THAN = (int) '>';
  99. public static final int LESS_THAN = (int) '<';
  100. public static final int PERCENT = (int) '%';
  101. public static final int QUESTION = (int) '?';
  102. public static final int AND = (int) '&';
  103. public static final int UNDERSCORE = (int) '_';
  104. // jeand : using concurrent data structure to avoid excessive blocking
  105. protected static final ConcurrentHashMap<Integer, String> globalSymbolTable;
  106. protected static final ConcurrentHashMap<String, ConcurrentHashMap<String, Integer>> lexerTables;
  107. protected Map<String, Integer> currentLexer;
  108. protected String currentLexerName;
  109. protected Token currentMatch;
  110. static {
  111. globalSymbolTable = new ConcurrentHashMap<Integer, String>();
  112. lexerTables = new ConcurrentHashMap<String, ConcurrentHashMap<String, Integer>>();
  113. }
  114. protected void addKeyword(String name, int value) {
  115. // System.out.println("addKeyword " + name + " value = " + value);
  116. // new Exception().printStackTrace();
  117. Integer val = Integer.valueOf(value);
  118. currentLexer.put(name, val);
  119. // if (!globalSymbolTable.containsKey(val))
  120. globalSymbolTable.putIfAbsent(val, name);
  121. }
  122. public String lookupToken(int value) {
  123. if (value > START) {
  124. return (String) globalSymbolTable.get(Integer.valueOf(value));
  125. } else {
  126. Character ch = Character.valueOf((char) value);
  127. return ch.toString();
  128. }
  129. }
  130. // protected Map<String, Integer> addLexer(String lexerName) {
  131. // currentLexer = (Map<String, Integer>) lexerTables.get(lexerName);
  132. // if (currentLexer == null) {
  133. // currentLexer = new Hashtable();
  134. // lexerTables.put(lexerName, currentLexer);
  135. // }
  136. // return currentLexer;
  137. // }
  138. //public abstract void selectLexer(String lexerName);
  139. public void selectLexer(String lexerName) {
  140. this.currentLexerName = lexerName;
  141. }
  142. protected LexerCore() {
  143. this.currentLexer = new ConcurrentHashMap<String, Integer>();
  144. this.currentLexerName = "charLexer";
  145. }
  146. /** Initialize the lexer with a buffer.
  147. */
  148. public LexerCore(String lexerName, char[] buffer) {
  149. super(buffer);
  150. this.currentLexerName = lexerName;
  151. }
  152. /** Peek the next id but dont move the buffer pointer forward.
  153. */
  154. public char[] peekNextId() {
  155. int oldPtr = ptr;
  156. char[] retval = ttoken();
  157. savedPtr = ptr;
  158. ptr = oldPtr;
  159. return retval;
  160. }
  161. /** Get the next id.
  162. */
  163. public char[] getNextId() {
  164. return ttoken();
  165. }
  166. // call this after you call match
  167. public Token getNextToken() {
  168. return this.currentMatch;
  169. }
  170. /** Look ahead for one token.
  171. */
  172. public Token peekNextToken() throws ParseException {
  173. return (Token) peekNextToken(1)[0];
  174. }
  175. public Token[] peekNextToken(int ntokens) throws ParseException {
  176. int old = ptr;
  177. Token[] retval = new Token[ntokens];
  178. for (int i = 0; i < ntokens; i++) {
  179. Token tok = new Token();
  180. if (startsId()) {
  181. char[] id = ttoken();
  182. tok.tokenValue = id;
  183. String idUppercase = String.valueOf(id).toUpperCase().intern();
  184. if (currentLexer.containsKey(idUppercase)) {
  185. Integer type = (Integer) currentLexer.get(idUppercase);
  186. tok.tokenType = type.intValue();
  187. } else
  188. tok.tokenType = ID;
  189. } else {
  190. char nextChar = getNextChar();
  191. tok.tokenValue = new char[] {nextChar};
  192. if (isAlpha(nextChar)) {
  193. tok.tokenType = ALPHA;
  194. } else if (isDigit(nextChar)) {
  195. tok.tokenType = DIGIT;
  196. } else
  197. tok.tokenType = (int) nextChar;
  198. }
  199. retval[i] = tok;
  200. }
  201. savedPtr = ptr;
  202. ptr = old;
  203. return retval;
  204. }
  205. /** Match the given token or throw an exception if no such token
  206. * can be matched.
  207. */
  208. public Token match(int tok) throws ParseException {
  209. if (Debug.parserDebug) {
  210. Debug.println("match " + tok);
  211. }
  212. if (tok > START && tok < END) {
  213. if (tok == ID) {
  214. // Generic ID sought.
  215. if (!startsId())
  216. throw new ParseException(buffer + "\nID expected", ptr);
  217. char[] id = getNextId();
  218. this.currentMatch = new Token();
  219. this.currentMatch.tokenValue = id;
  220. this.currentMatch.tokenType = ID;
  221. } else if (tok == SAFE) {
  222. if (!startsSafeToken())
  223. throw new ParseException(buffer + "\nID expected", ptr);
  224. char[] id = ttokenSafe();
  225. this.currentMatch = new Token();
  226. this.currentMatch.tokenValue = id;
  227. this.currentMatch.tokenType = SAFE;
  228. } else {
  229. char[] nexttok = getNextId();
  230. Integer cur = (Integer) currentLexer.get(String.valueOf(nexttok).toUpperCase().intern());
  231. if (cur == null || cur.intValue() != tok)
  232. throw new ParseException(
  233. buffer + "\nUnexpected Token : " + nexttok,
  234. ptr);
  235. this.currentMatch = new Token();
  236. this.currentMatch.tokenValue = nexttok;
  237. this.currentMatch.tokenType = tok;
  238. }
  239. } else if (tok > END) {
  240. // Character classes.
  241. char next = lookAhead(0);
  242. if (tok == DIGIT) {
  243. if (!isDigit(next))
  244. throw new ParseException(buffer + "\nExpecting DIGIT", ptr);
  245. this.currentMatch = new Token();
  246. this.currentMatch.tokenValue = new char[] {next};
  247. this.currentMatch.tokenType = tok;
  248. consume(1);
  249. } else if (tok == ALPHA) {
  250. if (!isAlpha(next))
  251. throw new ParseException(buffer + "\nExpecting ALPHA", ptr);
  252. this.currentMatch = new Token();
  253. this.currentMatch.tokenValue =
  254. new char[] {next};
  255. this.currentMatch.tokenType = tok;
  256. consume(1);
  257. }
  258. } else {
  259. // This is a direct character spec.
  260. char ch = (char) tok;
  261. char next = lookAhead(0);
  262. if (next == ch) {
  263. /*this.currentMatch = new Token();
  264. this.currentMatch.tokenValue =
  265. String.valueOf(ch);
  266. this.currentMatch.tokenType = tok;*/
  267. consume(1);
  268. } else
  269. throw new ParseException(
  270. buffer + "\nExpecting >>>" + ch + "<<< got >>>"
  271. + next + "<<<", ptr);
  272. }
  273. return this.currentMatch;
  274. }
  275. public void SPorHT() {
  276. try {
  277. char c = lookAhead(0);
  278. while (c == ' ' || c == '\t') {
  279. consume(1);
  280. c = lookAhead(0);
  281. }
  282. } catch (ParseException ex) {
  283. // Ignore
  284. }
  285. }
  286. /**
  287. * JvB: utility function added to validate tokens
  288. *
  289. * @see RFC3261 section 25.1:
  290. * token = 1*(alphanum / "-" / "." / "!" / "%" / "*"
  291. / "_" / "+" / "`" / "'" / "~" )
  292. * @param c - character to check
  293. * @return true iff character c is a valid token character as per RFC3261
  294. */
  295. public static final boolean isTokenChar( char c ) {
  296. if ( isAlphaDigit(c) ) return true;
  297. else switch (c)
  298. {
  299. case '-':
  300. case '.':
  301. case '!':
  302. case '%':
  303. case '*':
  304. case '_':
  305. case '+':
  306. case '`':
  307. case '\'':
  308. case '~':
  309. return true;
  310. default:
  311. return false;
  312. }
  313. }
  314. public boolean startsId() {
  315. try {
  316. char nextChar = lookAhead(0);
  317. return isTokenChar(nextChar);
  318. } catch (ParseException ex) {
  319. return false;
  320. }
  321. }
  322. public boolean startsSafeToken() {
  323. try {
  324. char nextChar = lookAhead(0);
  325. if (isAlphaDigit(nextChar)) {
  326. return true;
  327. }
  328. else {
  329. switch (nextChar) {
  330. case '_':
  331. case '+':
  332. case '-':
  333. case '!':
  334. case '`':
  335. case '\'':
  336. case '.':
  337. case '/':
  338. case '}':
  339. case '{':
  340. case ']':
  341. case '[':
  342. case '^':
  343. case '|':
  344. case '~':
  345. case '%': // bug fix by Bruno Konik, JvB copied here
  346. case '#':
  347. case '@':
  348. case '$':
  349. case ':':
  350. case ';':
  351. case '?':
  352. case '\"':
  353. case '*':
  354. case '=': // Issue 155 on java.net
  355. return true;
  356. default:
  357. return false;
  358. }
  359. }
  360. } catch (ParseException ex) {
  361. return false;
  362. }
  363. }
  364. public char[] ttoken() {
  365. int startIdx = ptr;
  366. try {
  367. while (hasMoreChars()) {
  368. char nextChar = lookAhead(0);
  369. if ( isTokenChar(nextChar) ) {
  370. consume(1);
  371. } else {
  372. break;
  373. }
  374. }
  375. char[] retval = new char[ptr - startIdx];
  376. System.arraycopy(buffer, startIdx, retval, 0, ptr - startIdx);
  377. // return String.valueOf(buffer, startIdx, ptr - startIdx);
  378. return retval;
  379. } catch (ParseException ex) {
  380. return null;
  381. }
  382. }
  383. /* JvB: unreferenced
  384. public String ttokenAllowSpace() {
  385. int startIdx = ptr;
  386. try {
  387. while (hasMoreChars()) {
  388. char nextChar = lookAhead(0);
  389. if (isAlphaDigit(nextChar)) {
  390. consume(1);
  391. }
  392. else {
  393. boolean isValidChar = false;
  394. switch (nextChar) {
  395. case '_':
  396. case '+':
  397. case '-':
  398. case '!':
  399. case '`':
  400. case '\'':
  401. case '~':
  402. case '%': // bug fix by Bruno Konik, JvB copied here
  403. case '.':
  404. case ' ':
  405. case '\t':
  406. case '*':
  407. isValidChar = true;
  408. }
  409. if (isValidChar) {
  410. consume(1);
  411. }
  412. else {
  413. break;
  414. }
  415. }
  416. }
  417. return buffer.substring(startIdx, ptr);
  418. } catch (ParseException ex) {
  419. return null;
  420. }
  421. }*/
  422. public char[] ttokenSafe() {
  423. int startIdx = ptr;
  424. try {
  425. while (hasMoreChars()) {
  426. char nextChar = lookAhead(0);
  427. if (isAlphaDigit(nextChar)) {
  428. consume(1);
  429. }
  430. else {
  431. boolean isValidChar = false;
  432. switch (nextChar) {
  433. case '_':
  434. case '+':
  435. case '-':
  436. case '!':
  437. case '`':
  438. case '\'':
  439. case '.':
  440. case '/':
  441. case '}':
  442. case '{':
  443. case ']':
  444. case '[':
  445. case '^':
  446. case '|':
  447. case '~':
  448. case '%': // bug fix by Bruno Konik, JvB copied here
  449. case '#':
  450. case '@':
  451. case '$':
  452. case ':':
  453. case ';':
  454. case '?':
  455. case '\"':
  456. case '*':
  457. isValidChar = true;
  458. }
  459. if (isValidChar) {
  460. consume(1);
  461. }
  462. else {
  463. break;
  464. }
  465. }
  466. }
  467. char[] retval = new char[ptr - startIdx];
  468. System.arraycopy(buffer, startIdx, retval, 0, ptr - startIdx);
  469. // return String.valueOf(buffer, startIdx, ptr - startIdx);
  470. return retval;
  471. } catch (ParseException ex) {
  472. return null;
  473. }
  474. }
  475. public static final char ALPHA_VALID_CHARS = Character.MAX_VALUE;
  476. public static final char DIGIT_VALID_CHARS = Character.MAX_VALUE - 1;
  477. public static final char ALPHADIGIT_VALID_CHARS = Character.MAX_VALUE - 2;
  478. public void consumeValidChars(char[] validChars) {
  479. int validCharsLength = validChars.length;
  480. try {
  481. while (hasMoreChars()) {
  482. char nextChar = lookAhead(0);
  483. boolean isValid = false;
  484. for (int i = 0; i < validCharsLength; i++) {
  485. char validChar = validChars[i];
  486. switch(validChar) {
  487. case ALPHA_VALID_CHARS:
  488. isValid = isAlpha(nextChar);
  489. break;
  490. case DIGIT_VALID_CHARS:
  491. isValid = isDigit(nextChar);
  492. break;
  493. case ALPHADIGIT_VALID_CHARS:
  494. isValid = isAlphaDigit(nextChar);
  495. break;
  496. default:
  497. isValid = nextChar == validChar;
  498. }
  499. if (isValid) {
  500. break;
  501. }
  502. }
  503. if (isValid) {
  504. consume(1);
  505. }
  506. else {
  507. break;
  508. }
  509. }
  510. } catch (ParseException ex) {
  511. }
  512. }
  513. /** Parse a comment string cursor is at a ". Leave cursor at closing "
  514. *@return the substring containing the quoted string excluding the
  515. * closing quote.
  516. */
  517. public String quotedString() throws ParseException {
  518. int startIdx = ptr + 1;
  519. if (lookAhead(0) != '\"')
  520. return null;
  521. consume(1);
  522. while (true) {
  523. char next = getNextChar();
  524. if (next == '\"') {
  525. // Got to the terminating quote.
  526. break;
  527. } else if (next == '\0') {
  528. throw new ParseException(
  529. String.valueOf(this.buffer) + " :unexpected EOL",
  530. this.ptr);
  531. } else if (next == '\\') {
  532. consume(1);
  533. }
  534. }
  535. return String.valueOf(buffer, startIdx, ptr - startIdx - 1);
  536. }
  537. /** Parse a comment string cursor is at a "(". Leave cursor at )
  538. *@return the substring containing the comment excluding the
  539. * closing brace.
  540. */
  541. public String comment() throws ParseException {
  542. StringBuilder retval = new StringBuilder();
  543. if (lookAhead(0) != '(')
  544. return null;
  545. consume(1);
  546. while (true) {
  547. char next = getNextChar();
  548. if (next == ')') {
  549. break;
  550. } else if (next == '\0') {
  551. throw new ParseException(
  552. this.buffer + " :unexpected EOL",
  553. this.ptr);
  554. } else if (next == '\\') {
  555. retval.append(next);
  556. next = getNextChar();
  557. if (next == '\0')
  558. throw new ParseException(
  559. this.buffer + " : unexpected EOL",
  560. this.ptr);
  561. retval.append(next);
  562. } else {
  563. retval.append(next);
  564. }
  565. }
  566. return retval.toString();
  567. }
  568. /** Return a substring containing no semicolons.
  569. *@return a substring containing no semicolons.
  570. */
  571. public String byteStringNoSemicolon() {
  572. StringBuilder retval = new StringBuilder();
  573. try {
  574. while (true) {
  575. char next = lookAhead(0);
  576. // bug fix from Ben Evans.
  577. if (next == '\0' || next == '\n' || next == ';' || next == ',' ) {
  578. break;
  579. } else {
  580. consume(1);
  581. retval.append(next);
  582. }
  583. }
  584. } catch (ParseException ex) {
  585. return retval.toString();
  586. }
  587. return retval.toString();
  588. }
  589. /**
  590. * Scan until you see a slash or an EOL.
  591. *
  592. * @return substring containing no slash.
  593. */
  594. public String byteStringNoSlash() {
  595. StringBuilder retval = new StringBuilder();
  596. try {
  597. while (true) {
  598. char next = lookAhead(0);
  599. // bug fix from Ben Evans.
  600. if (next == '\0' || next == '\n' || next == '/' ) {
  601. break;
  602. } else {
  603. consume(1);
  604. retval.append(next);
  605. }
  606. }
  607. } catch (ParseException ex) {
  608. return retval.toString();
  609. }
  610. return retval.toString();
  611. }
  612. /** Return a substring containing no commas
  613. *@return a substring containing no commas.
  614. */
  615. public String byteStringNoComma() {
  616. StringBuilder retval = new StringBuilder();
  617. try {
  618. while (true) {
  619. char next = lookAhead(0);
  620. if (next == '\n' || next == ',') {
  621. break;
  622. } else {
  623. consume(1);
  624. retval.append(next);
  625. }
  626. }
  627. } catch (ParseException ex) {
  628. }
  629. return retval.toString();
  630. }
  631. public static String charAsString(char ch) {
  632. return String.valueOf(ch);
  633. }
  634. /** Lookahead in the inputBuffer for n chars and return as a string.
  635. * Do not consume the input.
  636. */
  637. public String charAsString(int nchars) {
  638. return String.valueOf(buffer, ptr, nchars -1);
  639. }
  640. /** Get and consume the next number.
  641. *@return a substring corresponding to a number
  642. *(i.e. sequence of digits).
  643. */
  644. public String number() throws ParseException {
  645. int startIdx = ptr;
  646. try {
  647. if (!isDigit(lookAhead(0))) {
  648. throw new ParseException(
  649. buffer + ": Unexpected token at " + lookAhead(0),
  650. ptr);
  651. }
  652. consume(1);
  653. while (true) {
  654. char next = lookAhead(0);
  655. if (isDigit(next)) {
  656. consume(1);
  657. } else
  658. break;
  659. }
  660. return String.valueOf(buffer, startIdx, ptr - startIdx);
  661. } catch (ParseException ex) {
  662. return String.valueOf(buffer, startIdx, ptr - startIdx);
  663. }
  664. }
  665. /** Mark the position for backtracking.
  666. *@return the current location of the pointer.
  667. */
  668. public int markInputPosition() {
  669. return ptr;
  670. }
  671. /** Rewind the input ptr to the marked position.
  672. *@param position - the position to rewind the parser to.
  673. */
  674. public void rewindInputPosition(int position) {
  675. this.ptr = position;
  676. }
  677. /** Get the rest of the String
  678. * @return rest of the buffer.
  679. */
  680. public String getRest() {
  681. if (ptr >= bufferLen)
  682. return null;
  683. else
  684. return String.valueOf(buffer, ptr, bufferLen - ptr - 1);
  685. }
  686. /** Get the sub-String until the character is encountered
  687. * @param c the character to match
  688. * @return the substring that matches.
  689. */
  690. public String getString(char c) throws ParseException {
  691. StringBuilder retval = new StringBuilder();
  692. while (true) {
  693. char next = lookAhead(0);
  694. //System.out.println(" next = [" + next + ']' + "ptr = " + ptr);
  695. //System.out.println(next == '\0');
  696. if (next == '\0') {
  697. throw new ParseException(
  698. this.buffer + "unexpected EOL",
  699. this.ptr);
  700. } else if (next == c) {
  701. consume(1);
  702. break;
  703. } else if (next == '\\') {
  704. consume(1);
  705. char nextchar = lookAhead(0);
  706. if (nextchar == '\0') {
  707. throw new ParseException(
  708. this.buffer + "unexpected EOL",
  709. this.ptr);
  710. } else {
  711. consume(1);
  712. retval.append(nextchar);
  713. }
  714. } else {
  715. consume(1);
  716. retval.append(next);
  717. }
  718. }
  719. return retval.toString();
  720. }
  721. /** Get the read pointer.
  722. */
  723. public int getPtr() {
  724. return this.ptr;
  725. }
  726. /** Get the buffer.
  727. */
  728. public String getBuffer() {
  729. return String.valueOf(buffer);
  730. }
  731. public char[] getSubBuffer(int start, int end) {
  732. char[] retval = new char[end - start];
  733. System.arraycopy(buffer, start, retval, 0, end - start);
  734. return retval;
  735. }
  736. /** Create a parse exception.
  737. */
  738. public ParseException createParseException() {
  739. return new ParseException(getBuffer(), this.ptr);
  740. }
  741. }