1 /* 2 * [The "BSD license"] 3 * Copyright (c) 2012 Terence Parr 4 * Copyright (c) 2012 Sam Harwell 5 * Copyright (c) 2017 Egbert Voigt 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 module antlr.v4.runtime.Recognizer; 33 34 import std.stdio; 35 import std.algorithm; 36 import std.array; 37 import std.conv; 38 import antlr.v4.runtime.ANTLRErrorListener; 39 import antlr.v4.runtime.ConsoleErrorListener; 40 import antlr.v4.runtime.InterfaceRuleContext; 41 import antlr.v4.runtime.Token; 42 import antlr.v4.runtime.TokenConstantDefinition; 43 import antlr.v4.runtime.IntStream; 44 import antlr.v4.runtime.InterfaceRecognizer; 45 import antlr.v4.runtime.UnsupportedOperationException; 46 import antlr.v4.runtime.RecognitionException; 47 import antlr.v4.runtime.TokenFactory; 48 import antlr.v4.runtime.CommonToken; 49 import antlr.v4.runtime.ProxyErrorListener; 50 import antlr.v4.runtime.Vocabulary; 51 import antlr.v4.runtime.VocabularyImpl; 52 import antlr.v4.runtime.atn.ATN; 53 import antlr.v4.runtime.atn.ParseInfo; 54 55 // Class Template Recognizer 56 /** 57 * TODO add class description 58 */ 59 abstract class Recognizer(U, V) : InterfaceRecognizer 60 { 61 62 public static immutable int EOF = -1; 63 64 public int[string][Vocabulary] tokenTypeMapCache; 65 66 public int[string][string] ruleIndexMapCache; 67 68 public ANTLRErrorListener!(U,V)[] _listeners; 69 70 protected V _interp; 71 72 private int _stateNumber = -1; 73 74 public this() 75 { 76 _listeners = [ConsoleErrorListener!(U,V).instance]; 77 } 78 79 /** 80 * @uml 81 * Used to print out token names like ID during debugging and 82 * error reporting. The generated parsers implement a method 83 * that overrides this to point to their String[] tokenNames. 84 * 85 * @deprecated Use {@link #getVocabulary()} instead. 86 */ 87 abstract public string[] getTokenNames(); 88 89 abstract public string[] getRuleNames(); 90 91 /** 92 * @uml 93 * Get the vocabulary used by the recognizer. 94 * 95 * @return A {@link Vocabulary} instance providing information about the 96 * vocabulary used by the grammar. 97 */ 98 public Vocabulary getVocabulary() 99 { 100 return VocabularyImpl.fromTokenNames(getTokenNames()); 101 } 102 103 /** 104 * @uml 105 * Get a map from token names to token types. 106 * <p>Used for XPath and tree pattern compilation.</p> 107 */ 108 public int[string] getTokenTypeMap() 109 { 110 Vocabulary vocabulary = getVocabulary(); 111 int[string] result = tokenTypeMapCache[vocabulary]; 112 if (result is null) { 113 int[string] result1; 114 result = result1; 115 for (int i = 0; i < getATN.maxTokenType; i++) { 116 string literalName = vocabulary.getLiteralName(i); 117 if (literalName !is null) { 118 result[literalName] = i; 119 } 120 121 string symbolicName = vocabulary.getSymbolicName(i); 122 if (symbolicName != null) { 123 result[symbolicName] = i; 124 } 125 } 126 127 result["EOF"] = TokenConstantDefinition.EOF; 128 result.rehash; // for faster lookups 129 tokenTypeMapCache[vocabulary] = result; 130 } 131 return result; 132 } 133 134 /** 135 * @uml 136 * Get a map from rule names to rule indexes. 137 * 138 * <p>Used for XPath and tree pattern compilation. 139 */ 140 public int[string] getRuleIndexMap() 141 { 142 string[] ruleNames = getRuleNames(); 143 if (!ruleNames) { 144 throw new UnsupportedOperationException("The current recognizer does not provide a list of rule names."); 145 } 146 int[string] result; 147 if (to!string(joiner(ruleNames, ",")) in ruleIndexMapCache) { 148 result = ruleIndexMapCache[to!string(joiner(ruleNames, ","))]; 149 } 150 else { 151 foreach (int i, rn; ruleNames) { 152 result[rn] = i; 153 } 154 ruleIndexMapCache[to!string(joiner(ruleNames, ","))] = result; 155 } 156 return result; 157 } 158 159 public int getTokenType(string tokenName) 160 { 161 int ttype = getTokenTypeMap()[tokenName]; 162 if (ttype) return ttype; 163 return TokenConstantDefinition.INVALID_TYPE; 164 } 165 166 /** 167 * @uml 168 * If this recognizer was generated, it will have a serialized ATN 169 * representation of the grammar. 170 * 171 * <p>For interpreters, we don't know their serialized ATN despite having 172 * created the interpreter from it.</p> 173 */ 174 public wstring getSerializedATN() 175 { 176 throw new UnsupportedOperationException("there is no serialized ATN"); 177 } 178 179 /** 180 * @uml 181 * For debugging and other purposes, might want the grammar name. 182 * Have ANTLR generate an implementation for this method. 183 */ 184 abstract public string getGrammarFileName(); 185 186 /** 187 * @uml 188 * Get the {@link ATN} used by the recognizer for prediction. 189 * 190 * @return The {@link ATN} used by the recognizer for prediction. 191 */ 192 abstract public ATN getATN(); 193 194 /** 195 * @uml 196 * Get the ATN interpreter used by the recognizer for prediction. 197 * 198 * @return The ATN interpreter used by the recognizer for prediction. 199 */ 200 public V getInterpreter() 201 { 202 return _interp; 203 } 204 205 /** 206 * @uml 207 * If profiling during the parse/lex, this will return DecisionInfo records 208 * for each decision in recognizer in a ParseInfo object. 209 */ 210 public ParseInfo getParseInfo() 211 { 212 return null; 213 } 214 215 public void setInterpreter(V interpreter) 216 { 217 _interp = interpreter; 218 } 219 220 /** 221 * @uml 222 * What is the error header, normally line/character position information? 223 */ 224 public string getErrorHeader(RecognitionException e) 225 { 226 int line = e.getOffendingToken().getLine(); 227 int charPositionInLine = e.getOffendingToken().getCharPositionInLine(); 228 return "line " ~ to!string(line) ~ ":" ~ to!string(charPositionInLine); 229 } 230 231 /** 232 * @uml 233 * How should a token be displayed in an error message? The default 234 * is to display just the text, but during development you might 235 * want to have a lot of information spit out. Override in that case 236 * to use t.toString() (which, for CommonToken, dumps everything about 237 * the token). This is better than forcing you to override a method in 238 * your token objects because you don't have to go modify your lexer 239 * so that it creates a new Java type. 240 * 241 * @deprecated This method is not called by the ANTLR 4 Runtime. Specific 242 * implementations of {@link ANTLRErrorStrategy} may provide a similar 243 * feature when necessary. For example, see 244 * {@link DefaultErrorStrategy#getTokenErrorDisplay}. 245 */ 246 public string getTokenErrorDisplay(Token t) 247 { 248 if (t is null) return "<no token>"; 249 string s = t.getText(); 250 if (s is null) { 251 if (t.getType() == TokenConstantDefinition.EOF) { 252 s = "<EOF>"; 253 } 254 else { 255 s = "<" ~ to!string(t.getType) ~ ">"; 256 } 257 } 258 s = s.replace("\n","\\n"); 259 s = s.replace("\r","\\r"); 260 s = s.replace("\t","\\t"); 261 return "'" ~ s ~ "'"; 262 } 263 264 public void addErrorListener(ANTLRErrorListener!(U, V) listener) 265 { 266 if (listener is null) { 267 assert(0, "listener cannot be null."); 268 } 269 270 _listeners ~= listener; 271 } 272 273 public void removeErrorListener(ANTLRErrorListener!(U, V) listener) 274 { 275 foreach (int elementRemoveIndex, el; _listeners) { 276 if (listener is el) { 277 _listeners.remove(elementRemoveIndex); 278 break; 279 } 280 } 281 } 282 283 public void removeErrorListeners() 284 { 285 _listeners.length = 0; 286 } 287 288 public ANTLRErrorListener!(U,V)[] getErrorListeners() 289 { 290 return _listeners; 291 } 292 293 public ANTLRErrorListener!(U, V) getErrorListenerDispatch() 294 { 295 return new ProxyErrorListener!(U, V)(getErrorListeners()); 296 } 297 298 /** 299 * @uml 300 * subclass needs to override these if there are sempreds or actions 301 * that the ATN interp needs to execute 302 */ 303 public bool sempred(InterfaceRuleContext localctx, int ruleIndex, int actionIndex) 304 { 305 return true; 306 } 307 308 public bool precpred(InterfaceRuleContext localctx, int precedence) 309 { 310 return true; 311 } 312 313 public void action(InterfaceRuleContext localctx, int ruleIndex, int actionIndex) 314 { 315 } 316 317 /** 318 * @uml 319 * @final 320 */ 321 public final int getState() 322 { 323 return _stateNumber; 324 } 325 326 /** 327 * @uml 328 * @final 329 * Indicate that the recognizer has changed internal state that is 330 * consistent with the ATN state passed in. This way we always know 331 * where we are in the ATN as the parser goes along. The rule 332 * context objects form a stack that lets us see the stack of 333 * invoking rules. Combine this and we have complete ATN 334 * configuration information. 335 */ 336 public final void setState(int atnState) 337 { 338 //writeln("setState "+atnState); 339 _stateNumber = atnState; 340 // if ( traceATNStates ) _ctx.trace(atnState); 341 } 342 343 abstract public IntStream getInputStream(); 344 345 abstract public void setInputStream(IntStream input); 346 347 abstract public TokenFactory!CommonToken tokenFactory(); 348 349 abstract public void tokenFactory(TokenFactory!CommonToken input); 350 351 }