}
const AsmToken *tok = &Lexer.Lex();
+ bool StartOfStatement = Lexer.isAtStartOfStatement();
while (tok->is(AsmToken::Identifier)) {
+ if (StartOfStatement) {
+ AsmToken NextTok;
+
+ MutableArrayRef<AsmToken> Buf(NextTok);
+ size_t ReadCount = Lexer.peekTokens(Buf);
+ if (ReadCount && NextTok.is(AsmToken::Identifier) &&
+ (NextTok.getString().equals_lower("equ") ||
+ NextTok.getString().equals_lower("textequ"))) {
+ // This looks like an EQU or TEXTEQU directive; don't expand the
+ // identifier, allowing for redefinitions.
+ break;
+ }
+ }
auto it = Variables.find(tok->getIdentifier().lower());
const llvm::MCAsmMacro *M =
getContext().lookupMacro(tok->getIdentifier().lower());
/// ::= name "=" expression
/// | name "equ" expression (not redefinable)
/// | name "equ" text-list
-/// | name "textequ" text-list
+/// | name "textequ" text-list (redefinability unspecified)
bool MasmParser::parseDirectiveEquate(StringRef IDVal, StringRef Name,
DirectiveKind DirKind) {
Variable &Var = Variables[Name.lower()];
if (Var.Name.empty()) {
Var.Name = Name;
- } else if (!Var.Redefinable) {
- return TokError("invalid variable redefinition");
}
- Var.Redefinable = (DirKind != DK_EQU);
SMLoc StartLoc = Lexer.getLoc();
if (DirKind == DK_EQU || DirKind == DK_TEXTEQU) {
// "equ" and "textequ" both allow text expressions.
std::string Value;
- if (!parseTextItem(Value)) {
- Var.IsText = true;
- Var.TextValue = Value;
+ std::string TextItem;
+ if (!parseTextItem(TextItem)) {
+ Value += TextItem;
// Accept a text-list, not just one text-item.
auto parseItem = [&]() -> bool {
- if (parseTextItem(Value))
+ if (parseTextItem(TextItem))
return TokError("expected text item");
- Var.TextValue += Value;
+ Value += TextItem;
return false;
};
if (parseOptionalToken(AsmToken::Comma) && parseMany(parseItem))
return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
+ if (!Var.Redefinable && (!Var.IsText || Var.TextValue != Value))
+ return Error(getTok().getLoc(), "invalid variable redefinition");
+ Var.IsText = true;
+ Var.TextValue = Value;
+ Var.Redefinable = true;
+
return false;
}
}
SMLoc EndLoc;
if (parseExpression(Expr, EndLoc))
return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
+
+ int64_t Value;
+ if (!Expr->evaluateAsAbsolute(Value, getStreamer().getAssemblerPtr())) {
+ // Not an absolute expression; define as a text replacement.
+ StringRef ExprAsString = StringRef(
+ StartLoc.getPointer(), EndLoc.getPointer() - StartLoc.getPointer());
+ if (!Var.Redefinable && (!Var.IsText && Var.TextValue != ExprAsString))
+ return Error(getTok().getLoc(), "invalid variable redefinition");
+ Var.IsText = true;
+ Var.TextValue = ExprAsString.str();
+ } else {
+ if (!Var.Redefinable && (Var.IsText || Var.NumericValue != Value))
+ return Error(getTok().getLoc(), "invalid variable redefinition");
+ Var.NumericValue = Value;
+ }
+ Var.Redefinable = (DirKind == DK_ASSIGN);
+
MCSymbol *Sym = getContext().getOrCreateSymbol(Var.Name);
Sym->setRedefinable(Var.Redefinable);
Sym->setVariableValue(Expr);
Sym->setExternal(false);
- if (Expr->evaluateAsAbsolute(Var.NumericValue,
- getStreamer().getAssemblerPtr()))
- return false;
-
- // Not an absolute expression; define as a text replacement.
- Var.IsText = true;
- Var.TextValue = StringRef(StartLoc.getPointer(),
- EndLoc.getPointer() - StartLoc.getPointer()).str();
return false;
}
--- /dev/null
+; RUN: llvm-ml -filetype=s %s /Fo - | FileCheck %s
+
+.data
+
+; <var> = <expression> can be redefined at any time.
+assigned_number = 1
+t1_original BYTE assigned_number
+assigned_number = 1
+t1_reset BYTE assigned_number
+assigned_number = 2
+t1_changed BYTE assigned_number
+
+; CHECK-LABEL: t1_original:
+; CHECK-NEXT: .byte 1
+
+; CHECK-LABEL: t1_reset:
+; CHECK-NEXT: .byte 1
+
+; CHECK-LABEL: t1_changed:
+; CHECK-NEXT: .byte 2
+
+; <var> EQU <expression> can be redundantly set, but can't be changed.
+equated_number equ 3
+t2_original BYTE equated_number
+equated_number equ 3
+t2_reset BYTE equated_number
+
+; CHECK-LABEL: t2_original:
+; CHECK-NEXT: .byte 3
+
+; CHECK-LABEL: t2_reset:
+; CHECK-NEXT: .byte 3
+
+; <var> EQU <text> can be redefined at any time.
+equated_text equ <4, 5>
+t3_original BYTE equated_text
+equated_text equ <4, 5>
+t3_reset BYTE equated_text
+equated_text equ <5, 6>
+t3_changed BYTE equated_text
+
+; CHECK-LABEL: t3_original:
+; CHECK-NEXT: .byte 4
+; CHECK-NEXT: .byte 5
+
+; CHECK-LABEL: t3_reset:
+; CHECK-NEXT: .byte 4
+; CHECK-NEXT: .byte 5
+
+; CHECK-LABEL: t3_changed:
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 6
+
+; <var> TEXTEQU <text> can be redefined at any time.
+textequated_text textequ <7, 8>
+t4_original BYTE textequated_text
+textequated_text textequ <7, 8>
+t4_reset BYTE textequated_text
+textequated_text textequ <9, 10>
+t4_changed BYTE textequated_text
+
+; CHECK-LABEL: t4_original:
+; CHECK-NEXT: .byte 7
+; CHECK-NEXT: .byte 8
+
+; CHECK-LABEL: t4_reset:
+; CHECK-NEXT: .byte 7
+; CHECK-NEXT: .byte 8
+
+; CHECK-LABEL: t4_changed:
+; CHECK-NEXT: .byte 9
+; CHECK-NEXT: .byte 10
+
+.code
+
+end