1 21 22 package net.percederberg.grammatica; 23 24 import java.io.File ; 25 import java.io.FileNotFoundException ; 26 import java.io.FileReader ; 27 import java.io.Reader ; 28 import java.util.HashMap ; 29 import java.util.LinkedList ; 30 31 import net.percederberg.grammatica.parser.Analyzer; 32 import net.percederberg.grammatica.parser.Parser; 33 import net.percederberg.grammatica.parser.ParserCreationException; 34 import net.percederberg.grammatica.parser.ParserLogException; 35 import net.percederberg.grammatica.parser.ProductionPattern; 36 import net.percederberg.grammatica.parser.RecursiveDescentParser; 37 import net.percederberg.grammatica.parser.TokenPattern; 38 import net.percederberg.grammatica.parser.Tokenizer; 39 40 47 public class Grammar extends Object { 48 49 52 public static final String AUTHOR_DECLARATION = "AUTHOR"; 53 54 59 public static final String CASE_SENSITIVE_DECLARATION = "CASESENSITIVE"; 60 61 64 public static final String COPYRIGHT_DECLARATION = "COPYRIGHT"; 65 66 69 public static final String DATE_DECLARATION = "DATE"; 70 71 74 public static final String DESCRIPTION_DECLARATION = "DESCRIPTION"; 75 76 79 public static final String GRAMMAR_TYPE_DECLARATION = "GRAMMARTYPE"; 80 81 84 public static final String LICENSE_DECLARATION = "LICENSE"; 85 86 89 public static final String VERSION_DECLARATION = "VERSION"; 90 91 94 private String fileName = ""; 95 96 100 private HashMap declarations = new HashMap (); 101 102 105 private LinkedList tokens = new LinkedList (); 106 107 111 private HashMap tokenIds = new HashMap (); 112 113 117 private HashMap tokenNames = new HashMap (); 118 119 123 private HashMap tokenPatterns = new HashMap (); 124 125 128 private LinkedList productions = new LinkedList (); 129 130 134 private HashMap productionIds = new HashMap (); 135 136 140 private HashMap productionNames = new HashMap (); 141 142 145 private HashMap lines = new HashMap (); 146 147 158 public Grammar(File file) throws FileNotFoundException , 159 ParserLogException, GrammarException { 160 161 GrammarParser parser; 162 FirstPassAnalyzer first = new FirstPassAnalyzer(this); 163 SecondPassAnalyzer second = new SecondPassAnalyzer(this); 164 165 fileName = file.toString(); 166 try { 167 parser = new GrammarParser(new FileReader (file), first); 168 second.analyze(parser.parse()); 169 } catch (ParserCreationException e) { 170 throw new UnsupportedOperationException ( 171 "internal error in grammar parser: " + e.getMessage()); 172 } 173 verify(); 174 } 175 176 181 private void verify() throws GrammarException { 182 String type; 183 184 type = (String ) declarations.get(GRAMMAR_TYPE_DECLARATION); 186 if (type == null) { 187 throw new GrammarException( 188 fileName, 189 "grammar header missing " + GRAMMAR_TYPE_DECLARATION + 190 " declaration"); 191 } else if (!type.equals("LL")) { 192 throw new GrammarException( 193 fileName, 194 "unrecognized " + GRAMMAR_TYPE_DECLARATION + " value: '" + 195 type + "', currently only 'LL' is supported"); 196 } 197 198 if (productions.size() > 0) { 200 createParser(createTokenizer(null)); 201 } 202 } 203 204 214 public Tokenizer createTokenizer(Reader in) 215 throws GrammarException { 216 217 Tokenizer tokenizer; 218 219 try { 220 tokenizer = new Tokenizer(in, !getCaseSensitive()); 221 for (int i = 0; i < tokens.size(); i++) { 222 tokenizer.addPattern((TokenPattern) tokens.get(i)); 223 } 224 } catch (ParserCreationException e) { 225 if (e.getName() == null) { 226 throw new GrammarException(fileName, e.getMessage()); 227 } else { 228 LineRange range = (LineRange) lines.get(e.getName()); 229 throw new GrammarException(fileName, 230 e.getMessage(), 231 range.getStart(), 232 range.getEnd()); 233 } 234 } 235 236 return tokenizer; 237 } 238 239 249 public Parser createParser(Tokenizer tokenizer) 250 throws GrammarException { 251 252 return createParser(tokenizer, null); 253 } 254 255 266 public Parser createParser(Tokenizer tokenizer, Analyzer analyzer) 267 throws GrammarException { 268 269 Parser parser; 270 271 try { 272 parser = new RecursiveDescentParser(tokenizer, analyzer); 273 for (int i = 0; i < productions.size(); i++) { 274 parser.addPattern((ProductionPattern) productions.get(i)); 275 } 276 parser.prepare(); 277 } catch (ParserCreationException e) { 278 LineRange range = (LineRange) lines.get(e.getName()); 279 if (range == null) { 280 throw new GrammarException(fileName, e.getMessage()); 281 } else { 282 throw new GrammarException(fileName, 283 e.getMessage(), 284 range.getStart(), 285 range.getEnd()); 286 } 287 } 288 289 return parser; 290 } 291 292 297 public String getFileName() { 298 return fileName; 299 } 300 301 309 public String getDeclaration(String name) { 310 return (String ) declarations.get(name); 311 } 312 313 323 public boolean getCaseSensitive() { 324 String str = getDeclaration(CASE_SENSITIVE_DECLARATION); 325 326 if (str == null) { 327 return true; 328 } else { 329 return !str.equalsIgnoreCase("no") 330 && !str.equalsIgnoreCase("false"); 331 } 332 } 333 334 339 public int getTokenPatternCount() { 340 return tokens.size(); 341 } 342 343 350 public TokenPattern getTokenPattern(int pos) { 351 return (TokenPattern) tokens.get(pos); 352 } 353 354 361 public TokenPattern getTokenPatternById(int id) { 362 return (TokenPattern) tokenIds.get(new Integer (id)); 363 } 364 365 372 public TokenPattern getTokenPatternByName(String name) { 373 return (TokenPattern) tokenNames.get(name); 374 } 375 376 384 TokenPattern getTokenPatternByImage(String image) { 385 return (TokenPattern) tokenPatterns.get(image); 386 } 387 388 393 public int getProductionPatternCount() { 394 return productions.size(); 395 } 396 397 404 public ProductionPattern getProductionPattern(int pos) { 405 return (ProductionPattern) productions.get(pos); 406 } 407 408 415 public ProductionPattern getProductionPatternById(int id) { 416 return (ProductionPattern) productionIds.get(new Integer (id)); 417 } 418 419 426 public ProductionPattern getProductionPatternByName(String name) { 427 return (ProductionPattern) productionNames.get(name); 428 } 429 430 436 void addDeclaration(String name, String value) { 437 declarations.put(name, value); 438 } 439 440 447 void addToken(TokenPattern token, int start, int end) { 448 tokens.add(token); 449 tokenIds.put(new Integer (token.getId()), token); 450 tokenNames.put(token.getName(), token); 451 if (token.getType() == TokenPattern.STRING_TYPE) { 452 tokenPatterns.put(token.getPattern(), token); 453 } 454 lines.put(token.getName(), new LineRange(start, end)); 455 } 456 457 464 void addProduction(ProductionPattern production, int start, int end) { 465 productions.add(production); 466 productionIds.put(new Integer (production.getId()), production); 467 productionNames.put(production.getName(), production); 468 lines.put(production.getName(), new LineRange(start, end)); 469 } 470 471 472 475 private class LineRange { 476 477 480 private int start; 481 482 485 private int end; 486 487 493 public LineRange(int start, int end) { 494 this.start = start; 495 this.end = end; 496 } 497 498 503 public int getStart() { 504 return start; 505 } 506 507 512 public int getEnd() { 513 return end; 514 } 515 } 516 } 517 | Popular Tags |