nsresult txExprParser::createLocationStep(txExprLexer& lexer, txIParseContext* aContext, Expr** aExpr) { *aExpr = nullptr; //-- child axis is default LocationStep::LocationStepType axisIdentifier = LocationStep::CHILD_AXIS; nsAutoPtr<txNodeTest> nodeTest; //-- get Axis Identifier or AbbreviatedStep, if present Token* tok = lexer.peek(); switch (tok->mType) { case Token::AXIS_IDENTIFIER: { //-- eat token lexer.nextToken(); nsCOMPtr<nsIAtom> axis = do_GetAtom(tok->Value()); if (axis == nsGkAtoms::ancestor) { axisIdentifier = LocationStep::ANCESTOR_AXIS; } else if (axis == nsGkAtoms::ancestorOrSelf) { axisIdentifier = LocationStep::ANCESTOR_OR_SELF_AXIS; } else if (axis == nsGkAtoms::attribute) { axisIdentifier = LocationStep::ATTRIBUTE_AXIS; } else if (axis == nsGkAtoms::child) { axisIdentifier = LocationStep::CHILD_AXIS; } else if (axis == nsGkAtoms::descendant) { axisIdentifier = LocationStep::DESCENDANT_AXIS; } else if (axis == nsGkAtoms::descendantOrSelf) { axisIdentifier = LocationStep::DESCENDANT_OR_SELF_AXIS; } else if (axis == nsGkAtoms::following) { axisIdentifier = LocationStep::FOLLOWING_AXIS; } else if (axis == nsGkAtoms::followingSibling) { axisIdentifier = LocationStep::FOLLOWING_SIBLING_AXIS; } else if (axis == nsGkAtoms::_namespace) { axisIdentifier = LocationStep::NAMESPACE_AXIS; } else if (axis == nsGkAtoms::parent) { axisIdentifier = LocationStep::PARENT_AXIS; } else if (axis == nsGkAtoms::preceding) { axisIdentifier = LocationStep::PRECEDING_AXIS; } else if (axis == nsGkAtoms::precedingSibling) { axisIdentifier = LocationStep::PRECEDING_SIBLING_AXIS; } else if (axis == nsGkAtoms::self) { axisIdentifier = LocationStep::SELF_AXIS; } else { return NS_ERROR_XPATH_INVALID_AXIS; } break; } case Token::AT_SIGN: //-- eat token lexer.nextToken(); axisIdentifier = LocationStep::ATTRIBUTE_AXIS; break; case Token::PARENT_NODE : //-- eat token lexer.nextToken(); axisIdentifier = LocationStep::PARENT_AXIS; nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE); break; case Token::SELF_NODE : //-- eat token lexer.nextToken(); axisIdentifier = LocationStep::SELF_AXIS; nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE); break; default: break; } //-- get NodeTest unless an AbbreviatedStep was found nsresult rv = NS_OK; if (!nodeTest) { tok = lexer.peek(); if (tok->mType == Token::CNAME) { lexer.nextToken(); // resolve QName nsCOMPtr<nsIAtom> prefix, lName; PRInt32 nspace; rv = resolveQName(tok->Value(), getter_AddRefs(prefix), aContext, getter_AddRefs(lName), nspace, true); NS_ENSURE_SUCCESS(rv, rv); nodeTest = new txNameTest(prefix, lName, nspace, axisIdentifier == LocationStep::ATTRIBUTE_AXIS ? static_cast<PRUint16>(txXPathNodeType::ATTRIBUTE_NODE) : static_cast<PRUint16>(txXPathNodeType::ELEMENT_NODE)); } else { rv = createNodeTypeTest(lexer, getter_Transfers(nodeTest)); NS_ENSURE_SUCCESS(rv, rv); } } nsAutoPtr<LocationStep> lstep(new LocationStep(nodeTest, axisIdentifier)); nodeTest.forget(); //-- handle predicates rv = parsePredicates(lstep, lexer, aContext); NS_ENSURE_SUCCESS(rv, rv); *aExpr = lstep.forget(); return NS_OK; }
void Preprocessor::HandlePragmaIncludeAlias(Token &Tok) { // We will either get a quoted filename or a bracketed filename, and we // have to track which we got. The first filename is the source name, // and the second name is the mapped filename. If the first is quoted, // the second must be as well (cannot mix and match quotes and brackets). // Get the open paren Lex(Tok); if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::warn_pragma_include_alias_expected) << "("; return; } // We expect either a quoted string literal, or a bracketed name Token SourceFilenameTok; CurPPLexer->LexIncludeFilename(SourceFilenameTok); if (SourceFilenameTok.is(tok::eod)) { // The diagnostic has already been handled return; } StringRef SourceFileName; SmallString<128> FileNameBuffer; if (SourceFilenameTok.is(tok::string_literal) || SourceFilenameTok.is(tok::angle_string_literal)) { SourceFileName = getSpelling(SourceFilenameTok, FileNameBuffer); } else if (SourceFilenameTok.is(tok::less)) { // This could be a path instead of just a name FileNameBuffer.push_back('<'); SourceLocation End; if (ConcatenateIncludeName(FileNameBuffer, End)) return; // Diagnostic already emitted SourceFileName = FileNameBuffer.str(); } else { Diag(Tok, diag::warn_pragma_include_alias_expected_filename); return; } FileNameBuffer.clear(); // Now we expect a comma, followed by another include name Lex(Tok); if (Tok.isNot(tok::comma)) { Diag(Tok, diag::warn_pragma_include_alias_expected) << ","; return; } Token ReplaceFilenameTok; CurPPLexer->LexIncludeFilename(ReplaceFilenameTok); if (ReplaceFilenameTok.is(tok::eod)) { // The diagnostic has already been handled return; } StringRef ReplaceFileName; if (ReplaceFilenameTok.is(tok::string_literal) || ReplaceFilenameTok.is(tok::angle_string_literal)) { ReplaceFileName = getSpelling(ReplaceFilenameTok, FileNameBuffer); } else if (ReplaceFilenameTok.is(tok::less)) { // This could be a path instead of just a name FileNameBuffer.push_back('<'); SourceLocation End; if (ConcatenateIncludeName(FileNameBuffer, End)) return; // Diagnostic already emitted ReplaceFileName = FileNameBuffer.str(); } else { Diag(Tok, diag::warn_pragma_include_alias_expected_filename); return; } // Finally, we expect the closing paren Lex(Tok); if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::warn_pragma_include_alias_expected) << ")"; return; } // Now that we have the source and target filenames, we need to make sure // they're both of the same type (angled vs non-angled) StringRef OriginalSource = SourceFileName; bool SourceIsAngled = GetIncludeFilenameSpelling(SourceFilenameTok.getLocation(), SourceFileName); bool ReplaceIsAngled = GetIncludeFilenameSpelling(ReplaceFilenameTok.getLocation(), ReplaceFileName); if (!SourceFileName.empty() && !ReplaceFileName.empty() && (SourceIsAngled != ReplaceIsAngled)) { unsigned int DiagID; if (SourceIsAngled) DiagID = diag::warn_pragma_include_alias_mismatch_angle; else DiagID = diag::warn_pragma_include_alias_mismatch_quote; Diag(SourceFilenameTok.getLocation(), DiagID) << SourceFileName << ReplaceFileName; return; } // Now we can let the include handler know about this mapping getHeaderSearchInfo().AddIncludeAlias(OriginalSource, ReplaceFileName); }
void StereotypeDefinitionParser::parseIconCommands(StereotypeIcon *stereotypeIcon) { Token token; bool loop = true; IconShape iconShape; QList<ShapeValueF> parameters; typedef QList<IconCommandParameter> Parameters; static const IconCommandParameter SCALED(ShapeValueF::UnitScaled); static const IconCommandParameter FIX(ShapeValueF::UnitRelative); static const IconCommandParameter ABSOLUTE(ShapeValueF::UnitAbsolute); while (loop) { token = readNextToken(); if (token.type() != Token::TokenKeyword) { loop = false; } else { switch (token.subtype()) { case KEYWORD_CIRCLE: parameters = parseIconCommandParameters(Parameters() << SCALED << SCALED << SCALED); iconShape.addCircle(ShapePointF(parameters.at(0), parameters.at(1)), parameters.at(2)); expectSemicolonOrEndOfLine(); break; case KEYWORD_ELLIPSE: parameters = parseIconCommandParameters(Parameters() << SCALED << SCALED << SCALED << SCALED); iconShape.addEllipse(ShapePointF(parameters.at(0), parameters.at(1)), ShapeSizeF(parameters.at(2), parameters.at(3))); expectSemicolonOrEndOfLine(); break; case KEYWORD_LINE: parameters = parseIconCommandParameters(Parameters() << SCALED << SCALED << SCALED << SCALED); iconShape.addLine(ShapePointF(parameters.at(0), parameters.at(1)), ShapePointF(parameters.at(2), parameters.at(3))); expectSemicolonOrEndOfLine(); break; case KEYWORD_RECT: parameters = parseIconCommandParameters(Parameters() << SCALED << SCALED << SCALED << SCALED); iconShape.addRect(ShapePointF(parameters.at(0), parameters.at(1)), ShapeSizeF(parameters.at(2), parameters.at(3))); expectSemicolonOrEndOfLine(); break; case KEYWORD_ROUNDEDRECT: parameters = parseIconCommandParameters(Parameters() << SCALED << SCALED << SCALED << SCALED << FIX); iconShape.addRoundedRect(ShapePointF(parameters.at(0), parameters.at(1)), ShapeSizeF(parameters.at(2), parameters.at(3)), parameters.at(4)); expectSemicolonOrEndOfLine(); break; case KEYWORD_ARC: { parameters = parseIconCommandParameters( Parameters() << SCALED << SCALED << SCALED << SCALED << ABSOLUTE << ABSOLUTE); qreal startAngle = expectAbsoluteValue(parameters.at(4), d->m_scanner->sourcePos()); qreal spanAngle = expectAbsoluteValue(parameters.at(5), d->m_scanner->sourcePos()); iconShape.addArc(ShapePointF(parameters.at(0), parameters.at(1)), ShapeSizeF(parameters.at(2), parameters.at(3)), startAngle, spanAngle); expectSemicolonOrEndOfLine(); break; } case KEYWORD_MOVETO: parameters = parseIconCommandParameters(Parameters() << SCALED << SCALED); iconShape.moveTo(ShapePointF(parameters.at(0), parameters.at(1))); expectSemicolonOrEndOfLine(); break; case KEYWORD_LINETO: parameters = parseIconCommandParameters(Parameters() << SCALED << SCALED); iconShape.lineTo(ShapePointF(parameters.at(0), parameters.at(1))); expectSemicolonOrEndOfLine(); break; case KEYWORD_ARCMOVETO: { parameters = parseIconCommandParameters( Parameters() << SCALED << SCALED << SCALED << SCALED << ABSOLUTE); qreal angle = expectAbsoluteValue(parameters.at(4), d->m_scanner->sourcePos()); iconShape.arcMoveTo(ShapePointF(parameters.at(0), parameters.at(1)), ShapeSizeF(parameters.at(2), parameters.at(3)), angle); expectSemicolonOrEndOfLine(); break; } case KEYWORD_ARCTO: { parameters = parseIconCommandParameters( Parameters() << SCALED << SCALED << SCALED << SCALED << ABSOLUTE << ABSOLUTE); qreal startAngle = expectAbsoluteValue(parameters.at(4), d->m_scanner->sourcePos()); qreal sweepLength = expectAbsoluteValue(parameters.at(5), d->m_scanner->sourcePos()); iconShape.arcTo(ShapePointF(parameters.at(0), parameters.at(1)), ShapeSizeF(parameters.at(2), parameters.at(3)), startAngle, sweepLength); expectSemicolonOrEndOfLine(); break; } case KEYWORD_CLOSE: iconShape.closePath(); expectSemicolonOrEndOfLine(); break; default: loop = false; break; } } } stereotypeIcon->setIconShape(iconShape); d->m_scanner->unread(token); }
// --------------------------------------------------------------------------- // Token: Helper mthods // --------------------------------------------------------------------------- int Token::analyzeFirstCharacter(RangeToken* const rangeTok, const int options, TokenFactory* const tokFactory) { switch(fTokenType) { case T_CONCAT: { int ret = FC_CONTINUE; for (int i=0; i<size(); i++) { Token* tok = getChild(i); if (tok && (ret=tok->analyzeFirstCharacter(rangeTok, options, tokFactory))!= FC_CONTINUE) break; } return ret; } case T_UNION: { unsigned int childSize = size(); if (childSize == 0) return FC_CONTINUE; int ret = FC_CONTINUE; bool hasEmpty = false; for (unsigned int i=0; i < childSize; i++) { ret = getChild(i)->analyzeFirstCharacter(rangeTok, options, tokFactory); if (ret == FC_ANY) break; else hasEmpty = true; } return hasEmpty ? FC_CONTINUE : ret; } case T_CONDITION: { int ret1 = getChild(0)->analyzeFirstCharacter(rangeTok, options, tokFactory); if (size() == 1) return FC_CONTINUE; int ret2; if (ret1 != FC_ANY) { ret2 = getChild(1)->analyzeFirstCharacter(rangeTok, options, tokFactory); } if (ret1 == FC_ANY || ret2 == FC_ANY) return FC_ANY; if (ret1 == FC_CONTINUE || ret2 == FC_CONTINUE) return FC_CONTINUE; return FC_TERMINAL; } case T_CLOSURE: case T_NONGREEDYCLOSURE: { Token* tok = getChild(0); if (tok) tok->analyzeFirstCharacter(rangeTok, options, tokFactory); return FC_CONTINUE; } case T_DOT: return FC_ANY; case T_EMPTY: case T_ANCHOR: return FC_CONTINUE; case T_CHAR: { XMLInt32 ch = getChar(); rangeTok->addRange(ch, ch); if (ch < 0x1000 && isSet(options,RegularExpression::IGNORE_CASE)) { //REVISIT } } return FC_TERMINAL; case T_RANGE: { if (isSet(options, RegularExpression::IGNORE_CASE)) { rangeTok->mergeRanges(((RangeToken*) this)->getCaseInsensitiveToken(tokFactory)); } else { rangeTok->mergeRanges(this); } return FC_TERMINAL; } case T_NRANGE: { if (isSet(options, RegularExpression::IGNORE_CASE)) { RangeToken* caseITok = (((RangeToken*) this)->getCaseInsensitiveToken(tokFactory)); rangeTok->mergeRanges(RangeToken::complementRanges(caseITok, tokFactory, fMemoryManager)); } else { rangeTok->mergeRanges( RangeToken::complementRanges((RangeToken*) this, tokFactory, fMemoryManager)); } } case T_INDEPENDENT: case T_PAREN: { Token* tok = getChild(0); if (tok) return tok->analyzeFirstCharacter(rangeTok,options, tokFactory); } case T_MODIFIERGROUP: case T_BACKREFERENCE: rangeTok->addRange(0, UTF16_MAX); return FC_ANY; case T_STRING: { const XMLCh* str = getString(); XMLInt32 ch = str[0]; if (RegxUtil::isHighSurrogate((XMLCh) ch)) { } rangeTok->addRange(ch, ch); if (ch<0x10000 && isSet(options,RegularExpression::IGNORE_CASE)) { //REVISIT } } return FC_TERMINAL; case T_LOOKAHEAD: case T_NEGATIVELOOKAHEAD: case T_LOOKBEHIND: case T_NEGATIVELOOKBEHIND: return FC_CONTINUE; // default: // throw; } return 0; }
/// Lex a token following the 'import' contextual keyword. /// void Preprocessor::LexAfterModuleImport(Token &Result) { // Figure out what kind of lexer we actually have. recomputeCurLexerKind(); // Lex the next token. Lex(Result); // The token sequence // // import identifier (. identifier)* // // indicates a module import directive. We already saw the 'import' // contextual keyword, so now we're looking for the identifiers. if (ModuleImportExpectsIdentifier && Result.getKind() == tok::identifier) { // We expected to see an identifier here, and we did; continue handling // identifiers. ModuleImportPath.push_back(std::make_pair(Result.getIdentifierInfo(), Result.getLocation())); ModuleImportExpectsIdentifier = false; CurLexerKind = CLK_LexAfterModuleImport; return; } // If we're expecting a '.' or a ';', and we got a '.', then wait until we // see the next identifier. (We can also see a '[[' that begins an // attribute-specifier-seq here under the C++ Modules TS.) if (!ModuleImportExpectsIdentifier && Result.getKind() == tok::period) { ModuleImportExpectsIdentifier = true; CurLexerKind = CLK_LexAfterModuleImport; return; } // If we have a non-empty module path, load the named module. if (!ModuleImportPath.empty()) { // Under the Modules TS, the dot is just part of the module name, and not // a real hierarchy separator. Flatten such module names now. // // FIXME: Is this the right level to be performing this transformation? std::string FlatModuleName; if (getLangOpts().ModulesTS) { for (auto &Piece : ModuleImportPath) { if (!FlatModuleName.empty()) FlatModuleName += "."; FlatModuleName += Piece.first->getName(); } SourceLocation FirstPathLoc = ModuleImportPath[0].second; ModuleImportPath.clear(); ModuleImportPath.push_back( std::make_pair(getIdentifierInfo(FlatModuleName), FirstPathLoc)); } Module *Imported = nullptr; if (getLangOpts().Modules) { Imported = TheModuleLoader.loadModule(ModuleImportLoc, ModuleImportPath, Module::Hidden, /*IsIncludeDirective=*/false); if (Imported) makeModuleVisible(Imported, ModuleImportLoc); } if (Callbacks && (getLangOpts().Modules || getLangOpts().DebuggerSupport)) Callbacks->moduleImport(ModuleImportLoc, ModuleImportPath, Imported); } }
/// EvaluateHasIncludeCommon - Process a '__has_include("path")' /// or '__has_include_next("path")' expression. /// Returns true if successful. static bool EvaluateHasIncludeCommon(Token &Tok, IdentifierInfo *II, Preprocessor &PP, const DirectoryLookup *LookupFrom) { SourceLocation LParenLoc; // Get '('. PP.LexNonComment(Tok); // Ensure we have a '('. if (Tok.isNot(tok::l_paren)) { PP.Diag(Tok.getLocation(), diag::err_pp_missing_lparen) << II->getName(); return false; } // Save '(' location for possible missing ')' message. LParenLoc = Tok.getLocation(); // Get the file name. PP.getCurrentLexer()->LexIncludeFilename(Tok); // Reserve a buffer to get the spelling. SmallString<128> FilenameBuffer; StringRef Filename; SourceLocation EndLoc; switch (Tok.getKind()) { case tok::eod: // If the token kind is EOD, the error has already been diagnosed. return false; case tok::angle_string_literal: case tok::string_literal: { bool Invalid = false; Filename = PP.getSpelling(Tok, FilenameBuffer, &Invalid); if (Invalid) return false; break; } case tok::less: // This could be a <foo/bar.h> file coming from a macro expansion. In this // case, glue the tokens together into FilenameBuffer and interpret those. FilenameBuffer.push_back('<'); if (PP.ConcatenateIncludeName(FilenameBuffer, EndLoc)) return false; // Found <eod> but no ">"? Diagnostic already emitted. Filename = FilenameBuffer.str(); break; default: PP.Diag(Tok.getLocation(), diag::err_pp_expects_filename); return false; } // Get ')'. PP.LexNonComment(Tok); // Ensure we have a trailing ). if (Tok.isNot(tok::r_paren)) { PP.Diag(Tok.getLocation(), diag::err_pp_missing_rparen) << II->getName(); PP.Diag(LParenLoc, diag::note_matching) << "("; return false; } bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename); // If GetIncludeFilenameSpelling set the start ptr to null, there was an // error. if (Filename.empty()) return false; // Search include directories. const DirectoryLookup *CurDir; const FileEntry *File = PP.LookupFile(Filename, isAngled, LookupFrom, CurDir, NULL, NULL, NULL); // Get the result value. A result of true means the file exists. return File != 0; }
void MetaLexer::LexEndOfFile(char C, Token& Tok) { if (C == '\0') { Tok.setKind(tok::eof); Tok.setLength(1); } }
/// EvaluateDirectiveSubExpr - Evaluate the subexpression whose first token is /// PeekTok, and whose precedence is PeekPrec. This returns the result in LHS. /// /// If ValueLive is false, then this value is being evaluated in a context where /// the result is not used. As such, avoid diagnostics that relate to /// evaluation, such as division by zero warnings. static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec, Token &PeekTok, bool ValueLive, Preprocessor &PP) { unsigned PeekPrec = getPrecedence(PeekTok.getKind()); // If this token isn't valid, report the error. if (PeekPrec == ~0U) { PP.Diag(PeekTok.getLocation(), diag::err_pp_expr_bad_token_binop) << LHS.getRange(); return true; } while (1) { // If this token has a lower precedence than we are allowed to parse, return // it so that higher levels of the recursion can parse it. if (PeekPrec < MinPrec) return false; tok::TokenKind Operator = PeekTok.getKind(); // If this is a short-circuiting operator, see if the RHS of the operator is // dead. Note that this cannot just clobber ValueLive. Consider // "0 && 1 ? 4 : 1 / 0", which is parsed as "(0 && 1) ? 4 : (1 / 0)". In // this example, the RHS of the && being dead does not make the rest of the // expr dead. bool RHSIsLive; if (Operator == tok::ampamp && LHS.Val == 0) RHSIsLive = false; // RHS of "0 && x" is dead. else if (Operator == tok::pipepipe && LHS.Val != 0) RHSIsLive = false; // RHS of "1 || x" is dead. else if (Operator == tok::question && LHS.Val == 0) RHSIsLive = false; // RHS (x) of "0 ? x : y" is dead. else RHSIsLive = ValueLive; // Consume the operator, remembering the operator's location for reporting. SourceLocation OpLoc = PeekTok.getLocation(); PP.LexNonComment(PeekTok); PPValue RHS(LHS.getBitWidth()); // Parse the RHS of the operator. DefinedTracker DT; if (EvaluateValue(RHS, PeekTok, DT, RHSIsLive, PP)) return true; // Remember the precedence of this operator and get the precedence of the // operator immediately to the right of the RHS. unsigned ThisPrec = PeekPrec; PeekPrec = getPrecedence(PeekTok.getKind()); // If this token isn't valid, report the error. if (PeekPrec == ~0U) { PP.Diag(PeekTok.getLocation(), diag::err_pp_expr_bad_token_binop) << RHS.getRange(); return true; } // Decide whether to include the next binop in this subexpression. For // example, when parsing x+y*z and looking at '*', we want to recursively // handle y*z as a single subexpression. We do this because the precedence // of * is higher than that of +. The only strange case we have to handle // here is for the ?: operator, where the precedence is actually lower than // the LHS of the '?'. The grammar rule is: // // conditional-expression ::= // logical-OR-expression ? expression : conditional-expression // where 'expression' is actually comma-expression. unsigned RHSPrec; if (Operator == tok::question) // The RHS of "?" should be maximally consumed as an expression. RHSPrec = getPrecedence(tok::comma); else // All others should munch while higher precedence. RHSPrec = ThisPrec+1; if (PeekPrec >= RHSPrec) { if (EvaluateDirectiveSubExpr(RHS, RHSPrec, PeekTok, RHSIsLive, PP)) return true; PeekPrec = getPrecedence(PeekTok.getKind()); } assert(PeekPrec <= ThisPrec && "Recursion didn't work!"); // Usual arithmetic conversions (C99 6.3.1.8p1): result is unsigned if // either operand is unsigned. llvm::APSInt Res(LHS.getBitWidth()); switch (Operator) { case tok::question: // No UAC for x and y in "x ? y : z". case tok::lessless: // Shift amount doesn't UAC with shift value. case tok::greatergreater: // Shift amount doesn't UAC with shift value. case tok::comma: // Comma operands are not subject to UACs. case tok::pipepipe: // Logical || does not do UACs. case tok::ampamp: // Logical && does not do UACs. break; // No UAC default: Res.setIsUnsigned(LHS.isUnsigned()|RHS.isUnsigned()); // If this just promoted something from signed to unsigned, and if the // value was negative, warn about it. if (ValueLive && Res.isUnsigned()) { if (!LHS.isUnsigned() && LHS.Val.isNegative()) PP.Diag(OpLoc, diag::warn_pp_convert_lhs_to_positive) << LHS.Val.toString(10, true) + " to " + LHS.Val.toString(10, false) << LHS.getRange() << RHS.getRange(); if (!RHS.isUnsigned() && RHS.Val.isNegative()) PP.Diag(OpLoc, diag::warn_pp_convert_rhs_to_positive) << RHS.Val.toString(10, true) + " to " + RHS.Val.toString(10, false) << LHS.getRange() << RHS.getRange(); } LHS.Val.setIsUnsigned(Res.isUnsigned()); RHS.Val.setIsUnsigned(Res.isUnsigned()); } bool Overflow = false; switch (Operator) { default: llvm_unreachable("Unknown operator token!"); case tok::percent: if (RHS.Val != 0) Res = LHS.Val % RHS.Val; else if (ValueLive) { PP.Diag(OpLoc, diag::err_pp_remainder_by_zero) << LHS.getRange() << RHS.getRange(); return true; } break; case tok::slash: if (RHS.Val != 0) { if (LHS.Val.isSigned()) Res = llvm::APSInt(LHS.Val.sdiv_ov(RHS.Val, Overflow), false); else Res = LHS.Val / RHS.Val; } else if (ValueLive) { PP.Diag(OpLoc, diag::err_pp_division_by_zero) << LHS.getRange() << RHS.getRange(); return true; } break; case tok::star: if (Res.isSigned()) Res = llvm::APSInt(LHS.Val.smul_ov(RHS.Val, Overflow), false); else Res = LHS.Val * RHS.Val; break; case tok::lessless: { // Determine whether overflow is about to happen. unsigned ShAmt = static_cast<unsigned>(RHS.Val.getLimitedValue()); if (LHS.isUnsigned()) { Overflow = ShAmt >= LHS.Val.getBitWidth(); if (Overflow) ShAmt = LHS.Val.getBitWidth()-1; Res = LHS.Val << ShAmt; } else { Res = llvm::APSInt(LHS.Val.sshl_ov(ShAmt, Overflow), false); } break; } case tok::greatergreater: { // Determine whether overflow is about to happen. unsigned ShAmt = static_cast<unsigned>(RHS.Val.getLimitedValue()); if (ShAmt >= LHS.getBitWidth()) Overflow = true, ShAmt = LHS.getBitWidth()-1; Res = LHS.Val >> ShAmt; break; } case tok::plus: if (LHS.isUnsigned()) Res = LHS.Val + RHS.Val; else Res = llvm::APSInt(LHS.Val.sadd_ov(RHS.Val, Overflow), false); break; case tok::minus: if (LHS.isUnsigned()) Res = LHS.Val - RHS.Val; else Res = llvm::APSInt(LHS.Val.ssub_ov(RHS.Val, Overflow), false); break; case tok::lessequal: Res = LHS.Val <= RHS.Val; Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed) break; case tok::less: Res = LHS.Val < RHS.Val; Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed) break; case tok::greaterequal: Res = LHS.Val >= RHS.Val; Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed) break; case tok::greater: Res = LHS.Val > RHS.Val; Res.setIsUnsigned(false); // C99 6.5.8p6, result is always int (signed) break; case tok::exclaimequal: Res = LHS.Val != RHS.Val; Res.setIsUnsigned(false); // C99 6.5.9p3, result is always int (signed) break; case tok::equalequal: Res = LHS.Val == RHS.Val; Res.setIsUnsigned(false); // C99 6.5.9p3, result is always int (signed) break; case tok::amp: Res = LHS.Val & RHS.Val; break; case tok::caret: Res = LHS.Val ^ RHS.Val; break; case tok::pipe: Res = LHS.Val | RHS.Val; break; case tok::ampamp: Res = (LHS.Val != 0 && RHS.Val != 0); Res.setIsUnsigned(false); // C99 6.5.13p3, result is always int (signed) break; case tok::pipepipe: Res = (LHS.Val != 0 || RHS.Val != 0); Res.setIsUnsigned(false); // C99 6.5.14p3, result is always int (signed) break; case tok::comma: // Comma is invalid in pp expressions in c89/c++ mode, but is valid in C99 // if not being evaluated. if (!PP.getLangOpts().C99 || ValueLive) PP.Diag(OpLoc, diag::ext_pp_comma_expr) << LHS.getRange() << RHS.getRange(); Res = RHS.Val; // LHS = LHS,RHS -> RHS. break; case tok::question: { // Parse the : part of the expression. if (PeekTok.isNot(tok::colon)) { PP.Diag(PeekTok.getLocation(), diag::err_expected_colon) << LHS.getRange(), RHS.getRange(); PP.Diag(OpLoc, diag::note_matching) << "?"; return true; } // Consume the :. PP.LexNonComment(PeekTok); // Evaluate the value after the :. bool AfterColonLive = ValueLive && LHS.Val == 0; PPValue AfterColonVal(LHS.getBitWidth()); DefinedTracker DT; if (EvaluateValue(AfterColonVal, PeekTok, DT, AfterColonLive, PP)) return true; // Parse anything after the : with the same precedence as ?. We allow // things of equal precedence because ?: is right associative. if (EvaluateDirectiveSubExpr(AfterColonVal, ThisPrec, PeekTok, AfterColonLive, PP)) return true; // Now that we have the condition, the LHS and the RHS of the :, evaluate. Res = LHS.Val != 0 ? RHS.Val : AfterColonVal.Val; RHS.setEnd(AfterColonVal.getRange().getEnd()); // Usual arithmetic conversions (C99 6.3.1.8p1): result is unsigned if // either operand is unsigned. Res.setIsUnsigned(RHS.isUnsigned() | AfterColonVal.isUnsigned()); // Figure out the precedence of the token after the : part. PeekPrec = getPrecedence(PeekTok.getKind()); break; } case tok::colon: // Don't allow :'s to float around without being part of ?: exprs. PP.Diag(OpLoc, diag::err_pp_colon_without_question) << LHS.getRange() << RHS.getRange(); return true; } // If this operator is live and overflowed, report the issue. if (Overflow && ValueLive) PP.Diag(OpLoc, diag::warn_pp_expr_overflow) << LHS.getRange() << RHS.getRange(); // Put the result back into 'LHS' for our next iteration. LHS.Val = Res; LHS.setEnd(RHS.getRange().getEnd()); } }
/// EvaluateDirectiveExpression - Evaluate an integer constant expression that /// may occur after a #if or #elif directive. If the expression is equivalent /// to "!defined(X)" return X in IfNDefMacro. bool Preprocessor:: EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { // Save the current state of 'DisableMacroExpansion' and reset it to false. If // 'DisableMacroExpansion' is true, then we must be in a macro argument list // in which case a directive is undefined behavior. We want macros to be able // to recursively expand in order to get more gcc-list behavior, so we force // DisableMacroExpansion to false and restore it when we're done parsing the // expression. bool DisableMacroExpansionAtStartOfDirective = DisableMacroExpansion; DisableMacroExpansion = false; // Peek ahead one token. Token Tok; LexNonComment(Tok); // C99 6.10.1p3 - All expressions are evaluated as intmax_t or uintmax_t. unsigned BitWidth = getTargetInfo().getIntMaxTWidth(); PPValue ResVal(BitWidth); DefinedTracker DT; if (EvaluateValue(ResVal, Tok, DT, true, *this)) { // Parse error, skip the rest of the macro line. if (Tok.isNot(tok::eod)) DiscardUntilEndOfDirective(); // Restore 'DisableMacroExpansion'. DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective; return false; } // If we are at the end of the expression after just parsing a value, there // must be no (unparenthesized) binary operators involved, so we can exit // directly. if (Tok.is(tok::eod)) { // If the expression we parsed was of the form !defined(macro), return the // macro in IfNDefMacro. if (DT.State == DefinedTracker::NotDefinedMacro) IfNDefMacro = DT.TheMacro; // Restore 'DisableMacroExpansion'. DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective; return ResVal.Val != 0; } // Otherwise, we must have a binary operator (e.g. "#if 1 < 2"), so parse the // operator and the stuff after it. if (EvaluateDirectiveSubExpr(ResVal, getPrecedence(tok::question), Tok, true, *this)) { // Parse error, skip the rest of the macro line. if (Tok.isNot(tok::eod)) DiscardUntilEndOfDirective(); // Restore 'DisableMacroExpansion'. DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective; return false; } // If we aren't at the tok::eod token, something bad happened, like an extra // ')' token. if (Tok.isNot(tok::eod)) { Diag(Tok, diag::err_pp_expected_eol); DiscardUntilEndOfDirective(); } // Restore 'DisableMacroExpansion'. DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective; return ResVal.Val != 0; }
/// ExpandBuiltinMacro - If an identifier token is read that is to be expanded /// as a builtin macro, handle it and return the next token as 'Tok'. void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // Figure out which token this is. IdentifierInfo *II = Tok.getIdentifierInfo(); assert(II && "Can't be a macro without id info!"); // If this is an _Pragma or Microsoft __pragma directive, expand it, // invoke the pragma handler, then lex the token after it. if (II == Ident_Pragma) return Handle_Pragma(Tok); else if (II == Ident__pragma) // in non-MS mode this is null return HandleMicrosoft__pragma(Tok); ++NumBuiltinMacroExpanded; llvm::SmallString<128> TmpBuffer; llvm::raw_svector_ostream OS(TmpBuffer); // Set up the return result. Tok.setIdentifierInfo(0); Tok.clearFlag(Token::NeedsCleaning); if (II == Ident__LINE__) { // C99 6.10.8: "__LINE__: The presumed line number (within the current // source file) of the current source line (an integer constant)". This can // be affected by #line. SourceLocation Loc = Tok.getLocation(); // Advance to the location of the first _, this might not be the first byte // of the token if it starts with an escaped newline. Loc = AdvanceToTokenCharacter(Loc, 0); // One wrinkle here is that GCC expands __LINE__ to location of the *end* of // a macro expansion. This doesn't matter for object-like macros, but // can matter for a function-like macro that expands to contain __LINE__. // Skip down through expansion points until we find a file loc for the // end of the expansion history. Loc = SourceMgr.getInstantiationRange(Loc).second; PresumedLoc PLoc = SourceMgr.getPresumedLoc(Loc); // __LINE__ expands to a simple numeric value. OS << (PLoc.isValid()? PLoc.getLine() : 1); Tok.setKind(tok::numeric_constant); } else if (II == Ident__FILE__ || II == Ident__BASE_FILE__) { // C99 6.10.8: "__FILE__: The presumed name of the current source file (a // character string literal)". This can be affected by #line. PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation()); // __BASE_FILE__ is a GNU extension that returns the top of the presumed // #include stack instead of the current file. if (II == Ident__BASE_FILE__ && PLoc.isValid()) { SourceLocation NextLoc = PLoc.getIncludeLoc(); while (NextLoc.isValid()) { PLoc = SourceMgr.getPresumedLoc(NextLoc); if (PLoc.isInvalid()) break; NextLoc = PLoc.getIncludeLoc(); } } // Escape this filename. Turn '\' -> '\\' '"' -> '\"' llvm::SmallString<128> FN; if (PLoc.isValid()) { FN += PLoc.getFilename(); Lexer::Stringify(FN); OS << '"' << FN.str() << '"'; } Tok.setKind(tok::string_literal); } else if (II == Ident__DATE__) { if (!DATELoc.isValid()) ComputeDATE_TIME(DATELoc, TIMELoc, *this); Tok.setKind(tok::string_literal); Tok.setLength(strlen("\"Mmm dd yyyy\"")); Tok.setLocation(SourceMgr.createInstantiationLoc(DATELoc, Tok.getLocation(), Tok.getLocation(), Tok.getLength())); return; } else if (II == Ident__TIME__) { if (!TIMELoc.isValid()) ComputeDATE_TIME(DATELoc, TIMELoc, *this); Tok.setKind(tok::string_literal); Tok.setLength(strlen("\"hh:mm:ss\"")); Tok.setLocation(SourceMgr.createInstantiationLoc(TIMELoc, Tok.getLocation(), Tok.getLocation(), Tok.getLength())); return; } else if (II == Ident__INCLUDE_LEVEL__) { // Compute the presumed include depth of this token. This can be affected // by GNU line markers. unsigned Depth = 0; PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation()); if (PLoc.isValid()) { PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc()); for (; PLoc.isValid(); ++Depth) PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc()); } // __INCLUDE_LEVEL__ expands to a simple numeric value. OS << Depth; Tok.setKind(tok::numeric_constant); } else if (II == Ident__TIMESTAMP__) { // MSVC, ICC, GCC, VisualAge C++ extension. The generated string should be // of the form "Ddd Mmm dd hh::mm::ss yyyy", which is returned by asctime. // Get the file that we are lexing out of. If we're currently lexing from // a macro, dig into the include stack. const FileEntry *CurFile = 0; PreprocessorLexer *TheLexer = getCurrentFileLexer(); if (TheLexer) CurFile = SourceMgr.getFileEntryForID(TheLexer->getFileID()); const char *Result; if (CurFile) { time_t TT = CurFile->getModificationTime(); struct tm *TM = localtime(&TT); Result = asctime(TM); } else { Result = "??? ??? ?? ??:??:?? ????\n"; } // Surround the string with " and strip the trailing newline. OS << '"' << llvm::StringRef(Result, strlen(Result)-1) << '"'; Tok.setKind(tok::string_literal); } else if (II == Ident__COUNTER__) { // __COUNTER__ expands to a simple numeric value. OS << CounterValue++; Tok.setKind(tok::numeric_constant); } else if (II == Ident__has_feature || II == Ident__has_extension || II == Ident__has_builtin || II == Ident__has_attribute) { // The argument to these builtins should be a parenthesized identifier. SourceLocation StartLoc = Tok.getLocation(); bool IsValid = false; IdentifierInfo *FeatureII = 0; // Read the '('. Lex(Tok); if (Tok.is(tok::l_paren)) { // Read the identifier Lex(Tok); if (Tok.is(tok::identifier)) { FeatureII = Tok.getIdentifierInfo(); // Read the ')'. Lex(Tok); if (Tok.is(tok::r_paren)) IsValid = true; } } bool Value = false; if (!IsValid) Diag(StartLoc, diag::err_feature_check_malformed); else if (II == Ident__has_builtin) { // Check for a builtin is trivial. Value = FeatureII->getBuiltinID() != 0; } else if (II == Ident__has_attribute) Value = HasAttribute(FeatureII); else if (II == Ident__has_extension) Value = HasExtension(*this, FeatureII); else { assert(II == Ident__has_feature && "Must be feature check"); Value = HasFeature(*this, FeatureII); } OS << (int)Value; Tok.setKind(tok::numeric_constant); } else if (II == Ident__has_include || II == Ident__has_include_next) { // The argument to these two builtins should be a parenthesized // file name string literal using angle brackets (<>) or // double-quotes (""). bool Value; if (II == Ident__has_include) Value = EvaluateHasInclude(Tok, II, *this); else Value = EvaluateHasIncludeNext(Tok, II, *this); OS << (int)Value; Tok.setKind(tok::numeric_constant); } else { assert(0 && "Unknown identifier!"); } CreateString(OS.str().data(), OS.str().size(), Tok, Tok.getLocation()); }
/// EvaluateValue - Evaluate the token PeekTok (and any others needed) and /// return the computed value in Result. Return true if there was an error /// parsing. This function also returns information about the form of the /// expression in DT. See above for information on what DT means. /// /// If ValueLive is false, then this value is being evaluated in a context where /// the result is not used. As such, avoid diagnostics that relate to /// evaluation. static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, bool ValueLive, Preprocessor &PP) { DT.State = DefinedTracker::Unknown; if (PeekTok.is(tok::code_completion)) { if (PP.getCodeCompletionHandler()) PP.getCodeCompletionHandler()->CodeCompletePreprocessorExpression(); PP.setCodeCompletionReached(); PP.LexNonComment(PeekTok); } // If this token's spelling is a pp-identifier, check to see if it is // 'defined' or if it is a macro. Note that we check here because many // keywords are pp-identifiers, so we can't check the kind. if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) { // Handle "defined X" and "defined(X)". if (II->isStr("defined")) return(EvaluateDefined(Result, PeekTok, DT, ValueLive, PP)); // If this identifier isn't 'defined' or one of the special // preprocessor keywords and it wasn't macro expanded, it turns // into a simple 0, unless it is the C++ keyword "true", in which case it // turns into "1". if (ValueLive && II->getTokenID() != tok::kw_true && II->getTokenID() != tok::kw_false) PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II; Result.Val = II->getTokenID() == tok::kw_true; Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0. Result.setRange(PeekTok.getLocation()); PP.LexNonComment(PeekTok); return false; } switch (PeekTok.getKind()) { default: // Non-value token. PP.Diag(PeekTok, diag::err_pp_expr_bad_token_start_expr); return true; case tok::eod: case tok::r_paren: // If there is no expression, report and exit. PP.Diag(PeekTok, diag::err_pp_expected_value_in_expr); return true; case tok::numeric_constant: { SmallString<64> IntegerBuffer; bool NumberInvalid = false; StringRef Spelling = PP.getSpelling(PeekTok, IntegerBuffer, &NumberInvalid); if (NumberInvalid) return true; // a diagnostic was already reported NumericLiteralParser Literal(Spelling, PeekTok.getLocation(), PP); if (Literal.hadError) return true; // a diagnostic was already reported. if (Literal.isFloatingLiteral() || Literal.isImaginary) { PP.Diag(PeekTok, diag::err_pp_illegal_floating_literal); return true; } assert(Literal.isIntegerLiteral() && "Unknown ppnumber"); // Complain about, and drop, any ud-suffix. if (Literal.hasUDSuffix()) PP.Diag(PeekTok, diag::err_pp_invalid_udl) << /*integer*/1; // 'long long' is a C99 or C++11 feature. if (!PP.getLangOpts().C99 && Literal.isLongLong) { if (PP.getLangOpts().CPlusPlus) PP.Diag(PeekTok, PP.getLangOpts().CPlusPlus0x ? diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong); else PP.Diag(PeekTok, diag::ext_c99_longlong); } // Parse the integer literal into Result. if (Literal.GetIntegerValue(Result.Val)) { // Overflow parsing integer literal. if (ValueLive) PP.Diag(PeekTok, diag::warn_integer_too_large); Result.Val.setIsUnsigned(true); } else { // Set the signedness of the result to match whether there was a U suffix // or not. Result.Val.setIsUnsigned(Literal.isUnsigned); // Detect overflow based on whether the value is signed. If signed // and if the value is too large, emit a warning "integer constant is so // large that it is unsigned" e.g. on 12345678901234567890 where intmax_t // is 64-bits. if (!Literal.isUnsigned && Result.Val.isNegative()) { // Don't warn for a hex literal: 0x8000..0 shouldn't warn. if (ValueLive && Literal.getRadix() != 16) PP.Diag(PeekTok, diag::warn_integer_too_large_for_signed); Result.Val.setIsUnsigned(true); } } // Consume the token. Result.setRange(PeekTok.getLocation()); PP.LexNonComment(PeekTok); return false; } case tok::char_constant: // 'x' case tok::wide_char_constant: { // L'x' case tok::utf16_char_constant: // u'x' case tok::utf32_char_constant: // U'x' // Complain about, and drop, any ud-suffix. if (PeekTok.hasUDSuffix()) PP.Diag(PeekTok, diag::err_pp_invalid_udl) << /*character*/0; SmallString<32> CharBuffer; bool CharInvalid = false; StringRef ThisTok = PP.getSpelling(PeekTok, CharBuffer, &CharInvalid); if (CharInvalid) return true; CharLiteralParser Literal(ThisTok.begin(), ThisTok.end(), PeekTok.getLocation(), PP, PeekTok.getKind()); if (Literal.hadError()) return true; // A diagnostic was already emitted. // Character literals are always int or wchar_t, expand to intmax_t. const TargetInfo &TI = PP.getTargetInfo(); unsigned NumBits; if (Literal.isMultiChar()) NumBits = TI.getIntWidth(); else if (Literal.isWide()) NumBits = TI.getWCharWidth(); else if (Literal.isUTF16()) NumBits = TI.getChar16Width(); else if (Literal.isUTF32()) NumBits = TI.getChar32Width(); else NumBits = TI.getCharWidth(); // Set the width. llvm::APSInt Val(NumBits); // Set the value. Val = Literal.getValue(); // Set the signedness. UTF-16 and UTF-32 are always unsigned if (!Literal.isUTF16() && !Literal.isUTF32()) Val.setIsUnsigned(!PP.getLangOpts().CharIsSigned); if (Result.Val.getBitWidth() > Val.getBitWidth()) { Result.Val = Val.extend(Result.Val.getBitWidth()); } else { assert(Result.Val.getBitWidth() == Val.getBitWidth() && "intmax_t smaller than char/wchar_t?"); Result.Val = Val; } // Consume the token. Result.setRange(PeekTok.getLocation()); PP.LexNonComment(PeekTok); return false; } case tok::l_paren: { SourceLocation Start = PeekTok.getLocation(); PP.LexNonComment(PeekTok); // Eat the (. // Parse the value and if there are any binary operators involved, parse // them. if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true; // If this is a silly value like (X), which doesn't need parens, check for // !(defined X). if (PeekTok.is(tok::r_paren)) { // Just use DT unmodified as our result. } else { // Otherwise, we have something like (x+y), and we consumed '(x'. if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive, PP)) return true; if (PeekTok.isNot(tok::r_paren)) { PP.Diag(PeekTok.getLocation(), diag::err_pp_expected_rparen) << Result.getRange(); PP.Diag(Start, diag::note_matching) << "("; return true; } DT.State = DefinedTracker::Unknown; } Result.setRange(Start, PeekTok.getLocation()); PP.LexNonComment(PeekTok); // Eat the ). return false; } case tok::plus: { SourceLocation Start = PeekTok.getLocation(); // Unary plus doesn't modify the value. PP.LexNonComment(PeekTok); if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true; Result.setBegin(Start); return false; } case tok::minus: { SourceLocation Loc = PeekTok.getLocation(); PP.LexNonComment(PeekTok); if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true; Result.setBegin(Loc); // C99 6.5.3.3p3: The sign of the result matches the sign of the operand. Result.Val = -Result.Val; // -MININT is the only thing that overflows. Unsigned never overflows. bool Overflow = !Result.isUnsigned() && Result.Val.isMinSignedValue(); // If this operator is live and overflowed, report the issue. if (Overflow && ValueLive) PP.Diag(Loc, diag::warn_pp_expr_overflow) << Result.getRange(); DT.State = DefinedTracker::Unknown; return false; } case tok::tilde: { SourceLocation Start = PeekTok.getLocation(); PP.LexNonComment(PeekTok); if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true; Result.setBegin(Start); // C99 6.5.3.3p4: The sign of the result matches the sign of the operand. Result.Val = ~Result.Val; DT.State = DefinedTracker::Unknown; return false; } case tok::exclaim: { SourceLocation Start = PeekTok.getLocation(); PP.LexNonComment(PeekTok); if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true; Result.setBegin(Start); Result.Val = !Result.Val; // C99 6.5.3.3p5: The sign of the result is 'int', aka it is signed. Result.Val.setIsUnsigned(false); if (DT.State == DefinedTracker::DefinedMacro) DT.State = DefinedTracker::NotDefinedMacro; else if (DT.State == DefinedTracker::NotDefinedMacro) DT.State = DefinedTracker::DefinedMacro; return false; } // FIXME: Handle #assert } }
bool operator==(Token t) { return to_string() == t.to_string(); }
/// LexTokenInternal - This implements a simple Fortran family lexer. It is an /// extremely performance critical piece of code. This assumes that the buffer /// has a null character at the end of the file. It assumes that the Flags of /// Result have been cleared before calling this. void Lexer::LexTokenInternal(Token &Result) { // Check to see if there is still more of the line to lex. if (Text.empty() || Text.AtEndOfLine()) { Text.Reset(); Text.GetNextLine(); } // Check to see if we're at the start of a line. if (getLineBegin() == getCurrentPtr()) // The returned token is at the start of the line. Result.setFlag(Token::StartOfStatement); // If we saw a semicolon, then we're at the start of a new statement. if (LastTokenWasSemicolon) { LastTokenWasSemicolon = false; Result.setFlag(Token::StartOfStatement); } // Small amounts of horizontal whitespace is very common between tokens. char Char = getCurrentChar(); while (isHorizontalWhitespace(Char)) Char = getNextChar(); TokStart = getCurrentPtr(); tok::TokenKind Kind; switch (Char) { case 0: // Null. // Found end of file? if (getCurrentPtr() >= CurBuf->getBufferEnd()) { Kind = tok::eof; break; } getNextChar(); return LexTokenInternal(Result); case '\n': case '\r': case ' ': case '\t': case '\f': case '\v': do { Char = getNextChar(); } while (isHorizontalWhitespace(Char)); return LexTokenInternal(Result); case '.': Char = getNextChar(); if (isLetter(Char)) { // Match [A-Za-z]*, we have already matched '.'. while (isLetter(Char)) Char = getNextChar(); if (Char != '.') { // [TODO]: error. Diags.ReportError(SMLoc::getFromPointer(TokStart), "invalid defined operator missing end '.'"); FormTokenWithChars(Result, tok::unknown); return; } Char = getNextChar(); if (Char == '_') { // Parse the kind. do { Char = getNextChar(); } while (isIdentifierBody(Char) || isDecimalNumberBody(Char)); } return FormDefinedOperatorTokenWithChars(Result); } // FALLTHROUGH case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': // [TODO]: Kinds on literals. if (Result.isAtStartOfStatement()) return LexStatementLabel(Result); return LexNumericConstant(Result); case '"': case '\'': // [TODO]: Kinds. return LexCharacterLiteralConstant(Result, Char == '"'); // [TODO]: BOZ literals. case 'B': case 'b': if (Char == '"' || Char == '\'') { // No whitespace between B and quote. // Possible binary constant: B'...', B"..." const char *BOZBegin = getCurrentPtr(); bool DoubleQuote = (Char == '"'); do { Char = getNextChar(); } while (isBinaryNumberBody(Char)); if (getCurrentPtr() - TokStart == 2) { Diags.ReportError(SMLoc::getFromPointer(BOZBegin), "no binary digits for BOZ constant"); FormTokenWithChars(Result, tok::error); return; } if ((DoubleQuote && Char != '"') || Char != '\'') { Diags.ReportError(SMLoc::getFromPointer(BOZBegin), "binary BOZ constant missing ending quote"); FormTokenWithChars(Result, tok::error); return; } // Update the location of token. FormTokenWithChars(Result, tok::binary_boz_constant); Result.setLiteralData(TokStart); return; } goto LexIdentifier; case 'O': case 'o': if (Char == '"' || Char == '\'') { // No whitespace between O and quote. // Possible octal constant: O'...', O"..." const char *BOZBegin = getCurrentPtr(); bool DoubleQuote = (Char == '"'); do { Char = getNextChar(); } while (isOctalNumberBody(Char)); if (getCurrentPtr() - TokStart == 2) { Diags.ReportError(SMLoc::getFromPointer(BOZBegin), "no octal digits for BOZ constant"); FormTokenWithChars(Result, tok::error); return; } if ((DoubleQuote && Char != '"') || Char != '\'') { Diags.ReportError(SMLoc::getFromPointer(BOZBegin), "octal BOZ constant missing ending quote"); FormTokenWithChars(Result, tok::unknown); return; } // Update the location of token. FormTokenWithChars(Result, tok::octal_boz_constant); Result.setLiteralData(TokStart); return; } goto LexIdentifier; case 'X': case 'x': case 'Z': case 'z': if (Char == '"' || Char == '\'') { // No whitespace between Z and quote. // Possible hexadecimal constant: Z'...', Z"..." const char *BOZBegin = getCurrentPtr(); bool DoubleQuote = (Char == '"'); do { Char = getNextChar(); } while (isHexNumberBody(Char)); if (getCurrentPtr() - TokStart == 2) { Diags.ReportError(SMLoc::getFromPointer(BOZBegin), "no hex digits for BOZ constant"); FormTokenWithChars(Result, tok::unknown); return; } if ((DoubleQuote && Char != '"') || Char != '\'') { Diags.ReportError(SMLoc::getFromPointer(BOZBegin), "hex BOZ constant missing ending quote"); FormTokenWithChars(Result, tok::unknown); return; } // Update the location of token. FormTokenWithChars(Result, tok::hex_boz_constant); Result.setLiteralData(TokStart); return; } goto LexIdentifier; case 'A': /* 'B' */ case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': /* 'O' */ case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': /* 'X' */ case 'Y': /* 'Z' */ case 'a': /* 'b' */ case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': /* 'o' */ case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': /* 'x' */ case 'y': /* 'z' */ LexIdentifier: return LexIdentifier(Result); case '!': LexComment(Result); if (Features.ReturnComments) return; return LexTokenInternal(Result); // [TODO]: Special Characters. case '[': Kind = tok::l_square; break; case ']': Kind = tok::r_square; break; case '(': Char = peekNextChar(); if (Char == '/') { // beginning of array initialization. Kind = tok::l_parenslash; Char = getNextChar(); } else { Kind = tok::l_paren; } break; case ')': Kind = tok::r_paren; break; case '{': Kind = tok::l_brace; break; case '}': Kind = tok::r_brace; break; case ',': Kind = tok::comma; break; case ':': Char = peekNextChar(); if (Char == ':') { Kind = tok::coloncolon; Char = getNextChar(); } else { Kind = tok::colon; } break; case ';': LastTokenWasSemicolon = true; return LexTokenInternal(Result); case '%': Kind = tok::percent; break; case '~': Kind = tok::tilde; break; case '?': Kind = tok::question; break; case '`': Kind = tok::backtick; break; case '^': Kind = tok::caret; break; case '|': Kind = tok::pipe; break; case '$': Kind = tok::dollar; break; case '#': Kind = tok::hash; break; case '@': Kind = tok::at; break; // [TODO]: Arithmetical Operators case '+': Kind = tok::plus; break; case '-': Kind = tok::minus; break; case '*': Char = peekNextChar(); if (Char == '*') { // Power operator. Kind = tok::starstar; Char = getNextChar(); } else { Kind = tok::star; } break; case '/': Char = peekNextChar(); if (Char == '=') { // Not equal operator. Kind = tok::slashequal; Char = getNextChar(); } else if (Char == ')') { // End of array initialization list. Kind = tok::slashr_paren; Char = getNextChar(); } else if (Char == '/') { // Concatenation operator. Kind = tok::slashslash; Char = getNextChar(); } else { Kind = tok::slash; } break; // [TODO]: Logical Operators case '=': Char = peekNextChar(); if (Char == '=') { Kind = tok::equalequal; Char = getNextChar(); } else if (Char == '>') { Kind = tok::equalgreater; Char = getNextChar(); } else { Kind = tok::equal; } break; case '<': Char = peekNextChar(); if (Char == '=') { Kind = tok::lessequal; Char = getNextChar(); } else { Kind = tok::less; } break; case '>': Char = peekNextChar(); if (Char == '=') { Kind = tok::greaterequal; Char = getNextChar(); } else { Kind = tok::greater; } break; default: TokStart = getCurrentPtr(); Kind = tok::error; break; } // Update the location of token as well as LexPtr. Char = getNextChar(); FormTokenWithChars(Result, Kind); }
/// getSpelling() - Return the 'spelling' of this token. The spelling of a /// token are the characters used to represent the token in the source file. void Lexer::getSpelling(const Token &Tok, llvm::SmallVectorImpl<llvm::StringRef> &Spelling) const{ assert((int)Tok.getLength() >= 0 && "Token character range is bogus!"); const char *TokStart = Tok.isLiteral() ? Tok.getLiteralData() : Tok.getLocation().getPointer(); unsigned TokLen = Tok.getLength(); // If this token contains nothing interesting, return it directly. if (!Tok.needsCleaning()) return Spelling.push_back(llvm::StringRef(TokStart, TokLen)); const char *CurPtr = TokStart; const char *Start = TokStart; unsigned Len = 0; while (true) { while (Len != TokLen) { if (*CurPtr != '&') { ++CurPtr, ++Len; continue; } if (Tok.isNot(tok::char_literal_constant)) break; const char *TmpPtr = CurPtr + 1; unsigned TmpLen = Len + 1; while (TmpLen != TokLen && isHorizontalWhitespace(*TmpPtr)) ++TmpPtr, ++TmpLen; if (*TmpPtr == '\n' || *TmpPtr == '\r') break; CurPtr = TmpPtr; Len = TmpLen; } Spelling.push_back(llvm::StringRef(Start, CurPtr - Start)); if (*CurPtr != '&' || Len >= TokLen) break; Start = ++CurPtr; ++Len; if (Len >= TokLen) break; while (true) { // Skip blank lines... while (Len != TokLen && isWhitespace(*CurPtr)) ++CurPtr, ++Len; if (*CurPtr != '!') break; // ...and lines with only comments. while (Len != TokLen && *CurPtr != '\n' && *CurPtr != '\r') ++CurPtr, ++Len; } if (*CurPtr != '&' || Len >= TokLen) break; Start = ++CurPtr; ++Len; } }
/// HandleMacroExpandedIdentifier - If an identifier token is read that is to be /// expanded as a macro, handle it and return the next token as 'Identifier'. bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, MacroInfo *MI) { // If this is a macro expansion in the "#if !defined(x)" line for the file, // then the macro could expand to different things in other contexts, we need // to disable the optimization in this case. if (CurPPLexer) CurPPLexer->MIOpt.ExpandedMacro(); // If this is a builtin macro, like __LINE__ or _Pragma, handle it specially. if (MI->isBuiltinMacro()) { if (Callbacks) Callbacks->MacroExpands(Identifier, MI, Identifier.getLocation()); ExpandBuiltinMacro(Identifier); return false; } /// Args - If this is a function-like macro expansion, this contains, /// for each macro argument, the list of tokens that were provided to the /// invocation. MacroArgs *Args = 0; // Remember where the end of the expansion occurred. For an object-like // macro, this is the identifier. For a function-like macro, this is the ')'. SourceLocation ExpansionEnd = Identifier.getLocation(); // If this is a function-like macro, read the arguments. if (MI->isFunctionLike()) { // C99 6.10.3p10: If the preprocessing token immediately after the the macro // name isn't a '(', this macro should not be expanded. if (!isNextPPTokenLParen()) return true; // Remember that we are now parsing the arguments to a macro invocation. // Preprocessor directives used inside macro arguments are not portable, and // this enables the warning. InMacroArgs = true; Args = ReadFunctionLikeMacroArgs(Identifier, MI, ExpansionEnd); // Finished parsing args. InMacroArgs = false; // If there was an error parsing the arguments, bail out. if (Args == 0) return false; ++NumFnMacroExpanded; } else { ++NumMacroExpanded; } // Notice that this macro has been used. markMacroAsUsed(MI); // Remember where the token is expanded. SourceLocation ExpandLoc = Identifier.getLocation(); SourceRange ExpansionRange(ExpandLoc, ExpansionEnd); if (Callbacks) { if (InMacroArgs) { // We can have macro expansion inside a conditional directive while // reading the function macro arguments. To ensure, in that case, that // MacroExpands callbacks still happen in source order, queue this // callback to have it happen after the function macro callback. DelayedMacroExpandsCallbacks.push_back( MacroExpandsInfo(Identifier, MI, ExpansionRange)); } else { Callbacks->MacroExpands(Identifier, MI, ExpansionRange); if (!DelayedMacroExpandsCallbacks.empty()) { for (unsigned i=0, e = DelayedMacroExpandsCallbacks.size(); i!=e; ++i) { MacroExpandsInfo &Info = DelayedMacroExpandsCallbacks[i]; Callbacks->MacroExpands(Info.Tok, Info.MI, Info.Range); } DelayedMacroExpandsCallbacks.clear(); } } } // If we started lexing a macro, enter the macro expansion body. // If this macro expands to no tokens, don't bother to push it onto the // expansion stack, only to take it right back off. if (MI->getNumTokens() == 0) { // No need for arg info. if (Args) Args->destroy(*this); // Ignore this macro use, just return the next token in the current // buffer. bool HadLeadingSpace = Identifier.hasLeadingSpace(); bool IsAtStartOfLine = Identifier.isAtStartOfLine(); Lex(Identifier); // If the identifier isn't on some OTHER line, inherit the leading // whitespace/first-on-a-line property of this token. This handles // stuff like "! XX," -> "! ," and " XX," -> " ,", when XX is // empty. if (!Identifier.isAtStartOfLine()) { if (IsAtStartOfLine) Identifier.setFlag(Token::StartOfLine); if (HadLeadingSpace) Identifier.setFlag(Token::LeadingSpace); } Identifier.setFlag(Token::LeadingEmptyMacro); ++NumFastMacroExpanded; return false; } else if (MI->getNumTokens() == 1 && isTrivialSingleTokenExpansion(MI, Identifier.getIdentifierInfo(), *this)) { // Otherwise, if this macro expands into a single trivially-expanded // token: expand it now. This handles common cases like // "#define VAL 42". // No need for arg info. if (Args) Args->destroy(*this); // Propagate the isAtStartOfLine/hasLeadingSpace markers of the macro // identifier to the expanded token. bool isAtStartOfLine = Identifier.isAtStartOfLine(); bool hasLeadingSpace = Identifier.hasLeadingSpace(); // Replace the result token. Identifier = MI->getReplacementToken(0); // Restore the StartOfLine/LeadingSpace markers. Identifier.setFlagValue(Token::StartOfLine , isAtStartOfLine); Identifier.setFlagValue(Token::LeadingSpace, hasLeadingSpace); // Update the tokens location to include both its expansion and physical // locations. SourceLocation Loc = SourceMgr.createExpansionLoc(Identifier.getLocation(), ExpandLoc, ExpansionEnd,Identifier.getLength()); Identifier.setLocation(Loc); // If this is a disabled macro or #define X X, we must mark the result as // unexpandable. if (IdentifierInfo *NewII = Identifier.getIdentifierInfo()) { if (MacroInfo *NewMI = getMacroInfo(NewII)) if (!NewMI->isEnabled() || NewMI == MI) { Identifier.setFlag(Token::DisableExpand); Diag(Identifier, diag::pp_disabled_macro_expansion); } } // Since this is not an identifier token, it can't be macro expanded, so // we're done. ++NumFastMacroExpanded; return false; } // Start expanding the macro. EnterMacro(Identifier, ExpansionEnd, Args); // Now that the macro is at the top of the include stack, ask the // preprocessor to read the next token from it. Lex(Identifier); return false; }
/// EvaluateDefined - Process a 'defined(sym)' expression. static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT, bool ValueLive, Preprocessor &PP) { IdentifierInfo *II; Result.setBegin(PeekTok.getLocation()); // Get the next token, don't expand it. PP.LexUnexpandedNonComment(PeekTok); // Two options, it can either be a pp-identifier or a (. SourceLocation LParenLoc; if (PeekTok.is(tok::l_paren)) { // Found a paren, remember we saw it and skip it. LParenLoc = PeekTok.getLocation(); PP.LexUnexpandedNonComment(PeekTok); } if (PeekTok.is(tok::code_completion)) { if (PP.getCodeCompletionHandler()) PP.getCodeCompletionHandler()->CodeCompleteMacroName(false); PP.setCodeCompletionReached(); PP.LexUnexpandedNonComment(PeekTok); } // If we don't have a pp-identifier now, this is an error. if ((II = PeekTok.getIdentifierInfo()) == 0) { PP.Diag(PeekTok, diag::err_pp_defined_requires_identifier); return true; } // Otherwise, we got an identifier, is it defined to something? Result.Val = II->hasMacroDefinition(); Result.Val.setIsUnsigned(false); // Result is signed intmax_t. // If there is a macro, mark it used. if (Result.Val != 0 && ValueLive) { MacroInfo *Macro = PP.getMacroInfo(II); PP.markMacroAsUsed(Macro); } // Invoke the 'defined' callback. if (PPCallbacks *Callbacks = PP.getPPCallbacks()) Callbacks->Defined(PeekTok); // If we are in parens, ensure we have a trailing ). if (LParenLoc.isValid()) { // Consume identifier. Result.setEnd(PeekTok.getLocation()); PP.LexUnexpandedNonComment(PeekTok); if (PeekTok.isNot(tok::r_paren)) { PP.Diag(PeekTok.getLocation(), diag::err_pp_missing_rparen) << "defined"; PP.Diag(LParenLoc, diag::note_matching) << "("; return true; } // Consume the ). Result.setEnd(PeekTok.getLocation()); PP.LexNonComment(PeekTok); } else { // Consume identifier. Result.setEnd(PeekTok.getLocation()); PP.LexNonComment(PeekTok); } // Success, remember that we saw defined(X). DT.State = DefinedTracker::DefinedMacro; DT.TheMacro = II; return false; }
/// ReadFunctionLikeMacroArgs - After reading "MACRO" and knowing that the next /// token is the '(' of the macro, this method is invoked to read all of the /// actual arguments specified for the macro invocation. This returns null on /// error. MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName, MacroInfo *MI, SourceLocation &MacroEnd) { // The number of fixed arguments to parse. unsigned NumFixedArgsLeft = MI->getNumArgs(); bool isVariadic = MI->isVariadic(); // Outer loop, while there are more arguments, keep reading them. Token Tok; // Read arguments as unexpanded tokens. This avoids issues, e.g., where // an argument value in a macro could expand to ',' or '(' or ')'. LexUnexpandedToken(Tok); assert(Tok.is(tok::l_paren) && "Error computing l-paren-ness?"); // ArgTokens - Build up a list of tokens that make up each argument. Each // argument is separated by an EOF token. Use a SmallVector so we can avoid // heap allocations in the common case. SmallVector<Token, 64> ArgTokens; unsigned NumActuals = 0; while (Tok.isNot(tok::r_paren)) { assert((Tok.is(tok::l_paren) || Tok.is(tok::comma)) && "only expect argument separators here"); unsigned ArgTokenStart = ArgTokens.size(); SourceLocation ArgStartLoc = Tok.getLocation(); // C99 6.10.3p11: Keep track of the number of l_parens we have seen. Note // that we already consumed the first one. unsigned NumParens = 0; while (1) { // Read arguments as unexpanded tokens. This avoids issues, e.g., where // an argument value in a macro could expand to ',' or '(' or ')'. LexUnexpandedToken(Tok); if (Tok.is(tok::eof) || Tok.is(tok::eod)) { // "#if f(<eof>" & "#if f(\n" Diag(MacroName, diag::err_unterm_macro_invoc); // Do not lose the EOF/EOD. Return it to the client. MacroName = Tok; return 0; } else if (Tok.is(tok::r_paren)) { // If we found the ) token, the macro arg list is done. if (NumParens-- == 0) { MacroEnd = Tok.getLocation(); break; } } else if (Tok.is(tok::l_paren)) { ++NumParens; } else if (Tok.is(tok::comma) && NumParens == 0) { // Comma ends this argument if there are more fixed arguments expected. // However, if this is a variadic macro, and this is part of the // variadic part, then the comma is just an argument token. if (!isVariadic) break; if (NumFixedArgsLeft > 1) break; } else if (Tok.is(tok::comment) && !KeepMacroComments) { // If this is a comment token in the argument list and we're just in // -C mode (not -CC mode), discard the comment. continue; } else if (Tok.getIdentifierInfo() != 0) { // Reading macro arguments can cause macros that we are currently // expanding from to be popped off the expansion stack. Doing so causes // them to be reenabled for expansion. Here we record whether any // identifiers we lex as macro arguments correspond to disabled macros. // If so, we mark the token as noexpand. This is a subtle aspect of // C99 6.10.3.4p2. if (MacroInfo *MI = getMacroInfo(Tok.getIdentifierInfo())) if (!MI->isEnabled()) Tok.setFlag(Token::DisableExpand); } else if (Tok.is(tok::code_completion)) { if (CodeComplete) CodeComplete->CodeCompleteMacroArgument(MacroName.getIdentifierInfo(), MI, NumActuals); // Don't mark that we reached the code-completion point because the // parser is going to handle the token and there will be another // code-completion callback. } ArgTokens.push_back(Tok); } // If this was an empty argument list foo(), don't add this as an empty // argument. if (ArgTokens.empty() && Tok.getKind() == tok::r_paren) break; // If this is not a variadic macro, and too many args were specified, emit // an error. if (!isVariadic && NumFixedArgsLeft == 0) { if (ArgTokens.size() != ArgTokenStart) ArgStartLoc = ArgTokens[ArgTokenStart].getLocation(); // Emit the diagnostic at the macro name in case there is a missing ). // Emitting it at the , could be far away from the macro name. Diag(ArgStartLoc, diag::err_too_many_args_in_macro_invoc); return 0; } // Empty arguments are standard in C99 and C++0x, and are supported as an extension in // other modes. if (ArgTokens.size() == ArgTokenStart && !LangOpts.C99) Diag(Tok, LangOpts.CPlusPlus0x ? diag::warn_cxx98_compat_empty_fnmacro_arg : diag::ext_empty_fnmacro_arg); // Add a marker EOF token to the end of the token list for this argument. Token EOFTok; EOFTok.startToken(); EOFTok.setKind(tok::eof); EOFTok.setLocation(Tok.getLocation()); EOFTok.setLength(0); ArgTokens.push_back(EOFTok); ++NumActuals; assert(NumFixedArgsLeft != 0 && "Too many arguments parsed"); --NumFixedArgsLeft; } // Okay, we either found the r_paren. Check to see if we parsed too few // arguments. unsigned MinArgsExpected = MI->getNumArgs(); // See MacroArgs instance var for description of this. bool isVarargsElided = false; if (NumActuals < MinArgsExpected) { // There are several cases where too few arguments is ok, handle them now. if (NumActuals == 0 && MinArgsExpected == 1) { // #define A(X) or #define A(...) ---> A() // If there is exactly one argument, and that argument is missing, // then we have an empty "()" argument empty list. This is fine, even if // the macro expects one argument (the argument is just empty). isVarargsElided = MI->isVariadic(); } else if (MI->isVariadic() && (NumActuals+1 == MinArgsExpected || // A(x, ...) -> A(X) (NumActuals == 0 && MinArgsExpected == 2))) {// A(x,...) -> A() // Varargs where the named vararg parameter is missing: ok as extension. // #define A(x, ...) // A("blah") Diag(Tok, diag::ext_missing_varargs_arg); // Remember this occurred, allowing us to elide the comma when used for // cases like: // #define A(x, foo...) blah(a, ## foo) // #define B(x, ...) blah(a, ## __VA_ARGS__) // #define C(...) blah(a, ## __VA_ARGS__) // A(x) B(x) C() isVarargsElided = true; } else { // Otherwise, emit the error. Diag(Tok, diag::err_too_few_args_in_macro_invoc); return 0; } // Add a marker EOF token to the end of the token list for this argument. SourceLocation EndLoc = Tok.getLocation(); Tok.startToken(); Tok.setKind(tok::eof); Tok.setLocation(EndLoc); Tok.setLength(0); ArgTokens.push_back(Tok); // If we expect two arguments, add both as empty. if (NumActuals == 0 && MinArgsExpected == 2) ArgTokens.push_back(Tok); } else if (NumActuals > MinArgsExpected && !MI->isVariadic()) { // Emit the diagnostic at the macro name in case there is a missing ). // Emitting it at the , could be far away from the macro name. Diag(MacroName, diag::err_too_many_args_in_macro_invoc); return 0; } return MacroArgs::create(MI, ArgTokens, isVarargsElided, *this); }
/* * Prepares for matching. This method is called during construction. */ void RegularExpression::prepare() { compile(fTokenTree); fMinLength = fTokenTree->getMinLength(); fFirstChar = 0; if (!isSet(fOptions, PROHIBIT_HEAD_CHARACTER_OPTIMIZATION) && !isSet(fOptions, XMLSCHEMA_MODE)) { RangeToken* rangeTok = fTokenFactory->createRange(); int result = fTokenTree->analyzeFirstCharacter(rangeTok, fOptions, fTokenFactory); if (result == Token::FC_TERMINAL) { rangeTok->compactRanges(); fFirstChar = rangeTok; } rangeTok->createMap(); if (isSet(fOptions, IGNORE_CASE)) { rangeTok->getCaseInsensitiveToken(fTokenFactory); } } if (fOperations != 0 && fOperations->getNextOp() == 0 && (fOperations->getOpType() == Op::O_STRING || fOperations->getOpType() == Op::O_CHAR) ) { fFixedStringOnly = true; if (fOperations->getOpType() == Op::O_STRING) { fMemoryManager->deallocate(fFixedString);//delete [] fFixedString; fFixedString = XMLString::replicate(fOperations->getLiteral(), fMemoryManager); } else{ XMLInt32 ch = fOperations->getData(); if ( ch >= 0x10000) { // add as constant fMemoryManager->deallocate(fFixedString);//delete [] fFixedString; fFixedString = RegxUtil::decomposeToSurrogates(ch, fMemoryManager); } else { XMLCh* dummyStr = (XMLCh*) fMemoryManager->allocate(2 * sizeof(XMLCh));//new XMLCh[2]; dummyStr[0] = (XMLCh) fOperations->getData(); dummyStr[1] = chNull; fMemoryManager->deallocate(fFixedString);//delete [] fFixedString; fFixedString = dummyStr; } } fBMPattern = new (fMemoryManager) BMPattern(fFixedString, 256, isSet(fOptions, IGNORE_CASE), fMemoryManager); } else if (!isSet(fOptions, XMLSCHEMA_MODE) && !isSet(fOptions, PROHIBIT_FIXED_STRING_OPTIMIZATION)) { int fixedOpts = 0; Token* tok = fTokenTree->findFixedString(fOptions, fixedOpts); fMemoryManager->deallocate(fFixedString);//delete [] fFixedString; fFixedString = (tok == 0) ? 0 : XMLString::replicate(tok->getString(), fMemoryManager); if (fFixedString != 0 && XMLString::stringLen(fFixedString) < 2) { fMemoryManager->deallocate(fFixedString);//delete [] fFixedString; fFixedString = 0; } if (fFixedString != 0) { fBMPattern = new (fMemoryManager) BMPattern(fFixedString, 256, isSet(fixedOpts, IGNORE_CASE), fMemoryManager); } } }
/// ExpandBuiltinMacro - If an identifier token is read that is to be expanded /// as a builtin macro, handle it and return the next token as 'Tok'. void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // Figure out which token this is. IdentifierInfo *II = Tok.getIdentifierInfo(); assert(II && "Can't be a macro without id info!"); // If this is an _Pragma or Microsoft __pragma directive, expand it, // invoke the pragma handler, then lex the token after it. if (II == Ident_Pragma) return Handle_Pragma(Tok); else if (II == Ident__pragma) // in non-MS mode this is null return HandleMicrosoft__pragma(Tok); ++NumBuiltinMacroExpanded; SmallString<128> TmpBuffer; llvm::raw_svector_ostream OS(TmpBuffer); // Set up the return result. Tok.setIdentifierInfo(0); Tok.clearFlag(Token::NeedsCleaning); if (II == Ident__LINE__) { // C99 6.10.8: "__LINE__: The presumed line number (within the current // source file) of the current source line (an integer constant)". This can // be affected by #line. SourceLocation Loc = Tok.getLocation(); // Advance to the location of the first _, this might not be the first byte // of the token if it starts with an escaped newline. Loc = AdvanceToTokenCharacter(Loc, 0); // One wrinkle here is that GCC expands __LINE__ to location of the *end* of // a macro expansion. This doesn't matter for object-like macros, but // can matter for a function-like macro that expands to contain __LINE__. // Skip down through expansion points until we find a file loc for the // end of the expansion history. Loc = SourceMgr.getExpansionRange(Loc).second; PresumedLoc PLoc = SourceMgr.getPresumedLoc(Loc); // __LINE__ expands to a simple numeric value. OS << (PLoc.isValid()? PLoc.getLine() : 1); Tok.setKind(tok::numeric_constant); } else if (II == Ident__FILE__ || II == Ident__BASE_FILE__) { // C99 6.10.8: "__FILE__: The presumed name of the current source file (a // character string literal)". This can be affected by #line. PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation()); // __BASE_FILE__ is a GNU extension that returns the top of the presumed // #include stack instead of the current file. if (II == Ident__BASE_FILE__ && PLoc.isValid()) { SourceLocation NextLoc = PLoc.getIncludeLoc(); while (NextLoc.isValid()) { PLoc = SourceMgr.getPresumedLoc(NextLoc); if (PLoc.isInvalid()) break; NextLoc = PLoc.getIncludeLoc(); } } // Escape this filename. Turn '\' -> '\\' '"' -> '\"' SmallString<128> FN; if (PLoc.isValid()) { FN += PLoc.getFilename(); Lexer::Stringify(FN); OS << '"' << FN.str() << '"'; } Tok.setKind(tok::string_literal); } else if (II == Ident__DATE__) { if (!DATELoc.isValid()) ComputeDATE_TIME(DATELoc, TIMELoc, *this); Tok.setKind(tok::string_literal); Tok.setLength(strlen("\"Mmm dd yyyy\"")); Tok.setLocation(SourceMgr.createExpansionLoc(DATELoc, Tok.getLocation(), Tok.getLocation(), Tok.getLength())); return; } else if (II == Ident__TIME__) { if (!TIMELoc.isValid()) ComputeDATE_TIME(DATELoc, TIMELoc, *this); Tok.setKind(tok::string_literal); Tok.setLength(strlen("\"hh:mm:ss\"")); Tok.setLocation(SourceMgr.createExpansionLoc(TIMELoc, Tok.getLocation(), Tok.getLocation(), Tok.getLength())); return; } else if (II == Ident__INCLUDE_LEVEL__) { // Compute the presumed include depth of this token. This can be affected // by GNU line markers. unsigned Depth = 0; PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation()); if (PLoc.isValid()) { PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc()); for (; PLoc.isValid(); ++Depth) PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc()); } // __INCLUDE_LEVEL__ expands to a simple numeric value. OS << Depth; Tok.setKind(tok::numeric_constant); } else if (II == Ident__TIMESTAMP__) { // MSVC, ICC, GCC, VisualAge C++ extension. The generated string should be // of the form "Ddd Mmm dd hh::mm::ss yyyy", which is returned by asctime. // Get the file that we are lexing out of. If we're currently lexing from // a macro, dig into the include stack. const FileEntry *CurFile = 0; PreprocessorLexer *TheLexer = getCurrentFileLexer(); if (TheLexer) CurFile = SourceMgr.getFileEntryForID(TheLexer->getFileID()); const char *Result; if (CurFile) { time_t TT = CurFile->getModificationTime(); struct tm *TM = localtime(&TT); Result = asctime(TM); } else { Result = "??? ??? ?? ??:??:?? ????\n"; } // Surround the string with " and strip the trailing newline. OS << '"' << StringRef(Result, strlen(Result)-1) << '"'; Tok.setKind(tok::string_literal); } else if (II == Ident__COUNTER__) { // __COUNTER__ expands to a simple numeric value. OS << CounterValue++; Tok.setKind(tok::numeric_constant); } else if (II == Ident__has_feature || II == Ident__has_extension || II == Ident__has_builtin || II == Ident__has_attribute) { // The argument to these builtins should be a parenthesized identifier. SourceLocation StartLoc = Tok.getLocation(); bool IsValid = false; IdentifierInfo *FeatureII = 0; // Read the '('. Lex(Tok); if (Tok.is(tok::l_paren)) { // Read the identifier Lex(Tok); if (Tok.is(tok::identifier)) { FeatureII = Tok.getIdentifierInfo(); // Read the ')'. Lex(Tok); if (Tok.is(tok::r_paren)) IsValid = true; } } bool Value = false; if (!IsValid) Diag(StartLoc, diag::err_feature_check_malformed); else if (II == Ident__has_builtin) { // Check for a builtin is trivial. Value = FeatureII->getBuiltinID() != 0; } else if (II == Ident__has_attribute) Value = HasAttribute(FeatureII); else if (II == Ident__has_extension) Value = HasExtension(*this, FeatureII); else { assert(II == Ident__has_feature && "Must be feature check"); Value = HasFeature(*this, FeatureII); } OS << (int)Value; if (IsValid) Tok.setKind(tok::numeric_constant); } else if (II == Ident__has_include || II == Ident__has_include_next) { // The argument to these two builtins should be a parenthesized // file name string literal using angle brackets (<>) or // double-quotes (""). bool Value; if (II == Ident__has_include) Value = EvaluateHasInclude(Tok, II, *this); else Value = EvaluateHasIncludeNext(Tok, II, *this); OS << (int)Value; Tok.setKind(tok::numeric_constant); } else if (II == Ident__has_warning) { // The argument should be a parenthesized string literal. // The argument to these builtins should be a parenthesized identifier. SourceLocation StartLoc = Tok.getLocation(); bool IsValid = false; bool Value = false; // Read the '('. Lex(Tok); do { if (Tok.is(tok::l_paren)) { // Read the string. Lex(Tok); // We need at least one string literal. if (!Tok.is(tok::string_literal)) { StartLoc = Tok.getLocation(); IsValid = false; // Eat tokens until ')'. do Lex(Tok); while (!(Tok.is(tok::r_paren) || Tok.is(tok::eod))); break; } // String concatenation allows multiple strings, which can even come // from macro expansion. SmallVector<Token, 4> StrToks; while (Tok.is(tok::string_literal)) { // Complain about, and drop, any ud-suffix. if (Tok.hasUDSuffix()) Diag(Tok, diag::err_invalid_string_udl); StrToks.push_back(Tok); LexUnexpandedToken(Tok); } // Is the end a ')'? if (!(IsValid = Tok.is(tok::r_paren))) break; // Concatenate and parse the strings. StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this); assert(Literal.isAscii() && "Didn't allow wide strings in"); if (Literal.hadError) break; if (Literal.Pascal) { Diag(Tok, diag::warn_pragma_diagnostic_invalid); break; } StringRef WarningName(Literal.GetString()); if (WarningName.size() < 3 || WarningName[0] != '-' || WarningName[1] != 'W') { Diag(StrToks[0].getLocation(), diag::warn_has_warning_invalid_option); break; } // Finally, check if the warning flags maps to a diagnostic group. // We construct a SmallVector here to talk to getDiagnosticIDs(). // Although we don't use the result, this isn't a hot path, and not // worth special casing. llvm::SmallVector<diag::kind, 10> Diags; Value = !getDiagnostics().getDiagnosticIDs()-> getDiagnosticsInGroup(WarningName.substr(2), Diags); } } while (false); if (!IsValid) Diag(StartLoc, diag::err_warning_check_malformed); OS << (int)Value; Tok.setKind(tok::numeric_constant); } else { llvm_unreachable("Unknown identifier!"); } CreateString(OS.str().data(), OS.str().size(), Tok, Tok.getLocation(), Tok.getLocation()); }
std::set<std::string> TemplateSimplifier::expandSpecialized(Token *tokens) { std::set<std::string> expandedtemplates; // Locate specialized templates.. for (Token *tok = tokens; tok; tok = tok->next()) { if (!Token::simpleMatch(tok, "template < >")) continue; // what kind of template is this? Token *tok2 = tok->tokAt(3); while (tok2 && (tok2->isName() || tok2->str() == "*")) tok2 = tok2->next(); if (!TemplateSimplifier::templateParameters(tok2)) continue; // unknown template.. bail out if (!tok2->previous()->isName()) continue; tok2 = tok2->previous(); std::string s; { std::ostringstream ostr; const Token *tok3 = tok2; for (; tok3 && tok3->str() != ">"; tok3 = tok3->next()) { if (tok3 != tok2) ostr << " "; ostr << tok3->str(); } if (!Token::simpleMatch(tok3, "> (")) continue; s = ostr.str(); } // save search pattern.. const std::string pattern(s + " > ("); // remove spaces to create new name s.erase(std::remove(s.begin(), s.end(), ' '), s.end()); const std::string name(s + ">"); expandedtemplates.insert(name); // Rename template.. Token::eraseTokens(tok2, Token::findsimplematch(tok2, "(")); tok2->str(name); // delete the "template < >" tok->deleteNext(2); tok->deleteThis(); // Use this special template in the code.. while (NULL != (tok2 = const_cast<Token *>(Token::findmatch(tok2, pattern.c_str())))) { Token::eraseTokens(tok2, Token::findsimplematch(tok2, "(")); tok2->str(name); } } return expandedtemplates; }
void MetaLexer::LexPunctuator(char C, Token& Tok) { Tok.setLength(1); switch (C) { case '[' : Tok.setKind(tok::l_square); break; case ']' : Tok.setKind(tok::r_square); break; case '(' : Tok.setKind(tok::l_paren); break; case ')' : Tok.setKind(tok::r_paren); break; case '{' : Tok.setKind(tok::l_brace); break; case '}' : Tok.setKind(tok::r_brace); break; case '"' : Tok.setKind(tok::quote); break; case '\'' : Tok.setKind(tok::apostrophe); break; case ',' : Tok.setKind(tok::comma); break; case '.' : Tok.setKind(tok::dot); break; case '!' : Tok.setKind(tok::excl_mark); break; case '?' : Tok.setKind(tok::quest_mark); break; case '/' : Tok.setKind(tok::slash); break; case '\\' : Tok.setKind(tok::backslash); break; case '>' : Tok.setKind(tok::greater); break; case '&' : Tok.setKind(tok::ampersand); break; case '\0' : Tok.setKind(tok::eof); Tok.setLength(0); break;// if static call default: Tok.setLength(0); break; } }
void TemplateSimplifier::useDefaultArgumentValues(const std::list<Token *> &templates, const std::list<Token *> &templateInstantiations) { for (std::list<Token *>::const_iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1) { // template parameters with default value has syntax such as: // x = y // this list will contain all the '=' tokens for such arguments std::list<Token *> eq; // parameter number. 1,2,3,.. std::size_t templatepar = 1; // the template classname. This will be empty for template functions std::string classname; // Scan template declaration.. for (Token *tok = *iter1; tok; tok = tok->next()) { // end of template parameters? if (tok->str() == ">") { if (Token::Match(tok, "> class|struct %var%")) classname = tok->strAt(2); break; } // next template parameter if (tok->str() == ",") ++templatepar; // default parameter value else if (tok->str() == "=") eq.push_back(tok); } if (eq.empty() || classname.empty()) continue; // iterate through all template instantiations for (std::list<Token *>::const_iterator iter2 = templateInstantiations.begin(); iter2 != templateInstantiations.end(); ++iter2) { Token *tok = *iter2; if (!Token::Match(tok, (classname + " < %any%").c_str())) continue; // count the parameters.. unsigned int usedpar = 1; for (tok = tok->tokAt(3); tok; tok = tok->tokAt(2)) { if (tok->str() == ">") break; if (tok->str() == ",") ++usedpar; else break; } if (tok && tok->str() == ">") { tok = tok->previous(); std::list<Token *>::const_iterator it = eq.begin(); for (std::size_t i = (templatepar - eq.size()); it != eq.end() && i < usedpar; ++i) ++it; while (it != eq.end()) { tok->insertToken(","); tok = tok->next(); const Token *from = (*it)->next(); std::stack<Token *> links; while (from && (!links.empty() || (from->str() != "," && from->str() != ">"))) { tok->insertToken(from->str()); tok = tok->next(); if (Token::Match(tok, "(|[")) links.push(tok); else if (!links.empty() && Token::Match(tok, ")|]")) { Token::createMutualLinks(links.top(), tok); links.pop(); } from = from->next(); } ++it; } } } for (std::list<Token *>::iterator it = eq.begin(); it != eq.end(); ++it) { Token * const eqtok = *it; const Token *tok2; for (tok2 = eqtok->next(); tok2; tok2 = tok2->next()) { if (tok2->str() == "(") tok2 = tok2->link(); else if (tok2->str() == "," || tok2->str() == ">") break; } Token::eraseTokens(eqtok, tok2); eqtok->deleteThis(); } } }
/// HandleIdentifier - This callback is invoked when the lexer reads an /// identifier. This callback looks up the identifier in the map and/or /// potentially macro expands it or turns it into a named token (like 'for'). /// /// Note that callers of this method are guarded by checking the /// IdentifierInfo's 'isHandleIdentifierCase' bit. If this method changes, the /// IdentifierInfo methods that compute these properties will need to change to /// match. bool Preprocessor::HandleIdentifier(Token &Identifier) { assert(Identifier.getIdentifierInfo() && "Can't handle identifiers without identifier info!"); IdentifierInfo &II = *Identifier.getIdentifierInfo(); // If the information about this identifier is out of date, update it from // the external source. // We have to treat __VA_ARGS__ in a special way, since it gets // serialized with isPoisoned = true, but our preprocessor may have // unpoisoned it if we're defining a C99 macro. if (II.isOutOfDate()) { bool CurrentIsPoisoned = false; const bool IsSpecialVariadicMacro = &II == Ident__VA_ARGS__ || &II == Ident__VA_OPT__; if (IsSpecialVariadicMacro) CurrentIsPoisoned = II.isPoisoned(); updateOutOfDateIdentifier(II); Identifier.setKind(II.getTokenID()); if (IsSpecialVariadicMacro) II.setIsPoisoned(CurrentIsPoisoned); } // If this identifier was poisoned, and if it was not produced from a macro // expansion, emit an error. if (II.isPoisoned() && CurPPLexer) { HandlePoisonedIdentifier(Identifier); } // If this is a macro to be expanded, do it. if (MacroDefinition MD = getMacroDefinition(&II)) { auto *MI = MD.getMacroInfo(); assert(MI && "macro definition with no macro info?"); if (!DisableMacroExpansion) { if (!Identifier.isExpandDisabled() && MI->isEnabled()) { // C99 6.10.3p10: If the preprocessing token immediately after the // macro name isn't a '(', this macro should not be expanded. if (!MI->isFunctionLike() || isNextPPTokenLParen()) return HandleMacroExpandedIdentifier(Identifier, MD); } else { // C99 6.10.3.4p2 says that a disabled macro may never again be // expanded, even if it's in a context where it could be expanded in the // future. Identifier.setFlag(Token::DisableExpand); if (MI->isObjectLike() || isNextPPTokenLParen()) Diag(Identifier, diag::pp_disabled_macro_expansion); } } } // If this identifier is a keyword in a newer Standard or proposed Standard, // produce a warning. Don't warn if we're not considering macro expansion, // since this identifier might be the name of a macro. // FIXME: This warning is disabled in cases where it shouldn't be, like // "#define constexpr constexpr", "int constexpr;" if (II.isFutureCompatKeyword() && !DisableMacroExpansion) { Diag(Identifier, getFutureCompatDiagKind(II, getLangOpts())) << II.getName(); // Don't diagnose this keyword again in this translation unit. II.setIsFutureCompatKeyword(false); } // If this is an extension token, diagnose its use. // We avoid diagnosing tokens that originate from macro definitions. // FIXME: This warning is disabled in cases where it shouldn't be, // like "#define TY typeof", "TY(1) x". if (II.isExtensionToken() && !DisableMacroExpansion) Diag(Identifier, diag::ext_token_used); // If this is the 'import' contextual keyword following an '@', note // that the next token indicates a module name. // // Note that we do not treat 'import' as a contextual // keyword when we're in a caching lexer, because caching lexers only get // used in contexts where import declarations are disallowed. // // Likewise if this is the C++ Modules TS import keyword. if (((LastTokenWasAt && II.isModulesImport()) || Identifier.is(tok::kw_import)) && !InMacroArgs && !DisableMacroExpansion && (getLangOpts().Modules || getLangOpts().DebuggerSupport) && CurLexerKind != CLK_CachingLexer) { ModuleImportLoc = Identifier.getLocation(); ModuleImportPath.clear(); ModuleImportExpectsIdentifier = true; CurLexerKind = CLK_LexAfterModuleImport; } return true; }
Effect::Effect( const char * _filename, int alliance ): ObjectNonAttack( 0, 0, alliance ), image(NULL){ TokenReader tr; setMaxHealth( 100 ); Token * head; try{ head = tr.readTokenFromFile(_filename); } catch ( const TokenException * te ){ throw LoadException(__FILE__, __LINE__, "Could not load effect"); } if ( *head != "effect" ){ cout<<_filename<< " is not an effect"<<endl; // delete head; throw LoadException(__FILE__, __LINE__, "Not an effect"); } TokenView view = head->view(); while (view.hasMore()){ const Token * n = NULL; try{ view >> n; // for ( int q = 0; q < head->numTokens(); q++ ){ // n = head->getToken( q ); if ( *n == "anim" ){ if ( image ){ // cout<<"Mulitple animations specified"<<endl; throw LoadException(__FILE__, __LINE__, "Multiple animations specified"); } image = new Animation(n, NULL); } else { cout<<"Unhandled effect attribute: "<<endl; n->print(" "); } // } /* catch exception?? */ } catch( const exception & ex ){ // delete head; if (n != NULL){ n->print(" "); } /* if ( n ){ cout<<"Error with: "<<n<<endl; } else cout<<"Something bad happened in character"<<endl; throw ex; */ throw LoadException(__FILE__, __LINE__, "Effect parse error"); } } // delete head; }
/// Handle_Pragma - Read a _Pragma directive, slice it up, process it, then /// return the first token after the directive. The _Pragma token has just /// been read into 'Tok'. void Preprocessor::Handle_Pragma(Token &Tok) { // This works differently if we are pre-expanding a macro argument. // In that case we don't actually "activate" the pragma now, we only lex it // until we are sure it is lexically correct and then we backtrack so that // we activate the pragma whenever we encounter the tokens again in the token // stream. This ensures that we will activate it in the correct location // or that we will ignore it if it never enters the token stream, e.g: // // #define EMPTY(x) // #define INACTIVE(x) EMPTY(x) // INACTIVE(_Pragma("clang diagnostic ignored \"-Wconversion\"")) LexingFor_PragmaRAII _PragmaLexing(*this, InMacroArgPreExpansion, Tok); // Remember the pragma token location. SourceLocation PragmaLoc = Tok.getLocation(); // Read the '('. Lex(Tok); if (Tok.isNot(tok::l_paren)) { Diag(PragmaLoc, diag::err__Pragma_malformed); return _PragmaLexing.failed(); } // Read the '"..."'. Lex(Tok); if (!tok::isStringLiteral(Tok.getKind())) { Diag(PragmaLoc, diag::err__Pragma_malformed); // Skip this token, and the ')', if present. if (Tok.isNot(tok::r_paren)) Lex(Tok); if (Tok.is(tok::r_paren)) Lex(Tok); return _PragmaLexing.failed(); } if (Tok.hasUDSuffix()) { Diag(Tok, diag::err_invalid_string_udl); // Skip this token, and the ')', if present. Lex(Tok); if (Tok.is(tok::r_paren)) Lex(Tok); return _PragmaLexing.failed(); } // Remember the string. Token StrTok = Tok; // Read the ')'. Lex(Tok); if (Tok.isNot(tok::r_paren)) { Diag(PragmaLoc, diag::err__Pragma_malformed); return _PragmaLexing.failed(); } if (InMacroArgPreExpansion) return; SourceLocation RParenLoc = Tok.getLocation(); std::string StrVal = getSpelling(StrTok); // The _Pragma is lexically sound. Destringize according to C11 6.10.9.1: // "The string literal is destringized by deleting any encoding prefix, // deleting the leading and trailing double-quotes, replacing each escape // sequence \" by a double-quote, and replacing each escape sequence \\ by a // single backslash." if (StrVal[0] == 'L' || StrVal[0] == 'U' || (StrVal[0] == 'u' && StrVal[1] != '8')) StrVal.erase(StrVal.begin()); else if (StrVal[0] == 'u') StrVal.erase(StrVal.begin(), StrVal.begin() + 2); if (StrVal[0] == 'R') { // FIXME: C++11 does not specify how to handle raw-string-literals here. // We strip off the 'R', the quotes, the d-char-sequences, and the parens. assert(StrVal[1] == '"' && StrVal[StrVal.size() - 1] == '"' && "Invalid raw string token!"); // Measure the length of the d-char-sequence. unsigned NumDChars = 0; while (StrVal[2 + NumDChars] != '(') { assert(NumDChars < (StrVal.size() - 5) / 2 && "Invalid raw string token!"); ++NumDChars; } assert(StrVal[StrVal.size() - 2 - NumDChars] == ')'); // Remove 'R " d-char-sequence' and 'd-char-sequence "'. We'll replace the // parens below. StrVal.erase(0, 2 + NumDChars); StrVal.erase(StrVal.size() - 1 - NumDChars); } else { assert(StrVal[0] == '"' && StrVal[StrVal.size()-1] == '"' && "Invalid string token!"); // Remove escaped quotes and escapes. for (unsigned i = 1, e = StrVal.size(); i < e-2; ++i) { if (StrVal[i] == '\\' && (StrVal[i+1] == '\\' || StrVal[i+1] == '"')) { // \\ -> '\' and \" -> '"'. StrVal.erase(StrVal.begin()+i); --e; } } } // Remove the front quote, replacing it with a space, so that the pragma // contents appear to have a space before them. StrVal[0] = ' '; // Replace the terminating quote with a \n. StrVal[StrVal.size()-1] = '\n'; // Plop the string (including the newline and trailing null) into a buffer // where we can lex it. Token TmpTok; TmpTok.startToken(); CreateString(StrVal, TmpTok); SourceLocation TokLoc = TmpTok.getLocation(); // Make and enter a lexer object so that we lex and expand the tokens just // like any others. Lexer *TL = Lexer::Create_PragmaLexer(TokLoc, PragmaLoc, RParenLoc, StrVal.size(), *this); EnterSourceFileWithLexer(TL, 0); // With everything set up, lex this as a #pragma directive. HandlePragmaDirective(PIK__Pragma); // Finally, return whatever came after the pragma directive. return Lex(Tok); }
void UmlClass::readFormal(FileIn & in, Token & token) { if (! token.closed()) { signatures[token.xmiId()] = this; WrapperStr k = token.what(); const char * kstr = k; unsigned int rank = 0; while (in.read(), !token.close(kstr)) { WrapperStr s = token.what(); if (s == "parameter") { // useless if (! token.closed()) in.finish(token.what()); } else if ((s == "ownedparameter") && (token.xmiType() == "uml:ClassifierTemplateParameter")) { WrapperStr idparam = token.xmiId(); WrapperStr pname = token.valueOf("name"); // at least for VP WrapperStr value; if (! token.closed()) { while (in.read(), !token.close("ownedparameter")) { s = token.what(); if ((s == "ownedparameteredelement") || (s == "ownedelement")) { s = token.valueOf("name"); if (! s.isEmpty()) pname = s; } else if (s == "defaultvalue") value = token.valueOf("value"); if (! token.closed()) in.finish(token.what()); } } if (! pname.isEmpty()) { UmlFormalParameter f(pname, value); addFormal(rank++, f); formalsId.append(idparam); } } else if (! token.closed()) in.finish(token.what()); } } }
void StereotypeDefinitionParser::parseIconProperties(StereotypeIcon *stereotypeIcon) { Token token; bool loop = true; QSet<StereotypeIcon::Element> elements; QSet<QString> stereotypes; while (loop) { token = readNextToken(); if (token.type() != Token::TokenKeyword) { loop = false; } else { switch (token.subtype()) { case KEYWORD_TITLE: stereotypeIcon->setTitle(parseStringProperty()); expectSemicolonOrEndOfLine(); break; case KEYWORD_ELEMENTS: { QList<QString> identifiers = parseIdentifierListProperty(); foreach (const QString &identifier, identifiers) { static QHash<QString, StereotypeIcon::Element> elementNames = QHash<QString, StereotypeIcon::Element>() << qMakePair(QString(QStringLiteral("package")), StereotypeIcon::ElementPackage) << qMakePair(QString(QStringLiteral("component")), StereotypeIcon::ElementComponent) << qMakePair(QString(QStringLiteral("class")), StereotypeIcon::ElementClass) << qMakePair(QString(QStringLiteral("diagram")), StereotypeIcon::ElementDiagram) << qMakePair(QString(QStringLiteral("item")), StereotypeIcon::ElementItem); QString elementName = identifier.toLower(); if (!elementNames.contains(elementName)) throw StereotypeDefinitionParserError(QString(QStringLiteral("Unexpected value \"%1\" for element.")).arg(identifier), token.sourcePos()); elements.insert(elementNames.value(elementName)); } expectSemicolonOrEndOfLine(); break; } case KEYWORD_STEREOTYPE: stereotypes.insert(parseStringProperty()); expectSemicolonOrEndOfLine(); break; case KEYWORD_WIDTH: stereotypeIcon->setWidth(parseFloatProperty()); expectSemicolonOrEndOfLine(); break; case KEYWORD_HEIGHT: stereotypeIcon->setHeight(parseFloatProperty()); expectSemicolonOrEndOfLine(); break; case KEYWORD_MINWIDTH: stereotypeIcon->setMinWidth(parseFloatProperty()); expectSemicolonOrEndOfLine(); break; case KEYWORD_MINHEIGHT: stereotypeIcon->setMinHeight(parseFloatProperty()); expectSemicolonOrEndOfLine(); break; case KEYWORD_LOCK_SIZE: { QString lockValue = parseIdentifierProperty(); QString lockName = lockValue.toLower(); static QHash<QString, StereotypeIcon::SizeLock> lockNames = QHash<QString, StereotypeIcon::SizeLock>() << qMakePair(QString(QStringLiteral("none")), StereotypeIcon::LockNone) << qMakePair(QString(QStringLiteral("width")), StereotypeIcon::LockWidth) << qMakePair(QString(QStringLiteral("height")), StereotypeIcon::LockHeight) << qMakePair(QString(QStringLiteral("size")), StereotypeIcon::LockSize) << qMakePair(QString(QStringLiteral("ratio")), StereotypeIcon::LockRatio); if (lockNames.contains(lockName)) { StereotypeIcon::SizeLock sizeLock = lockNames.value(lockName); stereotypeIcon->setSizeLock(sizeLock); } else { throw StereotypeDefinitionParserError(QString(QStringLiteral("Unexpected value \"%1\" for size lock.")).arg(lockValue), token.sourcePos()); } break; } case KEYWORD_DISPLAY: { QString displayValue = parseIdentifierProperty(); QString displayName = displayValue.toLower(); static QHash<QString, StereotypeIcon::Display> displayNames = QHash<QString, StereotypeIcon::Display>() << qMakePair(QString(QStringLiteral("none")), StereotypeIcon::DisplayNone) << qMakePair(QString(QStringLiteral("label")), StereotypeIcon::DisplayLabel) << qMakePair(QString(QStringLiteral("decoration")), StereotypeIcon::DisplayDecoration) << qMakePair(QString(QStringLiteral("icon")), StereotypeIcon::DisplayIcon) << qMakePair(QString(QStringLiteral("smart")), StereotypeIcon::DisplaySmart); if (displayNames.contains(displayName)) { StereotypeIcon::Display display = displayNames.value(displayName); stereotypeIcon->setDisplay(display); } else { throw StereotypeDefinitionParserError(QString(QStringLiteral("Unexpected value \"%1\" for stereotype display.")).arg(displayValue), token.sourcePos()); } break; } case KEYWORD_TEXTALIGN: { QString alignValue = parseIdentifierProperty(); QString alignName = alignValue.toLower(); static QHash<QString, StereotypeIcon::TextAlignment> alignNames = QHash<QString, StereotypeIcon::TextAlignment>() << qMakePair(QString(QStringLiteral("below")), StereotypeIcon::TextalignBelow) << qMakePair(QString(QStringLiteral("center")), StereotypeIcon::TextalignCenter) << qMakePair(QString(QStringLiteral("none")), StereotypeIcon::TextalignNone); if (alignNames.contains(alignName)) { StereotypeIcon::TextAlignment textAlignment = alignNames.value(alignName); stereotypeIcon->setTextAlignment(textAlignment); } else { throw StereotypeDefinitionParserError(QString(QStringLiteral("Unexpected value \"%1\" for text alignment.")).arg(alignValue), token.sourcePos()); } break; } case KEYWORD_BASECOLOR: stereotypeIcon->setBaseColor(parseColorProperty()); expectSemicolonOrEndOfLine(); break; default: loop = false; break; } } } stereotypeIcon->setElements(elements); stereotypeIcon->setStereotypes(stereotypes); d->m_scanner->unread(token); }
void UmlClass::importIt(FileIn & in, Token & token, UmlItem * where) { where = where->container(aClass, token, in); // can't be null WrapperStr s = token.valueOf("name"); if (s.isEmpty()) { static unsigned n = 0; s.sprintf("anonymous_%u", ++n); } else s = legalName(s); UmlClass * cl = create(where, s); Association * assocclass = 0; bool stereotype = FALSE; if (cl == 0) in.error("cannot create classe '" + s + "' in '" + where->name() + "'"); cl->addItem(token.xmiId(), in); do where = where->parent(); while (where->kind() != aPackage); if (where->stereotype() == "profile") cl->set_PropertyValue("xmiId", token.xmiId()); if (token.xmiType() == "uml:Actor") cl->set_Stereotype("actor"); else if (token.xmiType() == "uml:Interface") cl->set_Stereotype("interface"); else if (token.xmiType() == "uml:Enumeration") cl->set_Stereotype("enum"); else if (token.xmiType() == "uml:Stereotype") { cl->set_Stereotype("stereotype"); NumberOf -= 1; NumberOfStereotype += 1; stereotype = TRUE; } else if (token.xmiType() == "uml:AssociationClass") { assocclass = &Association::get(token.xmiId(), token.valueOf("name")); assocclass->set_class_association(); } cl->setVisibility(token.valueOf("visibility")); if (token.valueOf("isabstract") == "true") cl->set_isAbstract(TRUE); if (token.valueOf("isactive") == "true") cl->set_isActive(TRUE); if (! token.closed()) { WrapperStr k = token.what(); const char * kstr = k; WrapperStr assocclass_ref1; WrapperStr assocclass_ref2; while (in.read(), !token.close(kstr)) { s = token.what(); if ((s == "ownedtemplatesignature") && ((token.xmiType() == "uml:TemplateSignature") || (token.xmiType() == "uml:RedefinableTemplateSignature"))) cl->readFormal(in, token); else if ((s == "templatebinding") && (token.xmiType() == "uml:TemplateBinding")) { Binding::import(in, token, cl); } else if ((assocclass != 0) && (s == "memberend")) { if (assocclass_ref1.isEmpty()) assocclass_ref1 = token.xmiIdref(); else assocclass_ref2 = token.xmiIdref(); if (! token.closed()) in.finish(s); } else if ((assocclass != 0) && (s == "ownedend") && (token.xmiType() == "uml:Property")) assocclass->import(in, token); else if (s == "ownedrule") cl->set_Constraint(UmlItem::readConstraint(in, token)); else if (stereotype && (s == "icon") && (token.xmiType() == "uml:Image")) { WrapperStr path = token.valueOf("location"); if (! path.isEmpty()) cl->set_PropertyValue("stereotypeIconPath", path); if (! token.closed()) in.finish(s); } else cl->UmlItem::import(in, token); } } cl->unload(TRUE, FALSE); }
void StereotypeDefinitionParser::expectOperator(int op, const QString &opName) { Token token = d->m_scanner->read(); if (token.type() != Token::TokenOperator || token.subtype() != op) throw StereotypeDefinitionParserError(QString(QStringLiteral("Expected '%1'.")).arg(opName), token.sourcePos()); }
nsresult txExprParser::createFilterOrStep(txExprLexer& lexer, txIParseContext* aContext, Expr** aResult) { *aResult = nullptr; nsresult rv = NS_OK; Token* tok = lexer.peek(); nsAutoPtr<Expr> expr; switch (tok->mType) { case Token::FUNCTION_NAME_AND_PAREN: rv = createFunctionCall(lexer, aContext, getter_Transfers(expr)); NS_ENSURE_SUCCESS(rv, rv); break; case Token::VAR_REFERENCE : lexer.nextToken(); { nsCOMPtr<nsIAtom> prefix, lName; PRInt32 nspace; nsresult rv = resolveQName(tok->Value(), getter_AddRefs(prefix), aContext, getter_AddRefs(lName), nspace); NS_ENSURE_SUCCESS(rv, rv); expr = new VariableRefExpr(prefix, lName, nspace); } break; case Token::L_PAREN: lexer.nextToken(); rv = createExpr(lexer, aContext, getter_Transfers(expr)); NS_ENSURE_SUCCESS(rv, rv); if (lexer.peek()->mType != Token::R_PAREN) { return NS_ERROR_XPATH_PAREN_EXPECTED; } lexer.nextToken(); break; case Token::LITERAL : lexer.nextToken(); expr = new txLiteralExpr(tok->Value()); break; case Token::NUMBER: { lexer.nextToken(); expr = new txLiteralExpr(txDouble::toDouble(tok->Value())); break; } default: return createLocationStep(lexer, aContext, aResult); } if (lexer.peek()->mType == Token::L_BRACKET) { nsAutoPtr<FilterExpr> filterExpr(new FilterExpr(expr)); expr.forget(); //-- handle predicates rv = parsePredicates(filterExpr, lexer, aContext); NS_ENSURE_SUCCESS(rv, rv); expr = filterExpr.forget(); } *aResult = expr.forget(); return NS_OK; }