Index: include/llvm/MC/MCParser/AsmLexer.h =================================================================== --- include/llvm/MC/MCParser/AsmLexer.h +++ include/llvm/MC/MCParser/AsmLexer.h @@ -36,7 +36,7 @@ protected: /// LexToken - Read the next token and return its code. - AsmToken LexToken() override; + AsmToken LexToken(bool AltMacroMode = false) override; public: AsmLexer(const MCAsmInfo &MAI); @@ -55,6 +55,11 @@ const MCAsmInfo &getMAI() const { return MAI; } private: + /// isAtString check if the next token is type or arithmetic. + /// string that begin with char '<' must to end with char '>' otherwise it is no a string. + /// True - + /// false- a and '...' string. - return AsmToken(AsmToken::String, StringRef(TokStart, CurPtr - TokStart)); +AsmToken AsmLexer::lexStringHandle(char FirstChar){ + char lastChar; + if (FirstChar == '<') + lastChar = '>'; + else + lastChar = FirstChar; + int CurChar = getNextChar(); + // TODO: does gas allow multiline string constants? + while (CurChar != lastChar) { + if (CurChar == '\\') { + // Allow \", etc. + CurChar = getNextChar(); + } + if (CurChar == EOF){ + std::string StrError = "unterminated string constant - missing" + lastChar; + StrError+= " at the end"; + return ReturnError(TokStart, StrError); + } + CurChar = getNextChar(); + if ((CurChar == '>')&& (lastChar == '>')){ + CurChar = getNextChar(); + if (CurChar == EOF) + break; + if ((CurChar == ',') || (CurChar == '\n')){ + CurPtr--; + break; + } + } + } + return AsmToken(AsmToken::String, StringRef(TokStart, CurPtr - TokStart)); } StringRef AsmLexer::LexUntilEndOfStatement() { @@ -476,123 +495,137 @@ strlen(MAI.getSeparatorString())) == 0; } -AsmToken AsmLexer::LexToken() { - TokStart = CurPtr; - // This always consumes at least one character. - int CurChar = getNextChar(); - - if (isAtStartOfComment(TokStart)) { - // If this comment starts with a '#', then return the Hash token and let - // the assembler parser see if it can be parsed as a cpp line filename - // comment. We do this only if we are at the start of a line. - if (CurChar == '#' && isAtStartOfLine) - return AsmToken(AsmToken::Hash, StringRef(TokStart, 1)); - isAtStartOfLine = true; - return LexLineComment(); - } - if (isAtStatementSeparator(TokStart)) { - CurPtr += strlen(MAI.getSeparatorString()) - 1; - return AsmToken(AsmToken::EndOfStatement, - StringRef(TokStart, strlen(MAI.getSeparatorString()))); - } - - // If we're missing a newline at EOF, make sure we still get an - // EndOfStatement token before the Eof token. - if (CurChar == EOF && !isAtStartOfLine) { - isAtStartOfLine = true; - return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1)); - } - - isAtStartOfLine = false; - switch (CurChar) { - default: - // Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]* - if (isalpha(CurChar) || CurChar == '_' || CurChar == '.') - return LexIdentifier(); - - // Unknown character, emit an error. - return ReturnError(TokStart, "invalid character in input"); - case EOF: return AsmToken(AsmToken::Eof, StringRef(TokStart, 0)); - case 0: - case ' ': - case '\t': - if (SkipSpace) { - // Ignore whitespace. - return LexToken(); - } else { - int len = 1; - while (*CurPtr==' ' || *CurPtr=='\t') { - CurPtr++; - len++; - } - return AsmToken(AsmToken::Space, StringRef(TokStart, len)); - } - case '\n': // FALL THROUGH. - case '\r': - isAtStartOfLine = true; - return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1)); - case ':': return AsmToken(AsmToken::Colon, StringRef(TokStart, 1)); - case '+': return AsmToken(AsmToken::Plus, StringRef(TokStart, 1)); - case '-': return AsmToken(AsmToken::Minus, StringRef(TokStart, 1)); - case '~': return AsmToken(AsmToken::Tilde, StringRef(TokStart, 1)); - case '(': return AsmToken(AsmToken::LParen, StringRef(TokStart, 1)); - case ')': return AsmToken(AsmToken::RParen, StringRef(TokStart, 1)); - case '[': return AsmToken(AsmToken::LBrac, StringRef(TokStart, 1)); - case ']': return AsmToken(AsmToken::RBrac, StringRef(TokStart, 1)); - case '{': return AsmToken(AsmToken::LCurly, StringRef(TokStart, 1)); - case '}': return AsmToken(AsmToken::RCurly, StringRef(TokStart, 1)); - case '*': return AsmToken(AsmToken::Star, StringRef(TokStart, 1)); - case ',': return AsmToken(AsmToken::Comma, StringRef(TokStart, 1)); - case '$': return AsmToken(AsmToken::Dollar, StringRef(TokStart, 1)); - case '@': return AsmToken(AsmToken::At, StringRef(TokStart, 1)); - case '\\': return AsmToken(AsmToken::BackSlash, StringRef(TokStart, 1)); - case '=': - if (*CurPtr == '=') - return ++CurPtr, AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2)); - return AsmToken(AsmToken::Equal, StringRef(TokStart, 1)); - case '|': - if (*CurPtr == '|') - return ++CurPtr, AsmToken(AsmToken::PipePipe, StringRef(TokStart, 2)); - return AsmToken(AsmToken::Pipe, StringRef(TokStart, 1)); - case '^': return AsmToken(AsmToken::Caret, StringRef(TokStart, 1)); - case '&': - if (*CurPtr == '&') - return ++CurPtr, AsmToken(AsmToken::AmpAmp, StringRef(TokStart, 2)); - return AsmToken(AsmToken::Amp, StringRef(TokStart, 1)); - case '!': - if (*CurPtr == '=') - return ++CurPtr, AsmToken(AsmToken::ExclaimEqual, StringRef(TokStart, 2)); - return AsmToken(AsmToken::Exclaim, StringRef(TokStart, 1)); - case '%': return AsmToken(AsmToken::Percent, StringRef(TokStart, 1)); - case '/': return LexSlash(); - case '#': return AsmToken(AsmToken::Hash, StringRef(TokStart, 1)); - case '\'': return LexSingleQuote(); - case '"': return LexQuote(); - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - return LexDigit(); - case '<': - switch (*CurPtr) { - case '<': return ++CurPtr, AsmToken(AsmToken::LessLess, - StringRef(TokStart, 2)); - case '=': return ++CurPtr, AsmToken(AsmToken::LessEqual, - StringRef(TokStart, 2)); - case '>': return ++CurPtr, AsmToken(AsmToken::LessGreater, - StringRef(TokStart, 2)); - default: return AsmToken(AsmToken::Less, StringRef(TokStart, 1)); - } - case '>': - switch (*CurPtr) { - case '>': return ++CurPtr, AsmToken(AsmToken::GreaterGreater, - StringRef(TokStart, 2)); - case '=': return ++CurPtr, AsmToken(AsmToken::GreaterEqual, - StringRef(TokStart, 2)); - default: return AsmToken(AsmToken::Greater, StringRef(TokStart, 1)); - } - - // TODO: Quoted identifiers (objc methods etc) - // local labels: [0-9][:] - // Forward/backward labels: [0-9][fb] - // Integers, fp constants, character constants. - } -} +bool AsmLexer::isAtString(const char* currentPtr){ + while ((*currentPtr != ',') && (*currentPtr != '\n') && (*currentPtr != EOF) && (*currentPtr != '\0')) + currentPtr++; + while (*(currentPtr-1) == ' ') + currentPtr--; + if (*(currentPtr - 1) == '>') + return true; + else + return false; +} + +AsmToken AsmLexer::LexToken(bool AltMacro){ + TokStart = CurPtr; + // This always consumes at least one character. + int CurChar = getNextChar(); + + if (isAtStartOfComment(TokStart)) { + // If this comment starts with a '#', then return the Hash token and let + // the assembler parser see if it can be parsed as a cpp line filename + // comment. We do this only if we are at the start of a line. + if (CurChar == '#' && isAtStartOfLine) + return AsmToken(AsmToken::Hash, StringRef(TokStart, 1)); + isAtStartOfLine = true; + return LexLineComment(); + } + if (isAtStatementSeparator(TokStart)) { + CurPtr += strlen(MAI.getSeparatorString()) - 1; + return AsmToken(AsmToken::EndOfStatement, + StringRef(TokStart, strlen(MAI.getSeparatorString()))); + } + + // If we're missing a newline at EOF, make sure we still get an + // EndOfStatement token before the Eof token. + if (CurChar == EOF && !isAtStartOfLine) { + isAtStartOfLine = true; + return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1)); + } + + isAtStartOfLine = false; + switch (CurChar) { + default: + // Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]* + if (isalpha(CurChar) || CurChar == '_' || CurChar == '.') + return LexIdentifier(); + + // Unknown character, emit an error. + return ReturnError(TokStart, "invalid character in input"); + case EOF: return AsmToken(AsmToken::Eof, StringRef(TokStart, 0)); + case 0: + case ' ': + case '\t': + if (SkipSpace) { + // Ignore whitespace. + return LexToken(AltMacro); + }else{ + int len = 1; + while (*CurPtr == ' ' || *CurPtr == '\t') { + CurPtr++; + len++; + } + return AsmToken(AsmToken::Space, StringRef(TokStart, len)); + } + case '\n': // FALL THROUGH. + case '\r': + isAtStartOfLine = true; + return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1)); + case ':': return AsmToken(AsmToken::Colon, StringRef(TokStart, 1)); + case '+': return AsmToken(AsmToken::Plus, StringRef(TokStart, 1)); + case '-': return AsmToken(AsmToken::Minus, StringRef(TokStart, 1)); + case '~': return AsmToken(AsmToken::Tilde, StringRef(TokStart, 1)); + case '(': return AsmToken(AsmToken::LParen, StringRef(TokStart, 1)); + case ')': return AsmToken(AsmToken::RParen, StringRef(TokStart, 1)); + case '[': return AsmToken(AsmToken::LBrac, StringRef(TokStart, 1)); + case ']': return AsmToken(AsmToken::RBrac, StringRef(TokStart, 1)); + case '{': return AsmToken(AsmToken::LCurly, StringRef(TokStart, 1)); + case '}': return AsmToken(AsmToken::RCurly, StringRef(TokStart, 1)); + case '*': return AsmToken(AsmToken::Star, StringRef(TokStart, 1)); + case ',': return AsmToken(AsmToken::Comma, StringRef(TokStart, 1)); + case '$': return AsmToken(AsmToken::Dollar, StringRef(TokStart, 1)); + case '@': return AsmToken(AsmToken::At, StringRef(TokStart, 1)); + case '\\': return AsmToken(AsmToken::BackSlash, StringRef(TokStart, 1)); + case '=': + if (*CurPtr == '=') + return ++CurPtr, AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2)); + return AsmToken(AsmToken::Equal, StringRef(TokStart, 1)); + case '|': + if (*CurPtr == '|') + return ++CurPtr, AsmToken(AsmToken::PipePipe, StringRef(TokStart, 2)); + return AsmToken(AsmToken::Pipe, StringRef(TokStart, 1)); + case '^': return AsmToken(AsmToken::Caret, StringRef(TokStart, 1)); + case '&': + if (*CurPtr == '&') + return ++CurPtr, AsmToken(AsmToken::AmpAmp, StringRef(TokStart, 2)); + return AsmToken(AsmToken::Amp, StringRef(TokStart, 1)); + case '!': + if (*CurPtr == '=') + return ++CurPtr, AsmToken(AsmToken::ExclaimEqual, StringRef(TokStart, 2)); + return AsmToken(AsmToken::Exclaim, StringRef(TokStart, 1)); + case '%': return AsmToken(AsmToken::Percent, StringRef(TokStart, 1)); + case '/': return LexSlash(); + case '#': return AsmToken(AsmToken::Hash, StringRef(TokStart, 1)); + case '\'': return LexSingleQuote(AltMacro); + case '"': return lexStringHandle();//LexQuote(); + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + return LexDigit(); + + case '<':{ + if (isAtString(CurPtr) && AltMacro) + return lexStringHandle('<'); + switch (*CurPtr) { + case '<': return ++CurPtr, AsmToken(AsmToken::LessLess, + StringRef(TokStart, 2)); + case '=': return ++CurPtr, AsmToken(AsmToken::LessEqual, + StringRef(TokStart, 2)); + case '>': return ++CurPtr, AsmToken(AsmToken::LessGreater, + StringRef(TokStart, 2)); + default:return AsmToken(AsmToken::Less, StringRef(TokStart, 1)); + } + } + case '>': + switch (*CurPtr) { + case '>': return ++CurPtr, AsmToken(AsmToken::GreaterGreater, + StringRef(TokStart, 2)); + case '=': return ++CurPtr, AsmToken(AsmToken::GreaterEqual, + StringRef(TokStart, 2)); + default: return AsmToken(AsmToken::Greater, StringRef(TokStart, 1)); + } + // TODO: Quoted identifiers (objc methods etc) + // local labels: [0-9][:] + // Forward/backward labels: [0-9][fb] + // Integers, fp constants, character constants. + } +} \ No newline at end of file Index: lib/MC/MCParser/AsmParser.cpp =================================================================== --- lib/MC/MCParser/AsmParser.cpp +++ lib/MC/MCParser/AsmParser.cpp @@ -26,7 +26,6 @@ #include "llvm/MC/MCParser/AsmCond.h" #include "llvm/MC/MCParser/AsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" -#include "llvm/MC/MCParser/MCAsmParserUtils.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSectionMachO.h" @@ -175,7 +174,10 @@ /// \brief Are we parsing ms-style inline assembly? bool ParsingInlineAsm; - + /// \ this is for the .altmode use. + bool AltMacroMode = false; + bool AltMacroPresent = false; + int64_t valueForTheAltMacro; public: AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, const MCAsmInfo &MAI); @@ -245,7 +247,7 @@ /// } private: - + bool PRE = false; bool parseStatement(ParseStatementInfo &Info, MCAsmParserSemaCallback *SI); void eatToEndOfLine(); @@ -359,7 +361,7 @@ DK_CFI_REMEMBER_STATE, DK_CFI_RESTORE_STATE, DK_CFI_SAME_VALUE, DK_CFI_RESTORE, DK_CFI_ESCAPE, DK_CFI_SIGNAL_FRAME, DK_CFI_UNDEFINED, DK_CFI_REGISTER, DK_CFI_WINDOW_SAVE, - DK_MACROS_ON, DK_MACROS_OFF, + DK_MACROS_ON, DK_MACROS_OFF, DK_ALTMACRO_ON, DK_NOALTMACRO, DK_MACRO, DK_EXITM, DK_ENDM, DK_ENDMACRO, DK_PURGEM, DK_SLEB128, DK_ULEB128, DK_ERR, DK_ERROR, DK_WARNING, @@ -416,8 +418,9 @@ bool parseDirectiveEndMacro(StringRef Directive); bool parseDirectiveMacro(SMLoc DirectiveLoc); bool parseDirectiveMacrosOnOff(StringRef Directive); - - // ".bundle_align_mode" + // AltMacros + bool parseDirectiveAltMacrosOnOff(StringRef Directive); + // ".bundle_align_mode" bool parseDirectiveBundleAlignMode(); // ".bundle_lock" bool parseDirectiveBundleLock(); @@ -599,15 +602,15 @@ } const AsmToken &AsmParser::Lex() { - const AsmToken *tok = &Lexer.Lex(); + const AsmToken *tok = &Lexer.Lex(AltMacroMode); - if (tok->is(AsmToken::Eof)) { + if (tok->is(AsmToken::Eof)) { // If this is the end of an included file, pop the parent file off the // include stack. SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer); if (ParentIncludeLoc != SMLoc()) { - jumpToLoc(ParentIncludeLoc); - tok = &Lexer.Lex(); + jumpToLoc(ParentIncludeLoc); + tok = &Lexer.Lex(AltMacroMode); } } @@ -777,6 +780,7 @@ /// primaryexpr ::= number /// primaryexpr ::= '.' /// primaryexpr ::= ~,+,- primaryexpr +/// primaryezpr ::= '%' bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { SMLoc FirstTokenLoc = getLexer().getLoc(); AsmToken::TokenKind FirstTokenKind = Lexer.getKind(); @@ -792,6 +796,12 @@ return true; Res = MCUnaryExpr::createLNot(Res, getContext()); return false; + case AsmToken::Percent:{ + if (AltMacroMode) + return false; + else + return true; + } case AsmToken::Dollar: case AsmToken::At: case AsmToken::String: @@ -1228,7 +1238,7 @@ // Treat '.' as a valid identifier in this context. Lex(); IDVal = "."; - } else if (parseIdentifier(IDVal)) { + }else if (parseIdentifier(IDVal)) { if (!TheCondState.Ignore) return TokError("unexpected token at start of statement"); IDVal = ""; @@ -1307,10 +1317,8 @@ MCSymbol *Sym; if (LocalLabelVal == -1) { if (ParsingInlineAsm && SI) { - StringRef RewrittenLabel = - SI->LookupInlineAsmLabel(IDVal, getSourceManager(), IDLoc, true); - assert(RewrittenLabel.size() && - "We should have an internal name here."); + StringRef RewrittenLabel = SI->LookupInlineAsmLabel(IDVal, getSourceManager(), IDLoc, true); + assert(RewrittenLabel.size() && "We should have an internal name here."); Info.AsmRewrites->push_back(AsmRewrite(AOK_Label, IDLoc, IDVal.size(), RewrittenLabel)); IDVal = RewrittenLabel; @@ -1392,7 +1400,7 @@ // Finally, if no one else is interested in this directive, it must be // generic and familiar to this class. - switch (DirKind) { + switch (DirKind) { default: break; case DK_SET: @@ -1561,6 +1569,10 @@ return parseDirectiveMacrosOnOff(IDVal); case DK_MACRO: return parseDirectiveMacro(IDLoc); + case DK_ALTMACRO_ON: + return parseDirectiveAltMacrosOnOff(IDVal); + case DK_NOALTMACRO: + return parseDirectiveAltMacrosOnOff(IDVal); case DK_EXITM: return parseDirectiveExitMacro(IDVal); case DK_ENDM: @@ -1781,10 +1793,10 @@ ArrayRef A, bool EnableAtPseudoVariable, const SMLoc &L) { unsigned NParameters = Parameters.size(); - bool HasVararg = NParameters ? Parameters.back().Vararg : false; + bool Percent = false; + bool HasVararg = NParameters ? Parameters.back().Vararg : false; if ((!IsDarwin || NParameters != 0) && NParameters != A.size()) return Error(L, "Wrong number of arguments"); - // A macro without parameters is handled differently on Darwin: // gas accepts no arguments and does no substitutions while (!Body.empty()) { @@ -1805,6 +1817,10 @@ // This macro has parameters, look for \foo, \bar, etc. if (Body[Pos] == '\\' && Pos + 1 != End) break; + if (Body[Pos] == '%' && Pos + 1 != End && AltMacroMode){ + Percent = true; + break; + } } } @@ -1874,16 +1890,21 @@ } } else { bool VarargParameter = HasVararg && Index == (NParameters - 1); - for (MCAsmMacroArgument::const_iterator it = A[Index].begin(), - ie = A[Index].end(); - it != ie; ++it) - // We expect no quotes around the string's contents when - // parsing for varargs. - if (it->getKind() != AsmToken::String || VarargParameter) - OS << it->getString(); - else - OS << it->getStringContents(); - + if (Percent&&AltMacroPresent){ + AltMacroPresent = false; + OS << valueForTheAltMacro; + } + else{ + for (MCAsmMacroArgument::const_iterator it = A[Index].begin(), + ie = A[Index].end(); + it != ie; ++it) + // We expect no quotes around the string's contents when + // parsing for varargs. + if (it->getKind() != AsmToken::String || VarargParameter) + OS << it->getString(); + else + OS << it->getStringContents(); + } Pos += 1 + Argument.size(); } } @@ -2027,12 +2048,12 @@ // Parse two kinds of macro invocations: // - macros defined without any parameters accept an arbitrary number of them // - macros defined with parameters accept at most that many of them - bool HasVararg = NParameters ? M->Parameters.back().Vararg : false; + + bool HasVararg = NParameters ? M->Parameters.back().Vararg : false; for (unsigned Parameter = 0; !NParameters || Parameter < NParameters; ++Parameter) { SMLoc IDLoc = Lexer.getLoc(); MCAsmMacroParameter FA; - if (Lexer.is(AsmToken::Identifier) && Lexer.peekTok().is(AsmToken::Equal)) { if (parseIdentifier(FA.Name)) { Error(IDLoc, "invalid argument identifier for formal argument"); @@ -2049,7 +2070,10 @@ NamedParametersFound = true; } - + if (Lexer.is(AsmToken::LParen)&&AltMacroMode){ + AltMacroPresent = true; + parseAbsoluteExpression(valueForTheAltMacro); + } if (NamedParametersFound && FA.Name.empty()) { Error(IDLoc, "cannot mix positional and keyword arguments"); eatToEndOfStatement(); @@ -2179,20 +2203,82 @@ ActiveMacros.pop_back(); } +static bool isUsedIn(const MCSymbol *Sym, const MCExpr *Value) { + switch (Value->getKind()) { + case MCExpr::Binary: { + const MCBinaryExpr *BE = static_cast(Value); + return isUsedIn(Sym, BE->getLHS()) || isUsedIn(Sym, BE->getRHS()); + } + case MCExpr::Target: + case MCExpr::Constant: + return false; + case MCExpr::SymbolRef: { + const MCSymbol &S = + static_cast(Value)->getSymbol(); + if (S.isVariable()) + return isUsedIn(Sym, S.getVariableValue()); + return &S == Sym; + } + case MCExpr::Unary: + return isUsedIn(Sym, static_cast(Value)->getSubExpr()); + } + + llvm_unreachable("Unknown expr kind!"); +} + bool AsmParser::parseAssignment(StringRef Name, bool allow_redef, bool NoDeadStrip) { - MCSymbol *Sym; + // FIXME: Use better location, we should use proper tokens. + SMLoc EqualLoc = Lexer.getLoc(); + const MCExpr *Value; - if (MCParserUtils::parseAssignmentExpression(Name, allow_redef, *this, Sym, - Value)) + if (parseExpression(Value)) return true; - if (!Sym) { - // In the case where we parse an expression starting with a '.', we will - // not generate an error, nor will we create a symbol. In this case we - // should just return out. + // Note: we don't count b as used in "a = b". This is to allow + // a = b + // b = c + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in assignment"); + + // Eat the end of statement marker. + Lex(); + + // Validate that the LHS is allowed to be a variable (either it has not been + // used as a symbol, or it is an absolute symbol). + MCSymbol *Sym = getContext().lookupSymbol(Name); + if (Sym) { + // Diagnose assignment to a label. + // + // FIXME: Diagnostics. Note the location of the definition as a label. + // FIXME: Diagnose assignment to protected identifier (e.g., register name). + if (isUsedIn(Sym, Value)) + return Error(EqualLoc, "Recursive use of '" + Name + "'"); + else if (Sym->isUndefined() && !Sym->isUsed() && !Sym->isVariable()) + ; // Allow redefinitions of undefined symbols only used in directives. + else if (Sym->isVariable() && !Sym->isUsed() && allow_redef) + ; // Allow redefinitions of variables that haven't yet been used. + else if (!Sym->isUndefined() && (!Sym->isVariable() || !allow_redef)) + return Error(EqualLoc, "redefinition of '" + Name + "'"); + else if (!Sym->isVariable()) + return Error(EqualLoc, "invalid assignment to '" + Name + "'"); + else if (!isa(Sym->getVariableValue())) + return Error(EqualLoc, "invalid reassignment of non-absolute variable '" + + Name + "'"); + + // Don't count these checks as uses. + Sym->setUsed(false); + } else if (Name == ".") { + if (Out.EmitValueToOffset(Value, 0)) { + Error(EqualLoc, "expected absolute expression"); + eatToEndOfStatement(); + } return false; - } + } else + Sym = getContext().getOrCreateSymbol(Name); + + Sym->setRedefinable(allow_redef); // Do the assignment. Out.EmitAssignment(Sym, Value); @@ -3221,7 +3307,15 @@ getStreamer().EmitCFIUndefined(Register); return false; } - +/// parseDirectiveAltMacrosOnOff +/// ::= .altmacro_on +/// ::= .altmacro_off +bool AsmParser::parseDirectiveAltMacrosOnOff(StringRef Directive) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '" + Directive + "' directive"); + AltMacroMode = (Directive == ".altmacro"); + return false; +} /// parseDirectiveMacrosOnOff /// ::= .macros_on /// ::= .macros_off @@ -3238,12 +3332,13 @@ /// ::= .macro name[,] [parameters] bool AsmParser::parseDirectiveMacro(SMLoc DirectiveLoc) { StringRef Name; + if (parseIdentifier(Name)) return TokError("expected identifier in '.macro' directive"); if (getLexer().is(AsmToken::Comma)) Lex(); - + MCAsmMacroParameters Parameters; while (getLexer().isNot(AsmToken::EndOfStatement)) { @@ -4246,6 +4341,8 @@ DirectiveKindMap[".err"] = DK_ERR; DirectiveKindMap[".error"] = DK_ERROR; DirectiveKindMap[".warning"] = DK_WARNING; + DirectiveKindMap[".altmacro"] = DK_ALTMACRO_ON; + DirectiveKindMap[".noaltmacro"] = DK_NOALTMACRO; } MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) { @@ -4716,103 +4813,6 @@ return false; } -namespace llvm { -namespace MCParserUtils { - -/// Returns whether the given symbol is used anywhere in the given expression, -/// or subexpressions. -static bool isSymbolUsedInExpression(const MCSymbol *Sym, const MCExpr *Value) { - switch (Value->getKind()) { - case MCExpr::Binary: { - const MCBinaryExpr *BE = static_cast(Value); - return isSymbolUsedInExpression(Sym, BE->getLHS()) || - isSymbolUsedInExpression(Sym, BE->getRHS()); - } - case MCExpr::Target: - case MCExpr::Constant: - return false; - case MCExpr::SymbolRef: { - const MCSymbol &S = - static_cast(Value)->getSymbol(); - if (S.isVariable()) - return isSymbolUsedInExpression(Sym, S.getVariableValue()); - return &S == Sym; - } - case MCExpr::Unary: - return isSymbolUsedInExpression( - Sym, static_cast(Value)->getSubExpr()); - } - - llvm_unreachable("Unknown expr kind!"); -} - -bool parseAssignmentExpression(StringRef Name, bool allow_redef, - MCAsmParser &Parser, MCSymbol *&Sym, - const MCExpr *&Value) { - MCAsmLexer &Lexer = Parser.getLexer(); - - // FIXME: Use better location, we should use proper tokens. - SMLoc EqualLoc = Lexer.getLoc(); - - if (Parser.parseExpression(Value)) { - Parser.TokError("missing expression"); - Parser.eatToEndOfStatement(); - return true; - } - - // Note: we don't count b as used in "a = b". This is to allow - // a = b - // b = c - - if (Lexer.isNot(AsmToken::EndOfStatement)) - return Parser.TokError("unexpected token in assignment"); - - // Eat the end of statement marker. - Parser.Lex(); - - // Validate that the LHS is allowed to be a variable (either it has not been - // used as a symbol, or it is an absolute symbol). - Sym = Parser.getContext().lookupSymbol(Name); - if (Sym) { - // Diagnose assignment to a label. - // - // FIXME: Diagnostics. Note the location of the definition as a label. - // FIXME: Diagnose assignment to protected identifier (e.g., register name). - if (isSymbolUsedInExpression(Sym, Value)) - return Parser.Error(EqualLoc, "Recursive use of '" + Name + "'"); - else if (Sym->isUndefined() && !Sym->isUsed() && !Sym->isVariable()) - ; // Allow redefinitions of undefined symbols only used in directives. - else if (Sym->isVariable() && !Sym->isUsed() && allow_redef) - ; // Allow redefinitions of variables that haven't yet been used. - else if (!Sym->isUndefined() && (!Sym->isVariable() || !allow_redef)) - return Parser.Error(EqualLoc, "redefinition of '" + Name + "'"); - else if (!Sym->isVariable()) - return Parser.Error(EqualLoc, "invalid assignment to '" + Name + "'"); - else if (!isa(Sym->getVariableValue())) - return Parser.Error(EqualLoc, - "invalid reassignment of non-absolute variable '" + - Name + "'"); - - // Don't count these checks as uses. - Sym->setUsed(false); - } else if (Name == ".") { - if (Parser.getStreamer().EmitValueToOffset(Value, 0)) { - Parser.Error(EqualLoc, "expected absolute expression"); - Parser.eatToEndOfStatement(); - return true; - } - return false; - } else - Sym = Parser.getContext().getOrCreateSymbol(Name); - - Sym->setRedefinable(allow_redef); - - return false; -} - -} // namespace MCParserUtils -} // namespace llvm - /// \brief Create an MCAsmParser instance. MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, MCContext &C, MCStreamer &Out, const MCAsmInfo &MAI) { Index: test/MC/AsmParser/altMacroTest.s =================================================================== --- test/MC/AsmParser/altMacroTest.s +++ test/MC/AsmParser/altMacroTest.s @@ -0,0 +1,55 @@ +# RUN: llvm-mc -triple i386-unknown-unknown %s | FileCheck %s + +.altmacro +.macro test1 name num + \name\num\(): + .long \name\num +.endm +test1 'b',1 +test1 'ab',1 +test1 "a",1 +test1 "ba",1 +test1 ,1 +.noaltmacro +# CHECK: b1 +# CHECK: .long b1 +# CHECK: ab1: +# CHECK: .long ab1 +# CHECK: a1: +# CHECK: .long a1 +# CHECK: ba1: +# CHECK: .long ba1 +# CHECK: bac1: +# CHECK: .long bac1 + +.altmacro +.macro test2 name, number +__mksym \name, %number +.endm + +.macro __mksym, name, number +\name\number\(): + .long \number +.endm + +.section .rodata + +/* now define symbols by hand... */ +test2 bar, 1 +test2 bar, (9/3 + (7-1)) + +/* ...or use other pseudo ops to do it in a loop */ +.irp i, 3, 2, 1 +test2 foobar, (\i * 2 + 1) +.endr + +# CHECK: bar1: +# CHECK: .long 1 +# CHECK: bar9: +# CHECK: .long 9 +# CHECK: foobar7: +# CHECK: .long 7 +# CHECK: foobar5: +# CHECK: .long 5 +# CHECK: foobar3: +# CHECK: .long 3 \ No newline at end of file Index: test/MC/AsmParser/altMacroTestFail.s =================================================================== --- test/MC/AsmParser/altMacroTestFail.s +++ test/MC/AsmParser/altMacroTestFail.s @@ -0,0 +1,10 @@ +# RUN: not llvm-mc -triple i386 -o /dev/null %s 2>&1 | FileCheck %s + +.macro lableRun name num + \name\num\(): + .long \name\num +.endm +.altmacro +.noaltmacro +lableRun 'bc',1 +# CHECK: error: single quote way too long \ No newline at end of file