/* *************************************************************************** * Copyright (C) 2002-2009 International Business Machines Corporation * * and others. All rights reserved. * *************************************************************************** */ package com.ibm.icu.text; import java.text.ParsePosition; import java.util.HashMap; import com.ibm.icu.lang.UCharacter; class RBBISymbolTable implements SymbolTable{ String fRules; HashMap fHashTable; RBBIRuleScanner fRuleScanner; // These next two fields are part of the mechanism for passing references to // already-constructed UnicodeSets back to the UnicodeSet constructor // when the pattern includes $variable references. String ffffString; UnicodeSet fCachedSetLookup; static class RBBISymbolTableEntry { String key; RBBINode val; } RBBISymbolTable(RBBIRuleScanner rs, String rules) { fRules = rules; fRuleScanner = rs; fHashTable = new HashMap(); ffffString = "\uffff"; } // // RBBISymbolTable::lookup This function from the abstract symbol table inteface // looks up a variable name and returns a UnicodeString // containing the substitution text. // // The variable name does NOT include the leading $. // public char[] lookup(String s) { RBBISymbolTableEntry el; RBBINode varRefNode; RBBINode exprNode; RBBINode usetNode; String retString; el = fHashTable.get(s); if (el == null) { return null; } // Walk through any chain of variable assignments that ultimately resolve to a Set Ref. varRefNode = el.val; while (varRefNode.fLeftChild.fType == RBBINode.varRef) { varRefNode = varRefNode.fLeftChild; } exprNode = varRefNode.fLeftChild; // Root node of expression for variable if (exprNode.fType == RBBINode.setRef) { // The $variable refers to a single UnicodeSet // return the ffffString, which will subsequently be interpreted as a // stand-in character for the set by RBBISymbolTable::lookupMatcher() usetNode = exprNode.fLeftChild; fCachedSetLookup = usetNode.fInputSet; retString = ffffString; } else { // The variable refers to something other than just a set. // This is an error in the rules being compiled. $Variables inside of UnicodeSets // must refer only to another set, not to some random non-set expression. // Note: single characters are represented as sets, so they are ok. fRuleScanner.error(RBBIRuleBuilder.U_BRK_MALFORMED_SET); retString = exprNode.fText; fCachedSetLookup = null; } return retString.toCharArray(); } // // RBBISymbolTable::lookupMatcher This function from the abstract symbol table // interface maps a single stand-in character to a // pointer to a Unicode Set. The Unicode Set code uses this // mechanism to get all references to the same $variable // name to refer to a single common Unicode Set instance. // // This implementation cheats a little, and does not maintain a map of stand-in chars // to sets. Instead, it takes advantage of the fact that the UnicodeSet // constructor will always call this function right after calling lookup(), // and we just need to remember what set to return between these two calls. public UnicodeMatcher lookupMatcher(int ch) { UnicodeSet retVal = null; if (ch == 0xffff) { retVal = fCachedSetLookup; fCachedSetLookup = null; } return retVal; } // // RBBISymbolTable::parseReference This function from the abstract symbol table interface // looks for a $variable name in the source text. // It does not look it up, only scans for it. // It is used by the UnicodeSet parser. // public String parseReference(String text, ParsePosition pos, int limit) { int start = pos.getIndex(); int i = start; String result = ""; while (i < limit) { int c = UTF16.charAt(text, i); if ((i == start && !UCharacter.isUnicodeIdentifierStart(c)) || !UCharacter.isUnicodeIdentifierPart(c)) { break; } i += UTF16.getCharCount(c); } if (i == start) { // No valid name chars return result; // Indicate failure with empty string } pos.setIndex(i); result = text.substring(start, i); return result; } // // RBBISymbolTable::lookupNode Given a key (a variable name), return the // corresponding RBBI Node. If there is no entry // in the table for this name, return NULL. // RBBINode lookupNode(String key) { RBBINode retNode = null; RBBISymbolTableEntry el; el = fHashTable.get(key); if (el != null) { retNode = el.val; } return retNode; } // // RBBISymbolTable::addEntry Add a new entry to the symbol table. // Indicate an error if the name already exists - // this will only occur in the case of duplicate // variable assignments. // void addEntry(String key, RBBINode val) { RBBISymbolTableEntry e; e = fHashTable.get(key); if (e != null) { fRuleScanner.error(RBBIRuleBuilder.U_BRK_VARIABLE_REDFINITION); return; } e = new RBBISymbolTableEntry(); e.key = key; e.val = val; fHashTable.put(e.key, e); } // // RBBISymbolTable::print Debugging function, dump out the symbol table contents. // ///CLOVER:OFF void rbbiSymtablePrint() { System.out .print("Variable Definitions\n" + "Name Node Val String Val\n" + "----------------------------------------------------------------------\n"); RBBISymbolTableEntry[] syms = fHashTable.values().toArray(new RBBISymbolTableEntry[0]); for (int i = 0; i < syms.length; i++) { RBBISymbolTableEntry s = syms[i]; System.out.print(" " + s.key + " "); // TODO: format output into columns. System.out.print(" " + s.val + " "); System.out.print(s.val.fLeftChild.fText); System.out.print("\n"); } System.out.println("\nParsed Variable Definitions\n"); for (int i = 0; i < syms.length; i++) { RBBISymbolTableEntry s = syms[i]; System.out.print(s.key); s.val.fLeftChild.printTree(true); System.out.print("\n"); } } ///CLOVER:ON }