19 #include "llvm/ADT/SmallString.h"
20 #include "llvm/ADT/StringExtras.h"
21 #include "llvm/MC/MCAsmInfo.h"
22 #include "llvm/MC/MCContext.h"
23 #include "llvm/MC/MCInstPrinter.h"
24 #include "llvm/MC/MCInstrInfo.h"
25 #include "llvm/MC/MCObjectFileInfo.h"
26 #include "llvm/MC/MCParser/MCAsmParser.h"
27 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
28 #include "llvm/MC/MCRegisterInfo.h"
29 #include "llvm/MC/MCStreamer.h"
30 #include "llvm/MC/MCSubtargetInfo.h"
31 #include "llvm/MC/MCTargetOptions.h"
32 #include "llvm/Support/SourceMgr.h"
33 #include "llvm/Support/TargetRegistry.h"
34 #include "llvm/Support/TargetSelect.h"
35 using namespace clang;
38 class ClangAsmParserCallback :
public llvm::MCAsmParserSemaCallback {
52 : TheParser(P), AsmLoc(Loc), AsmString(AsmString), AsmToks(Toks),
53 AsmTokOffsets(Offsets) {
54 assert(AsmToks.size() == AsmTokOffsets.size());
57 void *LookupInlineAsmIdentifier(StringRef &LineBuf,
58 llvm::InlineAsmIdentifierInfo &Info,
59 bool IsUnevaluatedContext)
override {
62 const Token *FirstOrigToken =
nullptr;
63 findTokensForString(LineBuf, LineToks, FirstOrigToken);
65 unsigned NumConsumedToks;
67 LineToks, NumConsumedToks, &Info, IsUnevaluatedContext);
71 if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) {
76 assert(FirstOrigToken &&
"not using original tokens?");
79 assert(FirstOrigToken[NumConsumedToks].getLocation() ==
80 LineToks[NumConsumedToks].getLocation());
81 unsigned FirstIndex = FirstOrigToken - AsmToks.begin();
82 unsigned LastIndex = FirstIndex + NumConsumedToks - 1;
86 unsigned TotalOffset =
87 (AsmTokOffsets[LastIndex] + AsmToks[LastIndex].getLength() -
88 AsmTokOffsets[FirstIndex]);
89 LineBuf = LineBuf.substr(0, TotalOffset);
93 Info.OpDecl =
static_cast<void *
>(Result.
get());
97 StringRef LookupInlineAsmLabel(StringRef Identifier, llvm::SourceMgr &LSM,
102 TheParser.getActions().GetOrCreateMSAsmLabel(Identifier, Loc, Create);
106 bool LookupInlineAsmField(StringRef
Base, StringRef Member,
107 unsigned &
Offset)
override {
108 return TheParser.getActions().LookupInlineAsmField(Base, Member, Offset,
112 static void DiagHandlerCallback(
const llvm::SMDiagnostic &D,
void *
Context) {
113 ((ClangAsmParserCallback *)Context)->handleDiagnostic(D);
119 const Token *&FirstOrigToken)
const {
122 assert(!std::less<const char *>()(Str.begin(), AsmString.begin()) &&
123 !std::less<const char *>()(AsmString.end(), Str.end()));
126 unsigned FirstCharOffset = Str.begin() - AsmString.begin();
127 const unsigned *FirstTokOffset = std::lower_bound(
128 AsmTokOffsets.begin(), AsmTokOffsets.end(), FirstCharOffset);
132 assert(*FirstTokOffset == FirstCharOffset);
136 unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin();
137 FirstOrigToken = &AsmToks[FirstTokIndex];
138 unsigned LastCharOffset = Str.end() - AsmString.begin();
139 for (
unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) {
140 if (AsmTokOffsets[i] >= LastCharOffset)
142 TempToks.push_back(AsmToks[i]);
146 SourceLocation translateLocation(
const llvm::SourceMgr &LSM, llvm::SMLoc SMLoc) {
150 const llvm::MemoryBuffer *LBuf =
151 LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(SMLoc));
152 unsigned Offset = SMLoc.getPointer() - LBuf->getBufferStart();
155 const unsigned *TokOffsetPtr =
156 std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(),
Offset);
157 unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin();
158 unsigned TokOffset = *TokOffsetPtr;
164 if (TokIndex < AsmToks.size()) {
165 const Token &Tok = AsmToks[TokIndex];
172 void handleDiagnostic(
const llvm::SMDiagnostic &D) {
173 const llvm::SourceMgr &LSM = *D.getSourceMgr();
175 TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();
185 unsigned &NumLineToksConsumed,
187 bool IsUnevaluatedContext) {
188 llvm::InlineAsmIdentifierInfo &Info =
189 *(llvm::InlineAsmIdentifierInfo *)CastInfo;
195 Token EndOfStreamTok;
197 EndOfStreamTok.
setKind(EndOfStream);
198 LineToks.push_back(EndOfStreamTok);
201 LineToks.push_back(Tok);
203 PP.EnterTokenStream(LineToks,
true);
211 ParseOptionalCXXScopeSpecifier(SS,
nullptr,
false);
219 if (Tok.
is(tok::kw_this)) {
220 Result = ParseCXXThis();
227 nullptr, TemplateKWLoc, Id);
230 IsUnevaluatedContext);
235 while (Result.
isUsable() && Tok.
is(tok::period)) {
237 if (IdTok.
isNot(tok::identifier))
247 unsigned LineIndex = 0;
248 if (Tok.
is(EndOfStream)) {
249 LineIndex = LineToks.size() - 2;
251 while (LineToks[LineIndex].getLocation() != Tok.
getLocation()) {
253 assert(LineIndex < LineToks.size() - 2);
259 if (Invalid || Tok.
is(EndOfStream)) {
260 NumLineToksConsumed = LineToks.size() - 2;
263 NumLineToksConsumed = LineIndex;
268 for (
unsigned i = 0, e = LineToks.size() - LineIndex - 2; i != e; ++i) {
271 assert(Tok.
is(EndOfStream));
287 assert(!AsmToks.empty() &&
"Didn't expect an empty AsmToks!");
290 bool isNewStatement =
true;
292 for (
unsigned i = 0, e = AsmToks.size(); i < e; ++i) {
293 const Token &Tok = AsmToks[i];
298 isNewStatement =
true;
307 TokOffsets.push_back(Asm.size());
310 if (Tok.
is(tok::kw_asm)) {
313 PP.
Diag(AsmLoc, diag::err_asm_empty);
322 bool SpellingInvalid =
false;
323 Asm += PP.
getSpelling(Tok, SpellingBuffer, &SpellingInvalid);
324 assert(!SpellingInvalid &&
"spelling was invalid after correct parse?");
327 isNewStatement =
false;
334 assert(TokOffsets.size() == AsmToks.size());
342 default:
return false;
345 case tok::kw_volatile:
346 case tok::kw_restrict:
347 case tok::kw___private:
348 case tok::kw___local:
349 case tok::kw___global:
350 case tok::kw___constant:
351 case tok::kw___generic:
352 case tok::kw___read_only:
353 case tok::kw___read_write:
354 case tok::kw___write_only:
361 return TokAfterAsm.
is(tok::l_paren) || TokAfterAsm.
is(tok::kw_goto) ||
385 bool SingleLineMode =
true;
386 unsigned BraceNesting = 0;
387 unsigned short savedBraceCount = BraceCount;
388 bool InAsmComment =
false;
391 unsigned NumTokensRead = 0;
393 bool SkippedStartOfLine =
false;
395 if (Tok.
is(tok::l_brace)) {
397 SingleLineMode =
false;
399 EndLoc = ConsumeBrace();
400 LBraceLocs.push_back(EndLoc);
404 std::pair<FileID, unsigned> ExpAsmLoc =
406 FID = ExpAsmLoc.first;
417 if (!InAsmComment && Tok.
is(tok::l_brace)) {
420 AsmToks.push_back(Tok);
421 EndLoc = ConsumeBrace();
423 LBraceLocs.push_back(EndLoc);
427 }
else if (!InAsmComment && Tok.
is(tok::semi)) {
430 if (!SingleLineMode) {
432 std::pair<FileID, unsigned> ExpSemiLoc =
434 FID = ExpSemiLoc.first;
437 }
else if (SingleLineMode || InAsmComment) {
440 std::pair<FileID, unsigned> ExpLoc =
442 if (ExpLoc.first != FID ||
443 SrcMgr.
getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) {
448 bool isAsm = Tok.
is(tok::kw_asm);
452 InAsmComment =
false;
461 }
else if (!InAsmComment && Tok.
is(tok::r_brace)) {
469 if (!InAsmComment && BraceNesting && Tok.
is(tok::r_brace) &&
470 BraceCount == (savedBraceCount + BraceNesting)) {
474 if (SingleLineMode || BraceNesting > 1) {
476 AsmToks.push_back(Tok);
478 EndLoc = ConsumeBrace();
482 if (BraceNesting == 0 && !SingleLineMode)
485 LBraceLocs.pop_back();
500 if (SkippedStartOfLine)
502 AsmToks.push_back(Tok);
507 SkippedStartOfLine =
false;
510 if (BraceNesting && BraceCount != savedBraceCount) {
512 for (
unsigned i = 0; i < BraceNesting; ++i) {
513 Diag(Tok, diag::err_expected) << tok::r_brace;
514 Diag(LBraceLocs.back(), diag::note_matching) << tok::l_brace;
515 LBraceLocs.pop_back();
518 }
else if (NumTokensRead == 0) {
520 Diag(Tok, diag::err_expected) << tok::l_brace;
531 llvm::Triple::ArchType ArchTy = TheTriple.getArch();
532 const std::string &TT = TheTriple.getTriple();
533 const llvm::Target *TheTarget =
nullptr;
534 bool UnsupportedArch =
535 (ArchTy != llvm::Triple::x86 && ArchTy != llvm::Triple::x86_64);
536 if (UnsupportedArch) {
537 Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName();
540 TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error);
542 Diag(AsmLoc, diag::err_msasm_unable_to_create_target) << Error;
545 assert(!LBraceLocs.empty() &&
"Should have at least one location here");
549 if (!TheTarget || AsmToks.empty()) {
550 return Actions.
ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, StringRef(),
552 ConstraintRefs, ClobberRefs, Exprs, EndLoc);
562 std::string FeaturesStr =
565 std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
566 std::unique_ptr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT));
568 std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo());
569 std::unique_ptr<llvm::MCObjectFileInfo> MOFI(
new llvm::MCObjectFileInfo());
570 std::unique_ptr<llvm::MCSubtargetInfo> STI(
571 TheTarget->createMCSubtargetInfo(TT, TO.
CPU, FeaturesStr));
573 llvm::SourceMgr TempSrcMgr;
574 llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr);
575 MOFI->InitMCObjectFileInfo(TheTriple,
false, llvm::CodeModel::Default,
577 std::unique_ptr<llvm::MemoryBuffer>
Buffer =
578 llvm::MemoryBuffer::getMemBuffer(AsmString,
"<MS inline asm>");
581 TempSrcMgr.AddNewSourceBuffer(std::move(Buffer), llvm::SMLoc());
583 std::unique_ptr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
584 std::unique_ptr<llvm::MCAsmParser>
Parser(
585 createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI));
588 llvm::MCTargetOptions MCOptions;
589 std::unique_ptr<llvm::MCTargetAsmParser> TargetParser(
590 TheTarget->createMCAsmParser(*STI, *
Parser, *MII, MCOptions));
592 std::unique_ptr<llvm::MCInstPrinter> IP(
593 TheTarget->createMCInstPrinter(llvm::Triple(TT), 1, *MAI, *MII, *MRI));
596 Parser->setAssemblerDialect(1);
597 Parser->setTargetParser(*TargetParser.get());
598 Parser->setParsingInlineAsm(
true);
599 TargetParser->setParsingInlineAsm(
true);
601 ClangAsmParserCallback
Callback(*
this, AsmLoc, AsmString, AsmToks,
603 TargetParser->setSemaCallback(&
Callback);
604 TempSrcMgr.setDiagHandler(ClangAsmParserCallback::DiagHandlerCallback,
609 std::string AsmStringIR;
614 NumInputs, OpExprs, Constraints, Clobbers,
620 auto End = std::remove(Clobbers.begin(), Clobbers.end(),
"fpsw");
621 Clobbers.erase(
End, Clobbers.end());
624 ClobberRefs.insert(ClobberRefs.end(), Clobbers.begin(), Clobbers.end());
627 unsigned NumExprs = NumOutputs + NumInputs;
628 ConstraintRefs.resize(NumExprs);
629 Exprs.resize(NumExprs);
630 for (
unsigned i = 0, e = NumExprs; i != e; ++i) {
631 Expr *OpExpr =
static_cast<Expr *
>(OpExprs[i].first);
636 if (OpExprs[i].second)
640 ConstraintRefs[i] = StringRef(Constraints[i]);
645 return Actions.
ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, AsmStringIR,
646 NumOutputs, NumInputs, ConstraintRefs,
647 ClobberRefs, Exprs, EndLoc);
669 StmtResult Parser::ParseAsmStatement(
bool &msAsm) {
670 assert(Tok.
is(tok::kw_asm) &&
"Not an asm stmt");
675 return ParseMicrosoftAsmStatement(AsmLoc);
680 ParseTypeQualifierListOpt(DS, AR_VendorAttributesParsed);
684 Diag(Loc, diag::w_asm_qualifier_ignored) <<
"const";
686 Diag(Loc, diag::w_asm_qualifier_ignored) <<
"restrict";
689 Diag(Loc, diag::w_asm_qualifier_ignored) <<
"_Atomic";
695 if (Tok.
is(tok::kw_goto)) {
696 Diag(Tok, diag::err_asm_goto_not_supported_yet);
701 if (Tok.
isNot(tok::l_paren)) {
702 Diag(Tok, diag::err_expected_lparen_after) <<
"asm";
709 ExprResult AsmString(ParseAsmStringLiteral());
713 if (!(
getLangOpts().GNUAsm || AsmString.isInvalid())) {
714 const auto *SL = cast<StringLiteral>(AsmString.get());
715 if (!SL->getString().trim().empty())
716 Diag(Loc, diag::err_gnu_inline_asm_disabled);
719 if (AsmString.isInvalid()) {
726 ExprVector Constraints;
730 if (Tok.
is(tok::r_paren)) {
735 Constraints, Exprs, AsmString.get(),
736 Clobbers, T.getCloseLocation());
740 bool AteExtraColon =
false;
741 if (Tok.
is(tok::colon) || Tok.
is(tok::coloncolon)) {
743 AteExtraColon = Tok.
is(tok::coloncolon);
746 if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
750 unsigned NumOutputs = Names.size();
753 if (AteExtraColon || Tok.
is(tok::colon) || Tok.
is(tok::coloncolon)) {
756 AteExtraColon =
false;
758 AteExtraColon = Tok.
is(tok::coloncolon);
762 if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
766 assert(Names.size() == Constraints.size() &&
767 Constraints.size() == Exprs.size() &&
"Input operand size mismatch!");
769 unsigned NumInputs = Names.size() - NumOutputs;
772 if (AteExtraColon || Tok.
is(tok::colon)) {
777 if (Tok.
isNot(tok::r_paren)) {
781 if (Clobber.isInvalid())
784 Clobbers.push_back(Clobber.get());
794 AsmLoc,
false, isVolatile, NumOutputs, NumInputs, Names.data(),
795 Constraints, Exprs, AsmString.get(), Clobbers, T.getCloseLocation());
815 if (!isTokenStringLiteral() && Tok.
isNot(tok::l_square))
820 if (Tok.
is(tok::l_square)) {
824 if (Tok.
isNot(tok::identifier)) {
825 Diag(Tok, diag::err_expected) << tok::identifier;
836 Names.push_back(
nullptr);
838 ExprResult Constraint(ParseAsmStringLiteral());
839 if (Constraint.isInvalid()) {
843 Constraints.push_back(Constraint.get());
845 if (Tok.
isNot(tok::l_paren)) {
846 Diag(Tok, diag::err_expected_lparen_after) <<
"asm operand";
860 Exprs.push_back(Res.
get());
bool isAtStartOfLine() const
isAtStartOfLine - Return true if this token is at the start of a line.
SourceManager & getSourceManager() const
Defines the clang::ASTContext interface.
ExprResult ParseExpression(TypeCastState isTypeCast=NotTypeCast)
Simple precedence-based parser for binary/ternary operators.
std::pair< FileID, unsigned > getDecomposedExpansionLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
StringRef getMSAsmLabel() const
const LangOptions & getLangOpts() const
const Token & LookAhead(unsigned N)
Peeks ahead N tokens and returns that token without consuming any tokens.
StmtResult ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, MultiExprArg Constraints, MultiExprArg Exprs, Expr *AsmString, MultiExprArg Clobbers, SourceLocation RParenLoc)
bool hasLeadingSpace() const
Return true if this token has whitespace before it.
std::unique_ptr< llvm::MemoryBuffer > Buffer
void setFlag(TokenFlags Flag)
Set the specified flag.
Parser - This implements a parser for the C family of languages.
Options for controlling the target.
ExprResult BuildUnaryOp(Scope *S, SourceLocation OpLoc, UnaryOperatorKind Opc, Expr *Input)
StringRef getSpelling(SourceLocation loc, SmallVectorImpl< char > &buffer, bool *invalid=nullptr) const
Return the 'spelling' of the token at the given location; does not go up to the spelling location or ...
bool SkipUntil(tok::TokenKind T, SkipUntilFlags Flags=static_cast< SkipUntilFlags >(0))
SkipUntil - Read tokens until we get to the specified token, then consume it (unless StopBeforeMatch ...
static bool isGCCAsmStatement(const Token &TokAfterAsm)
const Token & NextToken()
NextToken - This peeks ahead one token and returns it without consuming it.
bool TryConsumeToken(tok::TokenKind Expected)
One of these records is kept for each identifier that is lexed.
Token - This structure provides full information about a lexed token.
void setKind(tok::TokenKind K)
RAII class that helps handle the parsing of an open/close delimiter pair, such as braces { ...
Represents a C++ unqualified-id that has been parsed.
const TargetInfo & getTargetInfo() const
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
Represents a C++ nested-name-specifier or a global scope specifier.
tok::TokenKind getKind() const
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const
Forwarding function for diagnostics.
ExprResult LookupInlineAsmVarDeclField(Expr *RefExpr, StringRef Member, llvm::InlineAsmIdentifierInfo &Info, SourceLocation AsmLoc)
ExprResult LookupInlineAsmIdentifier(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, llvm::InlineAsmIdentifierInfo &Info, bool IsUnevaluatedContext)
Expr - This represents one expression.
StringRef getName() const
Return the actual identifier string.
MatchFinder::MatchCallback * Callback
static bool buildMSAsmString(Preprocessor &PP, SourceLocation AsmLoc, ArrayRef< Token > AsmToks, SmallVectorImpl< unsigned > &TokOffsets, SmallString< 512 > &Asm)
Turn a sequence of our tokens back into a string that we can hand to the MC asm parser.
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file. ...
bool isNot(tok::TokenKind K) const
The result type of a method or function.
std::string CPU
If given, the name of the target CPU to generate code for.
Stop skipping at semicolon.
ActionResult - This structure is used while parsing/acting on expressions, stmts, etc...
ExprResult ParseMSAsmIdentifier(llvm::SmallVectorImpl< Token > &LineToks, unsigned &NumLineToksConsumed, void *Info, bool IsUnevaluated)
Parse an identifier in an MS-style inline assembly block.
Encodes a location in the source.
static OMPLinearClause * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, OpenMPLinearClauseKind Modifier, SourceLocation ModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef< Expr * > VL, ArrayRef< Expr * > PL, ArrayRef< Expr * > IL, Expr *Step, Expr *CalcStep, Stmt *PreInit, Expr *PostUpdate)
Creates clause with a list of variables VL and a linear step Step.
Parser(Preprocessor &PP, Sema &Actions, bool SkipFunctionBodies)
LabelDecl - Represents the declaration of a label.
Scope * getCurScope() const
void Lex(Token &Result)
Lex the next token for this preprocessor.
std::vector< std::string > Features
The list of target specific features to enable or disable – this should be a list of strings starting...
TokenKind
Provides a simple uniform namespace for tokens from all C languages.
bool is(tok::TokenKind K) const
is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {...
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, bool AllowDestructorName, bool AllowConstructorName, ParsedType ObjectType, SourceLocation &TemplateKWLoc, UnqualifiedId &Result)
Parse a C++ unqualified-id (or a C identifier), which describes the name of an entity.
static bool isTypeQualifier(const Token &Tok)
isTypeQualifier - Return true if the current token could be the start of a type-qualifier-list.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid=nullptr) const
Given a SourceLocation, return the spelling line number for the position indicated.
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Defines the Diagnostic-related interfaces.
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
TargetOptions & getTargetOpts() const
Retrieve the target options.
ActionResult< Stmt * > StmtResult
Captures information about "declaration specifiers".
SourceLocation ConsumeToken()
ConsumeToken - Consume the current 'peek token' and lex the next one.
ExprResult CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl=nullptr, llvm::function_ref< ExprResult(Expr *)> Filter=[](Expr *E) -> ExprResult{return E;})
Process any TypoExprs in the given Expr and its children, generating diagnostics as appropriate and r...
Defines the clang::TargetInfo interface.
StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, ArrayRef< Token > AsmToks, StringRef AsmString, unsigned NumOutputs, unsigned NumInputs, ArrayRef< StringRef > Constraints, ArrayRef< StringRef > Clobbers, ArrayRef< Expr * > Exprs, SourceLocation EndLoc)
void clearFlag(TokenFlags Flag)
Unset the specified flag.
This class handles loading and caching of source files into memory.
void startToken()
Reset all flags to cleared.
void * getPtrEncoding() const
When a SourceLocation itself cannot be used, this returns an (opaque) pointer encoding for it...
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
IdentifierInfo * getIdentifierInfo() const