1 5 package org.h2.bnf; 6 7 import java.io.ByteArrayInputStream ; 8 import java.io.InputStreamReader ; 9 import java.io.Reader ; 10 import java.sql.ResultSet ; 11 import java.util.ArrayList ; 12 import java.util.HashMap ; 13 import java.util.Iterator ; 14 import java.util.Random ; 15 import java.util.StringTokenizer ; 16 17 import org.h2.server.web.DbContextRule; 18 import org.h2.tools.Csv; 19 import org.h2.util.Resources; 20 import org.h2.util.StringUtils; 21 22 public class Bnf { 23 24 static boolean COMBINE_KEYWORDS; 25 26 private static final String SEPARATORS = " [](){}|.,\r\n<>:-+*/=<\">!'"; 27 private static final long MAX_PARSE_TIME = 100; 28 29 private Random random; 30 private HashMap ruleMap = new HashMap (); 31 private String syntax; 32 private String currentToken; 33 private String [] tokens; 34 private char firstChar; 35 private int index; 36 private Rule lastRepeat; 37 private ArrayList statements; 38 private String currentTopic; 39 40 46 public static Bnf getInstance(Reader csv) throws Exception { 47 Bnf bnf = new Bnf(); 48 if(csv == null) { 49 byte[] data = Resources.get("/org/h2/res/help.csv"); 50 csv = new InputStreamReader (new ByteArrayInputStream (data)); 51 } 52 bnf.parse(csv); 53 return bnf; 54 } 55 56 Bnf() { 57 this.random = new Random (); 58 random.setSeed(1); 59 } 60 61 void addFixedRule(String name, int fixedType) { 62 Rule rule = new RuleFixed(fixedType); 63 addRule(name, 0, "Fixed", rule); 64 } 65 66 RuleHead addRule(String topic, int id, String section, Rule rule) { 67 RuleHead head = new RuleHead(id, section, topic, rule); 68 if(ruleMap.get(StringUtils.toLowerEnglish(topic)) != null) { 69 throw new Error ("already exists: " + topic); 70 } 71 ruleMap.put(StringUtils.toLowerEnglish(topic), head); 72 return head; 73 } 74 75 public Random getRandom() { 76 return random; 77 } 78 79 public HashMap getRuleMap() { 80 return ruleMap; 81 } 82 83 public void parse(Reader csv) throws Exception { 84 Rule functions = null; 85 statements = new ArrayList (); 86 ResultSet rs = Csv.getInstance().read(csv, null); 87 for(int id=0; rs.next(); id++) { 88 String section = rs.getString("SECTION").trim(); 89 if(section.startsWith("System")) { 90 continue; 91 } 92 String topic = StringUtils.toLowerEnglish(rs.getString("TOPIC").trim()); 93 topic = StringUtils.replaceAll(topic, " ", ""); 94 topic = StringUtils.replaceAll(topic, "_", ""); 95 syntax = rs.getString("SYNTAX").trim(); 96 currentTopic = section; 97 if(section.startsWith("Function")) { 98 int end = syntax.indexOf(':'); 99 syntax = syntax.substring(0, end); 100 } 101 tokens = tokenize(); 102 index = 0; 103 Rule rule = parseRule(); 104 if(section.startsWith("Command")) { 105 rule = new RuleList(rule, new RuleElement(";\n\n", currentTopic), false); 106 } 107 RuleHead head = addRule(topic, id, section, rule); 108 if(section.startsWith("Function")) { 109 if(functions == null) { 110 functions = rule; 111 } else { 112 functions = new RuleList(rule, functions, true); 113 } 114 } else if(section.startsWith("Commands")) { 115 statements.add(head); 116 } 117 } 118 addRule("@func@", 0, "Function", functions); 119 addFixedRule("@ymd@", RuleFixed.YMD); 120 addFixedRule("@hms@", RuleFixed.HMS); 121 addFixedRule("@nanos@", RuleFixed.NANOS); 122 addFixedRule("anythingExceptSingleQuote", RuleFixed.ANY_EXCEPT_SINGLE_QUOTE); 123 addFixedRule("anythingExceptDoubleQuote", RuleFixed.ANY_EXCEPT_DOUBLE_QUOTE); 124 addFixedRule("anythingUntilEndOfLine", RuleFixed.ANY_UNTIL_EOL); 125 addFixedRule("anythingUntilEndComment", RuleFixed.ANY_UNTIL_END); 126 addFixedRule("anything", RuleFixed.ANY_WORD); 127 addFixedRule("@hexStart@", RuleFixed.HEXSTART); 128 addFixedRule("@concat@", RuleFixed.CONCAT); 129 addFixedRule("@az_@", RuleFixed.AZ_); 130 addFixedRule("@af@", RuleFixed.AF); 131 addFixedRule("@digit@", RuleFixed.DIGIT); 132 } 133 134 public String getSyntax(String rule, String syntax) { 135 StringTokenizer tokenizer = new StringTokenizer (syntax, SEPARATORS, true); 136 StringBuffer buff = new StringBuffer (); 137 while(tokenizer.hasMoreTokens()) { 138 String s = tokenizer.nextToken(); 139 if(s.length() == 1 || StringUtils.toUpperEnglish(s).equals(s)) { 140 buff.append(s); 141 continue; 142 } 143 String section = null; 144 int id = -1; 145 for(int i=0; i<s.length(); i++) { 146 String test = StringUtils.toLowerEnglish(s.substring(i)); 147 RuleHead r = (RuleHead)ruleMap.get(test); 148 if(r != null) { 149 id = r.id; 150 section = r.section; 151 break; 152 } 153 } 154 if(id == -1) { 155 buff.append(s); 156 continue; 157 } 158 String page = "grammar.html"; 159 if(section.startsWith("Data Types")) { 160 page = "datatypes.html"; 161 } else if(section.startsWith("Functions")) { 162 page = "functions.html"; 163 } 164 buff.append("<a HREF=\""+page+"#sql"+id+"\">"); 165 buff.append(s); 166 buff.append("</a>"); 167 } 168 return buff.toString(); 169 } 170 171 private Rule parseRule() { 172 read(); 173 Rule r= parseOr(); 174 return r; 175 } 176 177 private Rule parseOr() { 178 Rule r = parseList(); 179 if(firstChar == '|') { 180 read(); 181 r = new RuleList(r, parseOr(), true); 182 } 183 lastRepeat = r; 184 return r; 185 } 186 187 private Rule parseList() { 188 Rule r = parseToken(); 189 if(firstChar != '|' && firstChar != ']' && firstChar != '}' && firstChar != 0) { 190 r = new RuleList(r, parseList(), false); 191 } 192 lastRepeat = r; 193 return r; 194 } 195 196 private Rule parseToken() { 197 Rule r; 198 if((firstChar >= 'A' && firstChar <= 'Z') || (firstChar >= 'a' && firstChar <= 'z')) { 199 r = new RuleElement(currentToken, currentTopic); 201 } else if(firstChar == '[') { 202 read(); 203 Rule r2 = parseOr(); 204 boolean repeat = false; 205 if(r2.last() instanceof RuleRepeat) { 206 repeat = true; 207 } 208 r = new RuleOptional(r2, repeat); 209 if(firstChar != ']') { 210 throw new Error ("expected ], got " + currentToken + " syntax:" + syntax); 211 } 212 } else if(firstChar == '{') { 213 read(); 214 r = parseOr(); 215 if(firstChar != '}') { 216 throw new Error ("expected }, got " + currentToken+ " syntax:" + syntax); 217 } 218 } else if("@commadots@".equals(currentToken)) { 219 r = new RuleList(new RuleElement(",", currentTopic), lastRepeat, false); 220 r = new RuleRepeat(r); 221 } else if("@dots@".equals(currentToken)) { 222 r = new RuleRepeat(lastRepeat); 223 } else { 224 r = new RuleElement(currentToken, currentTopic); 225 } 226 lastRepeat = r; 227 read(); 228 return r; 229 } 230 231 private void read() { 232 if(index < tokens.length) { 233 currentToken = tokens[index++]; 234 firstChar = currentToken.charAt(0); 235 } else { 236 currentToken = ""; 237 firstChar = 0; 238 } 239 } 240 241 private String [] tokenize() { 242 ArrayList list = new ArrayList (); 243 syntax = StringUtils.replaceAll(syntax, "yyyy-MM-dd", "@ymd@"); 244 syntax = StringUtils.replaceAll(syntax, "hh:mm:ss", "@hms@"); 245 syntax = StringUtils.replaceAll(syntax, "nnnnnnnnn", "@nanos@"); 246 syntax = StringUtils.replaceAll(syntax, "function", "@func@"); 247 syntax = StringUtils.replaceAll(syntax, "0x", "@hexStart@"); 248 syntax = StringUtils.replaceAll(syntax, ",...", "@commadots@"); 249 syntax = StringUtils.replaceAll(syntax, "...", "@dots@"); 250 syntax = StringUtils.replaceAll(syntax, "||", "@concat@"); 251 syntax = StringUtils.replaceAll(syntax, "a-z|_", "@az_@"); 252 syntax = StringUtils.replaceAll(syntax, "A-Z|_", "@az_@"); 253 syntax = StringUtils.replaceAll(syntax, "a-f", "@af@"); 254 syntax = StringUtils.replaceAll(syntax, "A-F", "@af@"); 255 syntax = StringUtils.replaceAll(syntax, "0-9", "@digit@"); 256 StringTokenizer tokenizer = new StringTokenizer (syntax, SEPARATORS, true); 257 while(tokenizer.hasMoreTokens()) { 258 String s = tokenizer.nextToken(); 259 if(s.length() == 1) { 260 if(" \r\n".indexOf(s.charAt(0))>=0) { 261 continue; 262 } 263 } 264 list.add(s); 265 } 266 return (String []) list.toArray(new String [0]); 267 } 268 269 public HashMap getNextTokenList(String query) { 270 HashMap next = new HashMap (); 271 Sentence sentence = new Sentence(); 272 sentence.next = next; 273 sentence.text = query; 274 for(int i=0; i<statements.size(); i++) { 275 RuleHead head = (RuleHead) statements.get(i); 276 if(!head.section.startsWith("Commands")) { 277 continue; 278 } 279 sentence.max = System.currentTimeMillis() + MAX_PARSE_TIME; 280 head.getRule().addNextTokenList(query, sentence); 281 } 282 return next; 283 } 284 285 public void linkStatements() { 286 HashMap ruleMap = getRuleMap(); 287 for(Iterator it = ruleMap.values().iterator(); it.hasNext(); ) { 288 RuleHead r = (RuleHead) it.next(); 289 r.getRule().setLinks(ruleMap); 290 } 291 } 292 293 public void updateTopic(String topic, DbContextRule rule) { 294 topic = StringUtils.toLowerEnglish(topic); 295 RuleHead head = (RuleHead) ruleMap.get(topic); 296 if(head == null) { 297 head = new RuleHead(0, "db", topic, rule); 298 ruleMap.put(topic, head); 299 statements.add(head); 300 } else { 301 head.rule = rule; 302 } 303 } 304 305 public void updateTopic(String topic, String [] array) { 306 topic = StringUtils.toLowerEnglish(topic); 307 ArrayList list = new ArrayList (); 308 for(int i=0; i<array.length; i++) { 309 list.add(new RuleElement(array[i], true, topic)); 310 } 311 RuleList rule = new RuleList(list, true); 312 RuleHead head = (RuleHead) ruleMap.get(topic); 313 if(head == null) { 314 head = new RuleHead(0, "db", topic, rule); 315 ruleMap.put(topic, head); 316 statements.add(head); 317 } else { 318 head.rule = rule; 319 } 320 } 321 322 public ArrayList getStatements() { 323 return statements; 324 } 325 326 } 327 | Popular Tags |