483 lines · c
1//===- TGLexer.h - Lexer for TableGen Files ---------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This class represents the Lexer for tablegen files.10//11//===----------------------------------------------------------------------===//12 13#ifndef LLVM_LIB_TABLEGEN_TGLEXER_H14#define LLVM_LIB_TABLEGEN_TGLEXER_H15 16#include "llvm/ADT/SmallVector.h"17#include "llvm/ADT/StringRef.h"18#include "llvm/ADT/StringSet.h"19#include "llvm/Support/DataTypes.h"20#include "llvm/Support/SMLoc.h"21#include <cassert>22#include <set>23#include <string>24 25namespace llvm {26template <typename T> class ArrayRef;27class SourceMgr;28class Twine;29 30namespace tgtok {31enum TokKind {32 // Markers33 Eof,34 Error,35 36 // Tokens with no info.37 minus, // -38 plus, // +39 l_square, // [40 r_square, // ]41 l_brace, // {42 r_brace, // }43 l_paren, // (44 r_paren, // )45 less, // <46 greater, // >47 colon, // :48 semi, // ;49 comma, // ,50 dot, // .51 equal, // =52 question, // ?53 paste, // #54 dotdotdot, // ...55 56 // Boolean literals.57 TrueVal,58 FalseVal,59 60 // Integer value.61 IntVal,62 63 // Binary constant. Note that these are sized according to the number of64 // bits given.65 BinaryIntVal,66 67 // Preprocessing tokens for internal usage by the lexer.68 // They are never returned as a result of Lex().69 Ifdef,70 Ifndef,71 Else,72 Endif,73 Define,74 75 // Reserved keywords. ('ElseKW' is named to distinguish it from the76 // existing 'Else' that means the preprocessor #else.)77 Bit,78 Bits,79 Code,80 Dag,81 ElseKW,82 Field,83 In,84 Include,85 Int,86 List,87 String,88 Then,89 90 // Object start tokens.91 OBJECT_START_FIRST,92 Assert = OBJECT_START_FIRST,93 Class,94 Def,95 Defm,96 Defset,97 Deftype,98 Defvar,99 Dump,100 Foreach,101 If,102 Let,103 MultiClass,104 OBJECT_START_LAST = MultiClass,105 106 // Bang operators.107 BANG_OPERATOR_FIRST,108 XConcat = BANG_OPERATOR_FIRST,109 XADD,110 XSUB,111 XMUL,112 XDIV,113 XNOT,114 XLOG2,115 XAND,116 XOR,117 XXOR,118 XSRA,119 XSRL,120 XSHL,121 XListConcat,122 XListFlatten,123 XListSplat,124 XStrConcat,125 XInterleave,126 XSubstr,127 XFind,128 XMatch,129 XCast,130 XSubst,131 XForEach,132 XFilter,133 XFoldl,134 XHead,135 XTail,136 XSize,137 XEmpty,138 XInitialized,139 XInstances,140 XIf,141 XCond,142 XEq,143 XIsA,144 XDag,145 XNe,146 XLe,147 XLt,148 XGe,149 XGt,150 XSetDagOp,151 XGetDagOp,152 XSetDagOpName,153 XGetDagOpName,154 XExists,155 XListRemove,156 XToLower,157 XToUpper,158 XRange,159 XGetDagArg,160 XGetDagName,161 XSetDagArg,162 XSetDagName,163 XRepr,164 BANG_OPERATOR_LAST = XRepr,165 166 // String valued tokens.167 STRING_VALUE_FIRST,168 Id = STRING_VALUE_FIRST,169 StrVal,170 VarName,171 CodeFragment,172 STRING_VALUE_LAST = CodeFragment,173};174 175/// isBangOperator - Return true if this is a bang operator.176static inline bool isBangOperator(tgtok::TokKind Kind) {177 return tgtok::BANG_OPERATOR_FIRST <= Kind && Kind <= BANG_OPERATOR_LAST;178}179 180/// isObjectStart - Return true if this is a valid first token for a statement.181static inline bool isObjectStart(tgtok::TokKind Kind) {182 return tgtok::OBJECT_START_FIRST <= Kind && Kind <= OBJECT_START_LAST;183}184 185/// isStringValue - Return true if this is a string value.186static inline bool isStringValue(tgtok::TokKind Kind) {187 return tgtok::STRING_VALUE_FIRST <= Kind && Kind <= STRING_VALUE_LAST;188}189} // namespace tgtok190 191/// TGLexer - TableGen Lexer class.192class TGLexer {193 SourceMgr &SrcMgr;194 195 const char *CurPtr = nullptr;196 StringRef CurBuf;197 198 // Information about the current token.199 const char *TokStart = nullptr;200 tgtok::TokKind CurCode = tgtok::TokKind::Eof;201 std::string CurStrVal; // This is valid for Id, StrVal, VarName, CodeFragment202 int64_t CurIntVal = 0; // This is valid for IntVal.203 204 /// CurBuffer - This is the current buffer index we're lexing from as managed205 /// by the SourceMgr object.206 unsigned CurBuffer = 0;207 208public:209 typedef std::set<std::string> DependenciesSetTy;210 211private:212 /// Dependencies - This is the list of all included files.213 DependenciesSetTy Dependencies;214 215public:216 TGLexer(SourceMgr &SrcMgr, ArrayRef<std::string> Macros);217 218 tgtok::TokKind Lex() { return CurCode = LexToken(CurPtr == CurBuf.begin()); }219 220 const DependenciesSetTy &getDependencies() const { return Dependencies; }221 222 tgtok::TokKind getCode() const { return CurCode; }223 224 const std::string &getCurStrVal() const {225 assert(tgtok::isStringValue(CurCode) &&226 "This token doesn't have a string value");227 return CurStrVal;228 }229 int64_t getCurIntVal() const {230 assert(CurCode == tgtok::IntVal && "This token isn't an integer");231 return CurIntVal;232 }233 std::pair<int64_t, unsigned> getCurBinaryIntVal() const {234 assert(CurCode == tgtok::BinaryIntVal &&235 "This token isn't a binary integer");236 return {CurIntVal, (CurPtr - TokStart) - 2};237 }238 239 SMLoc getLoc() const;240 SMRange getLocRange() const;241 242private:243 /// LexToken - Read the next token and return its code.244 tgtok::TokKind LexToken(bool FileOrLineStart = false);245 246 tgtok::TokKind ReturnError(SMLoc Loc, const Twine &Msg);247 tgtok::TokKind ReturnError(const char *Loc, const Twine &Msg);248 249 int getNextChar();250 int peekNextChar(int Index) const;251 void SkipBCPLComment();252 bool SkipCComment();253 tgtok::TokKind LexIdentifier();254 bool LexInclude();255 tgtok::TokKind LexString();256 tgtok::TokKind LexVarName();257 tgtok::TokKind LexNumber();258 tgtok::TokKind LexBracket();259 tgtok::TokKind LexExclaim();260 261 // Process EOF encountered in LexToken().262 // If EOF is met in an include file, then the method will update263 // CurPtr, CurBuf and preprocessing include stack, and return true.264 // If EOF is met in the top-level file, then the method will265 // update and check the preprocessing include stack, and return false.266 bool processEOF();267 268 // *** Structures and methods for preprocessing support ***269 270 // A set of macro names that are defined either via command line or271 // by using:272 // #define NAME273 StringSet<> DefinedMacros;274 275 // Each of #ifdef and #else directives has a descriptor associated276 // with it.277 //278 // An ordered list of preprocessing controls defined by #ifdef/#else279 // directives that are in effect currently is called preprocessing280 // control stack. It is represented as a vector of PreprocessorControlDesc's.281 //282 // The control stack is updated according to the following rules:283 //284 // For each #ifdef we add an element to the control stack.285 // For each #else we replace the top element with a descriptor286 // with an inverted IsDefined value.287 // For each #endif we pop the top element from the control stack.288 //289 // When CurPtr reaches the current buffer's end, the control stack290 // must be empty, i.e. #ifdef and the corresponding #endif291 // must be located in the same file.292 struct PreprocessorControlDesc {293 // Either tgtok::Ifdef or tgtok::Else.294 tgtok::TokKind Kind;295 296 // True, if the condition for this directive is true, false - otherwise.297 // Examples:298 // #ifdef NAME : true, if NAME is defined, false - otherwise.299 // ...300 // #else : false, if NAME is defined, true - otherwise.301 bool IsDefined;302 303 // Pointer into CurBuf to the beginning of the preprocessing directive304 // word, e.g.:305 // #ifdef NAME306 // ^ - SrcPos307 SMLoc SrcPos;308 };309 310 // We want to disallow code like this:311 // file1.td:312 // #define NAME313 // #ifdef NAME314 // include "file2.td"315 // EOF316 // file2.td:317 // #endif318 // EOF319 //320 // To do this, we clear the preprocessing control stack on entry321 // to each of the included file. PrepIncludeStack is used to store322 // preprocessing control stacks for the current file and all its323 // parent files. The back() element is the preprocessing control324 // stack for the current file.325 SmallVector<SmallVector<PreprocessorControlDesc>> PrepIncludeStack;326 327 // Validate that the current preprocessing control stack is empty,328 // since we are about to exit a file, and pop the include stack.329 //330 // If IncludeStackMustBeEmpty is true, the include stack must be empty331 // after the popping, otherwise, the include stack must not be empty332 // after the popping. Basically, the include stack must be empty333 // only if we exit the "top-level" file (i.e. finish lexing).334 //335 // The method returns false, if the current preprocessing control stack336 // is not empty (e.g. there is an unterminated #ifdef/#else),337 // true - otherwise.338 bool prepExitInclude(bool IncludeStackMustBeEmpty);339 340 // Look ahead for a preprocessing directive starting from CurPtr. The caller341 // must only call this method, if *(CurPtr - 1) is '#'. If the method matches342 // a preprocessing directive word followed by a whitespace, then it returns343 // one of the internal token kinds, i.e. Ifdef, Else, Endif, Define.344 //345 // CurPtr is not adjusted by this method.346 tgtok::TokKind prepIsDirective() const;347 348 // Given a preprocessing token kind, adjusts CurPtr to the end349 // of the preprocessing directive word.350 //351 // We use look-ahead prepIsDirective() and prepEatPreprocessorDirective()352 // to avoid adjusting CurPtr before we are sure that '#' is followed353 // by a preprocessing directive. If it is not, then we fall back to354 // tgtok::paste interpretation of '#'.355 void prepEatPreprocessorDirective(tgtok::TokKind Kind);356 357 // The main "exit" point from the token parsing to preprocessor.358 //359 // The method is called for CurPtr, when prepIsDirective() returns360 // true. The first parameter matches the result of prepIsDirective(),361 // denoting the actual preprocessor directive to be processed.362 //363 // If the preprocessing directive disables the tokens processing, e.g.:364 // #ifdef NAME // NAME is undefined365 // then lexPreprocessor() enters the lines-skipping mode.366 // In this mode, it does not parse any tokens, because the code under367 // the #ifdef may not even be a correct tablegen code. The preprocessor368 // looks for lines containing other preprocessing directives, which369 // may be prepended with whitespaces and C-style comments. If the line370 // does not contain a preprocessing directive, it is skipped completely.371 // Otherwise, the preprocessing directive is processed by recursively372 // calling lexPreprocessor(). The processing of the encountered373 // preprocessing directives includes updating preprocessing control stack374 // and adding new macros into DefinedMacros set.375 //376 // The second parameter controls whether lexPreprocessor() is called from377 // LexToken() (true) or recursively from lexPreprocessor() (false).378 //379 // If ReturnNextLiveToken is true, the method returns the next380 // LEX token following the current directive or following the end381 // of the disabled preprocessing region corresponding to this directive.382 // If ReturnNextLiveToken is false, the method returns the first parameter,383 // unless there were errors encountered in the disabled preprocessing384 // region - in this case, it returns tgtok::Error.385 tgtok::TokKind lexPreprocessor(tgtok::TokKind Kind,386 bool ReturnNextLiveToken = true);387 388 // Worker method for lexPreprocessor() to skip lines after some389 // preprocessing directive up to the buffer end or to the directive390 // that re-enables token processing. The method returns true391 // upon processing the next directive that re-enables tokens392 // processing. False is returned if an error was encountered.393 //394 // Note that prepSkipRegion() calls lexPreprocessor() to process395 // encountered preprocessing directives. In this case, the second396 // parameter to lexPreprocessor() is set to false. Being passed397 // false ReturnNextLiveToken, lexPreprocessor() must never call398 // prepSkipRegion(). We assert this by passing ReturnNextLiveToken399 // to prepSkipRegion() and checking that it is never set to false.400 bool prepSkipRegion(bool MustNeverBeFalse);401 402 // Lex name of the macro after either #ifdef or #define. We could have used403 // LexIdentifier(), but it has special handling of "include" word, which404 // could result in awkward diagnostic errors. Consider:405 // ----406 // #ifdef include407 // class ...408 // ----409 // LexIdentifier() will engage LexInclude(), which will complain about410 // missing file with name "class". Instead, prepLexMacroName() will treat411 // "include" as a normal macro name.412 //413 // On entry, CurPtr points to the end of a preprocessing directive word.414 // The method allows for whitespaces between the preprocessing directive415 // and the macro name. The allowed whitespaces are ' ' and '\t'.416 //417 // If the first non-whitespace symbol after the preprocessing directive418 // is a valid start symbol for an identifier (i.e. [a-zA-Z_]), then419 // the method updates TokStart to the position of the first non-whitespace420 // symbol, sets CurPtr to the position of the macro name's last symbol,421 // and returns a string reference to the macro name. Otherwise,422 // TokStart is set to the first non-whitespace symbol after the preprocessing423 // directive, and the method returns an empty string reference.424 //425 // In all cases, TokStart may be used to point to the word following426 // the preprocessing directive.427 StringRef prepLexMacroName();428 429 // Skip any whitespaces starting from CurPtr. The method is used430 // only in the lines-skipping mode to find the first non-whitespace431 // symbol after or at CurPtr. Allowed whitespaces are ' ', '\t', '\n'432 // and '\r'. The method skips C-style comments as well, because433 // it is used to find the beginning of the preprocessing directive.434 // If we do not handle C-style comments the following code would435 // result in incorrect detection of a preprocessing directive:436 // /*437 // #ifdef NAME438 // */439 // As long as we skip C-style comments, the following code is correctly440 // recognized as a preprocessing directive:441 // /* first line comment442 // second line comment */ #ifdef NAME443 //444 // The method returns true upon reaching the first non-whitespace symbol445 // or EOF, CurPtr is set to point to this symbol. The method returns false,446 // if an error occurred during skipping of a C-style comment.447 bool prepSkipLineBegin();448 449 // Skip any whitespaces or comments after a preprocessing directive.450 // The method returns true upon reaching either end of the line451 // or end of the file. If there is a multiline C-style comment452 // after the preprocessing directive, the method skips453 // the comment, so the final CurPtr may point to one of the next lines.454 // The method returns false, if an error occurred during skipping455 // C- or C++-style comment, or a non-whitespace symbol appears456 // after the preprocessing directive.457 //458 // The method maybe called both during lines-skipping and tokens459 // processing. It actually verifies that only whitespaces or/and460 // comments follow a preprocessing directive.461 //462 // After the execution of this mehod, CurPtr points either to new line463 // symbol, buffer end or non-whitespace symbol following the preprocesing464 // directive.465 bool prepSkipDirectiveEnd();466 467 // Return true, if the current preprocessor control stack is such that468 // we should allow lexer to process the next token, false - otherwise.469 //470 // In particular, the method returns true, if all the #ifdef/#else471 // controls on the stack have their IsDefined member set to true.472 bool prepIsProcessingEnabled();473 474 // Report an error, if we reach EOF with non-empty preprocessing control475 // stack. This means there is no matching #endif for the previous476 // #ifdef/#else.477 void prepReportPreprocessorStackError();478};479 480} // end namespace llvm481 482#endif483